Merge remote-tracking branch 'origin/fix/typeerror-bij-het-reloaden-van-een-pagina-met-menubalk-#150' into fix/typeerror-bij-het-reloaden-van-een-pagina-met-menubalk-#150
This commit is contained in:
		
						commit
						d73b1ae0be
					
				
					 16 changed files with 231 additions and 567 deletions
				
			
		|  | @ -11,10 +11,7 @@ | ||||||
|         requiresAuth?: boolean; |         requiresAuth?: boolean; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const showMenuBar = computed(() => |     const showMenuBar = computed(() => (route.meta as RouteMeta).requiresAuth && auth.authState.user); | ||||||
|         (route.meta as RouteMeta).requiresAuth |  | ||||||
|         && auth.authState.user |  | ||||||
|     ) |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|  |  | ||||||
|  | @ -7,7 +7,7 @@ import { useThemeQuery } from "@/queries/themes.ts"; | ||||||
| 
 | 
 | ||||||
|     const props = defineProps({ |     const props = defineProps({ | ||||||
|         selectedTheme: { type: String, required: true }, |         selectedTheme: { type: String, required: true }, | ||||||
|     selectedAge: { type: String, required: true } |         selectedAge: { type: String, required: true }, | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     const { locale } = useI18n(); |     const { locale } = useI18n(); | ||||||
|  | @ -23,9 +23,10 @@ watchEffect(() => { | ||||||
|         allCards.value = themes; |         allCards.value = themes; | ||||||
| 
 | 
 | ||||||
|         if (props.selectedTheme) { |         if (props.selectedTheme) { | ||||||
|         cards.value = themes.filter((theme) => |             cards.value = themes.filter( | ||||||
|  |                 (theme) => | ||||||
|                     THEMESITEMS[props.selectedTheme]?.includes(theme.key) && |                     THEMESITEMS[props.selectedTheme]?.includes(theme.key) && | ||||||
|             AGE_TO_THEMES[props.selectedAge]?.includes(theme.key) |                     AGE_TO_THEMES[props.selectedAge]?.includes(theme.key), | ||||||
|             ); |             ); | ||||||
|         } else { |         } else { | ||||||
|             cards.value = themes; |             cards.value = themes; | ||||||
|  | @ -33,15 +34,23 @@ watchEffect(() => { | ||||||
|     }); |     }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| <template> | <template> | ||||||
|     <v-container> |     <v-container> | ||||||
|         <div v-if="isLoading" class="text-center py-10"> |         <div | ||||||
|             <v-progress-circular indeterminate color="primary" /> |             v-if="isLoading" | ||||||
|  |             class="text-center py-10" | ||||||
|  |         > | ||||||
|  |             <v-progress-circular | ||||||
|  |                 indeterminate | ||||||
|  |                 color="primary" | ||||||
|  |             /> | ||||||
|             <p>Loading...</p> |             <p>Loading...</p> | ||||||
|         </div> |         </div> | ||||||
| 
 | 
 | ||||||
|         <div v-else-if="error" class="text-center py-10 text-error"> |         <div | ||||||
|  |             v-else-if="error" | ||||||
|  |             class="text-center py-10 text-error" | ||||||
|  |         > | ||||||
|             <v-icon large>mdi-alert-circle</v-icon> |             <v-icon large>mdi-alert-circle</v-icon> | ||||||
|             <p>Error loading: {{ error.message }}</p> |             <p>Error loading: {{ error.message }}</p> | ||||||
|         </div> |         </div> | ||||||
|  |  | ||||||
|  | @ -1,367 +0,0 @@ | ||||||
| <script setup lang="ts"> |  | ||||||
|     import { ref } from "vue"; |  | ||||||
|     import { useI18n } from "vue-i18n"; |  | ||||||
| 
 |  | ||||||
|     import auth from "@/services/auth/auth-service.ts"; |  | ||||||
| 
 |  | ||||||
|     // Import assets |  | ||||||
|     import dwengoLogo from "../../../assets/img/dwengo-groen-zwart.svg"; |  | ||||||
| 
 |  | ||||||
|     const { t, locale } = useI18n(); |  | ||||||
| 
 |  | ||||||
|     const role = auth.authState.activeRole; |  | ||||||
| 
 |  | ||||||
|     const name: string = auth.authState.user!.profile.name!; |  | ||||||
|     const initials: string = name |  | ||||||
|         .split(" ") |  | ||||||
|         .map((n) => n[0]) |  | ||||||
|         .join(""); |  | ||||||
| 
 |  | ||||||
|     // Available languages |  | ||||||
|     const languages = ref([ |  | ||||||
|         { name: "English", code: "en" }, |  | ||||||
|         { name: "Nederlands", code: "nl" }, |  | ||||||
|         { name: "Français", code: "fr" }, |  | ||||||
|         { name: "Deutsch", code: "de" } |  | ||||||
|     ]); |  | ||||||
| 
 |  | ||||||
|     // Logic to change the language of the website to the selected language |  | ||||||
|     const changeLanguage = (langCode: string) => { |  | ||||||
|         locale.value = langCode; |  | ||||||
|         localStorage.setItem("user-lang", langCode); |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     // 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(); |  | ||||||
|     }; |  | ||||||
| </script> |  | ||||||
| 
 |  | ||||||
| <template> |  | ||||||
|     <main> |  | ||||||
|         <div class="menu_collapsed"> |  | ||||||
|             <v-app-bar |  | ||||||
|                 app |  | ||||||
|                 style="background-color: #f6faf2" |  | ||||||
|             > |  | ||||||
|                 <template v-slot:prepend> |  | ||||||
|                     <v-app-bar-nav-icon @click="drawer = !drawer" /> |  | ||||||
|                 </template> |  | ||||||
| 
 |  | ||||||
|                 <v-app-bar-title> |  | ||||||
|                     <router-link |  | ||||||
|                         to="/user" |  | ||||||
|                         class="dwengo_home" |  | ||||||
|                     > |  | ||||||
|                         <div> |  | ||||||
|                             <img |  | ||||||
|                                 class="dwengo_logo" |  | ||||||
|                                 :src="dwengoLogo" |  | ||||||
|                                 style="width: 100px" |  | ||||||
|                             /> |  | ||||||
|                             <p |  | ||||||
|                                 class="caption" |  | ||||||
|                                 style="font-size: smaller" |  | ||||||
|                             > |  | ||||||
|                                 {{ t(`${role}`) }} |  | ||||||
|                             </p> |  | ||||||
|                         </div> |  | ||||||
|                     </router-link> |  | ||||||
|                 </v-app-bar-title> |  | ||||||
| 
 |  | ||||||
|                 <v-spacer></v-spacer> |  | ||||||
| 
 |  | ||||||
|                 <v-menu open-on-hover> |  | ||||||
|                     <template v-slot:activator="{ props }"> |  | ||||||
|                         <v-btn |  | ||||||
|                             v-bind="props" |  | ||||||
|                             icon |  | ||||||
|                             variant="text" |  | ||||||
|                         > |  | ||||||
|                             <v-icon |  | ||||||
|                                 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> |  | ||||||
| 
 |  | ||||||
|                 <v-btn |  | ||||||
|                     @click="performLogout" |  | ||||||
|                     text |  | ||||||
|                 > |  | ||||||
|                     <v-tooltip |  | ||||||
|                         :text="t('logout')" |  | ||||||
|                         location="bottom" |  | ||||||
|                     > |  | ||||||
|                         <template v-slot:activator="{ props }"> |  | ||||||
|                             <v-icon |  | ||||||
|                                 v-bind="props" |  | ||||||
|                                 icon="mdi-logout" |  | ||||||
|                                 size="x-large" |  | ||||||
|                                 color="#0e6942" |  | ||||||
|                             /> |  | ||||||
|                         </template> |  | ||||||
|                     </v-tooltip> |  | ||||||
|                 </v-btn> |  | ||||||
|             </v-app-bar> |  | ||||||
| 
 |  | ||||||
|             <v-navigation-drawer |  | ||||||
|                 v-model="drawer" |  | ||||||
|                 app |  | ||||||
|             > |  | ||||||
|                 <v-list> |  | ||||||
|                     <v-list-item |  | ||||||
|                         to="/user/assignment" |  | ||||||
|                         link |  | ||||||
|                     > |  | ||||||
|                         <v-list-item-content> |  | ||||||
|                             <v-list-item-title class="menu_item">{{ t("assignments") }}</v-list-item-title> |  | ||||||
|                         </v-list-item-content> |  | ||||||
|                     </v-list-item> |  | ||||||
| 
 |  | ||||||
|                     <v-list-item |  | ||||||
|                         to="/user/class" |  | ||||||
|                         link |  | ||||||
|                     > |  | ||||||
|                         <v-list-item-content> |  | ||||||
|                             <v-list-item-title class="menu_item">{{ t("classes") }}</v-list-item-title> |  | ||||||
|                         </v-list-item-content> |  | ||||||
|                     </v-list-item> |  | ||||||
| 
 |  | ||||||
|                     <v-list-item |  | ||||||
|                         to="/user/discussion" |  | ||||||
|                         link |  | ||||||
|                     > |  | ||||||
|                         <v-list-item-content> |  | ||||||
|                             <v-list-item-title class="menu_item">{{ t("discussions") }}</v-list-item-title> |  | ||||||
|                         </v-list-item-content> |  | ||||||
|                     </v-list-item> |  | ||||||
|                 </v-list> |  | ||||||
|             </v-navigation-drawer> |  | ||||||
|         </div> |  | ||||||
|         <v-app-bar app> |  | ||||||
|             <nav class="menu"> |  | ||||||
|                 <div class="left"> |  | ||||||
|                     <ul> |  | ||||||
|                         <li> |  | ||||||
|                             <router-link |  | ||||||
|                                 to="/user" |  | ||||||
|                                 class="dwengo_home" |  | ||||||
|                             > |  | ||||||
|                                 <img |  | ||||||
|                                     class="dwengo_logo" |  | ||||||
|                                     :src="dwengoLogo" |  | ||||||
|                                 /> |  | ||||||
|                                 <p class="caption"> |  | ||||||
|                                     {{ t(`${role}`) }} |  | ||||||
|                                 </p> |  | ||||||
|                             </router-link> |  | ||||||
|                         </li> |  | ||||||
|                         <li> |  | ||||||
|                             <router-link |  | ||||||
|                                 :to="`/user/assignment`" |  | ||||||
|                                 class="menu_item" |  | ||||||
|                             > |  | ||||||
|                                 {{ t("assignments") }} |  | ||||||
|                             </router-link> |  | ||||||
|                         </li> |  | ||||||
|                         <li> |  | ||||||
|                             <router-link |  | ||||||
|                                 to="/user/class" |  | ||||||
|                                 class="menu_item" |  | ||||||
|                                 >{{ t("classes") }}</router-link |  | ||||||
|                             > |  | ||||||
|                         </li> |  | ||||||
|                         <li> |  | ||||||
|                             <router-link |  | ||||||
|                                 to="/user/discussion" |  | ||||||
|                                 class="menu_item" |  | ||||||
|                                 >{{ t("discussions") }} |  | ||||||
|                             </router-link> |  | ||||||
|                         </li> |  | ||||||
|                         <li> |  | ||||||
|                             <v-menu open-on-hover> |  | ||||||
|                                 <template v-slot:activator="{ props }"> |  | ||||||
|                                     <v-btn |  | ||||||
|                                         v-bind="props" |  | ||||||
|                                         icon |  | ||||||
|                                         variant="text" |  | ||||||
|                                     > |  | ||||||
|                                         <v-icon |  | ||||||
|                                             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> |  | ||||||
|                         </li> |  | ||||||
|                     </ul> |  | ||||||
|                 </div> |  | ||||||
|                 <div class="right"> |  | ||||||
|                     <li> |  | ||||||
|                         <!-- <v-btn |  | ||||||
|                             @click="performLogout" |  | ||||||
|                             to="/login" |  | ||||||
|                             style="background-color: transparent; box-shadow: none !important" |  | ||||||
|                         > |  | ||||||
|                             <v-tooltip |  | ||||||
|                                 :text="t('logout')" |  | ||||||
|                                 location="bottom" |  | ||||||
|                             > |  | ||||||
|                                 <template v-slot:activator="{ props }"> |  | ||||||
|                                     <v-icon |  | ||||||
|                                         v-bind="props" |  | ||||||
|                                         icon="mdi-logout" |  | ||||||
|                                         size="x-large" |  | ||||||
|                                         color="#0e6942" |  | ||||||
|                                     ></v-icon> |  | ||||||
|                                 </template> |  | ||||||
|                             </v-tooltip> |  | ||||||
|                         </v-btn> --> |  | ||||||
|                         <v-dialog max-width="500"> |  | ||||||
|                             <template v-slot:activator="{ props: activatorProps }"> |  | ||||||
|                                 <v-btn |  | ||||||
|                                     v-bind="activatorProps" |  | ||||||
|                                     style="background-color: transparent; box-shadow: none !important" |  | ||||||
|                                 > |  | ||||||
|                                     <v-tooltip |  | ||||||
|                                         :text="t('logout')" |  | ||||||
|                                         location="bottom" |  | ||||||
|                                     > |  | ||||||
|                                         <template v-slot:activator="{ props }"> |  | ||||||
|                                             <v-icon |  | ||||||
|                                                 v-bind="props" |  | ||||||
|                                                 icon="mdi-logout" |  | ||||||
|                                                 size="x-large" |  | ||||||
|                                                 color="#0e6942" |  | ||||||
|                                             > |  | ||||||
|                                             </v-icon> |  | ||||||
|                                         </template> |  | ||||||
|                                     </v-tooltip> |  | ||||||
|                                 </v-btn> |  | ||||||
|                             </template> |  | ||||||
| 
 |  | ||||||
|                             <template v-slot:default="{ isActive }"> |  | ||||||
|                                 <v-card :title="t('logoutVerification')"> |  | ||||||
|                                     <v-card-actions> |  | ||||||
|                                         <v-spacer></v-spacer> |  | ||||||
| 
 |  | ||||||
|                                         <v-btn |  | ||||||
|                                             :text="t('cancel')" |  | ||||||
|                                             @click="isActive.value = false" |  | ||||||
|                                         ></v-btn> |  | ||||||
|                                         <v-btn |  | ||||||
|                                             :text="t('logout')" |  | ||||||
|                                             @click="performLogout" |  | ||||||
|                                             to="/login" |  | ||||||
|                                         ></v-btn> |  | ||||||
|                                     </v-card-actions> |  | ||||||
|                                 </v-card> |  | ||||||
|                             </template> |  | ||||||
|                         </v-dialog> |  | ||||||
|                     </li> |  | ||||||
|                     <li> |  | ||||||
|                         <v-avatar |  | ||||||
|                             size="large" |  | ||||||
|                             color="#0e6942" |  | ||||||
|                             style="font-size: large; font-weight: bold" |  | ||||||
|                             >{{ initials }}</v-avatar |  | ||||||
|                         > |  | ||||||
|                     </li> |  | ||||||
|                 </div> |  | ||||||
|             </nav> |  | ||||||
|         </v-app-bar> |  | ||||||
|     </main> |  | ||||||
| </template> |  | ||||||
| 
 |  | ||||||
| <style scoped> |  | ||||||
|     .menu { |  | ||||||
|         background-color: #f6faf2; |  | ||||||
|         display: flex; |  | ||||||
|         justify-content: space-between; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .right { |  | ||||||
|         align-items: center; |  | ||||||
|         padding: 10px; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .right li { |  | ||||||
|         margin-left: 15px; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     nav ul { |  | ||||||
|         display: flex; |  | ||||||
|         list-style-type: none; |  | ||||||
|         margin: 0; |  | ||||||
|         padding: 0; |  | ||||||
|         gap: 15px; |  | ||||||
|         align-items: center; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     li { |  | ||||||
|         display: inline; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .dwengo_home { |  | ||||||
|         text-align: center; |  | ||||||
|         text-decoration: none; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .dwengo_logo { |  | ||||||
|         width: 150px; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .caption { |  | ||||||
|         color: black; |  | ||||||
|         margin-top: -25px; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     .menu_item { |  | ||||||
|         color: #0e6942; |  | ||||||
|         text-decoration: none; |  | ||||||
|         font-size: large; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     nav a.router-link-active { |  | ||||||
|         font-weight: bold; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @media (max-width: 700px) { |  | ||||||
|         .menu { |  | ||||||
|             display: none; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     @media (min-width: 701px) { |  | ||||||
|         .menu_collapsed { |  | ||||||
|             display: none; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| </style> |  | ||||||
|  | @ -22,7 +22,7 @@ | ||||||
|         { name: "English", code: "en" }, |         { name: "English", code: "en" }, | ||||||
|         { name: "Nederlands", code: "nl" }, |         { name: "Nederlands", code: "nl" }, | ||||||
|         { name: "Français", code: "fr" }, |         { name: "Français", code: "fr" }, | ||||||
|         { name: "Deutsch", code: "de" } |         { name: "Deutsch", code: "de" }, | ||||||
|     ]); |     ]); | ||||||
| 
 | 
 | ||||||
|     // Logic to change the language of the website to the selected language |     // Logic to change the language of the website to the selected language | ||||||
|  | @ -31,20 +31,26 @@ | ||||||
|         localStorage.setItem("user-lang", langCode); |         localStorage.setItem("user-lang", langCode); | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     // contains functionality to let the collapsed menu appear and disappear |     // Contains functionality to let the collapsed menu appear and disappear | ||||||
|     // when the screen size varies |     // When the screen size varies | ||||||
|     const drawer = ref(false); |     const drawer = ref(false); | ||||||
| 
 | 
 | ||||||
|     // when the user wants to logout, a popup is shown to verify this |     // When the user wants to logout, a popup is shown to verify this | ||||||
|     // if verified, the user should be logged out |     // If verified, the user should be logged out | ||||||
|     const performLogout = () => { |     const performLogout = () => { | ||||||
|         auth.logout(); |         auth.logout(); | ||||||
|     }; |     }; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <v-app-bar class="app-bar" app> |     <v-app-bar | ||||||
|         <v-app-bar-nav-icon class="menu_collapsed" @click="drawer = !drawer" /> |         class="app-bar" | ||||||
|  |         app | ||||||
|  |     > | ||||||
|  |         <v-app-bar-nav-icon | ||||||
|  |             class="menu_collapsed" | ||||||
|  |             @click="drawer = !drawer" | ||||||
|  |         /> | ||||||
|         <router-link |         <router-link | ||||||
|             to="/user" |             to="/user" | ||||||
|             class="dwengo_home" |             class="dwengo_home" | ||||||
|  | @ -55,9 +61,7 @@ | ||||||
|                     alt="Dwengo logo" |                     alt="Dwengo logo" | ||||||
|                     :src="dwengoLogo" |                     :src="dwengoLogo" | ||||||
|                 /> |                 /> | ||||||
|                 <p |                 <p class="caption"> | ||||||
|                     class="caption" |  | ||||||
|                 > |  | ||||||
|                     {{ t(`${role}`) }} |                     {{ t(`${role}`) }} | ||||||
|                 </p> |                 </p> | ||||||
|             </div> |             </div> | ||||||
|  |  | ||||||
|  | @ -31,7 +31,10 @@ defineProps<{ | ||||||
|         </v-card-title> |         </v-card-title> | ||||||
|         <v-card-text class="description flex-grow-1">{{ description }}</v-card-text> |         <v-card-text class="description flex-grow-1">{{ description }}</v-card-text> | ||||||
|         <v-card-actions> |         <v-card-actions> | ||||||
|             <v-btn :to="`theme/${path}`" variant="text"> |             <v-btn | ||||||
|  |                 :to="`theme/${path}`" | ||||||
|  |                 variant="text" | ||||||
|  |             > | ||||||
|                 {{ t("read-more") }} |                 {{ t("read-more") }} | ||||||
|             </v-btn> |             </v-btn> | ||||||
|         </v-card-actions> |         </v-card-actions> | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ import i18n from "./i18n/i18n.ts"; | ||||||
| // Components
 | // Components
 | ||||||
| import App from "./App.vue"; | import App from "./App.vue"; | ||||||
| import router from "./router"; | import router from "./router"; | ||||||
| import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query'; | import { VueQueryPlugin, QueryClient } from "@tanstack/vue-query"; | ||||||
| 
 | 
 | ||||||
| const app = createApp(App); | const app = createApp(App); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,25 +1,22 @@ | ||||||
| import { useQuery } from '@tanstack/vue-query'; | import { useQuery } from "@tanstack/vue-query"; | ||||||
| import { getThemeController } from '@/controllers/controllers'; | import { getThemeController } from "@/controllers/controllers"; | ||||||
| import { type MaybeRefOrGetter, toValue } from "vue"; | import { type MaybeRefOrGetter, toValue } from "vue"; | ||||||
| 
 | 
 | ||||||
| const themeController = getThemeController(); | const themeController = getThemeController(); | ||||||
| 
 | 
 | ||||||
| export const useThemeQuery = (language: MaybeRefOrGetter<string>) => { | export const useThemeQuery = (language: MaybeRefOrGetter<string>) => | ||||||
|     return useQuery({ |     useQuery({ | ||||||
|         queryKey: ['themes', language], |         queryKey: ["themes", language], | ||||||
|         queryFn: () => { |         queryFn: () => { | ||||||
|             const lang = toValue(language); |             const lang = toValue(language); | ||||||
|             return themeController.getAll(lang); |             return themeController.getAll(lang); | ||||||
|         }, |         }, | ||||||
|         enabled: () => !!toValue(language), |         enabled: () => Boolean(toValue(language)), | ||||||
|     }); |     }); | ||||||
| }; |  | ||||||
| 
 | 
 | ||||||
| export const useThemeHruidsQuery = (themeKey: string | null) => { | export const useThemeHruidsQuery = (themeKey: string | null) => | ||||||
|     return useQuery({ |     useQuery({ | ||||||
|         queryKey: ['theme-hruids', themeKey], |         queryKey: ["theme-hruids", themeKey], | ||||||
|         queryFn: () => themeController.getHruidsByKey(themeKey!), |         queryFn: () => themeController.getHruidsByKey(themeKey!), | ||||||
|         enabled: !!themeKey, |         enabled: Boolean(themeKey), | ||||||
|     }); |     }); | ||||||
| }; |  | ||||||
| 
 |  | ||||||
|  |  | ||||||
|  | @ -1,37 +1,64 @@ | ||||||
| export const THEMES_KEYS = [ | export const THEMES_KEYS = [ | ||||||
|     "kiks", "art", "socialrobot", "agriculture", "wegostem", |     "kiks", | ||||||
|     "computational_thinking", "math_with_python", "python_programming", |     "art", | ||||||
|     "stem", "care", "chatbot", "physical_computing", "algorithms", "basics_ai" |     "socialrobot", | ||||||
|  |     "agriculture", | ||||||
|  |     "wegostem", | ||||||
|  |     "computational_thinking", | ||||||
|  |     "math_with_python", | ||||||
|  |     "python_programming", | ||||||
|  |     "stem", | ||||||
|  |     "care", | ||||||
|  |     "chatbot", | ||||||
|  |     "physical_computing", | ||||||
|  |     "algorithms", | ||||||
|  |     "basics_ai", | ||||||
| ]; | ]; | ||||||
| 
 | 
 | ||||||
| export const THEMESITEMS: Record<string, string[]> = { | export const THEMESITEMS: Record<string, string[]> = { | ||||||
|     "all": THEMES_KEYS, |     all: THEMES_KEYS, | ||||||
|     "culture": ["art", "wegostem", "chatbot"], |     culture: ["art", "wegostem", "chatbot"], | ||||||
|     "electricity-and-mechanics": ["socialrobot", "wegostem", "stem", "physical_computing"], |     "electricity-and-mechanics": ["socialrobot", "wegostem", "stem", "physical_computing"], | ||||||
|     "nature-and-climate": ["kiks", "agriculture"], |     "nature-and-climate": ["kiks", "agriculture"], | ||||||
|     "agriculture": ["agriculture"], |     agriculture: ["agriculture"], | ||||||
|     "society": ["kiks", "socialrobot", "care", "chatbot"], |     society: ["kiks", "socialrobot", "care", "chatbot"], | ||||||
|     "math": ["kiks", "math_with_python", "python_programming", "stem", "care", "basics_ai"], |     math: ["kiks", "math_with_python", "python_programming", "stem", "care", "basics_ai"], | ||||||
|     "technology": ["socialrobot", "wegostem", "computational_thinking", "stem", "physical_computing", "basics_ai"], |     technology: ["socialrobot", "wegostem", "computational_thinking", "stem", "physical_computing", "basics_ai"], | ||||||
|     "algorithms": ["math_with_python", "python_programming", "stem", "algorithms", "basics_ai"], |     algorithms: ["math_with_python", "python_programming", "stem", "algorithms", "basics_ai"], | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const AGEITEMS = [ | export const AGEITEMS = ["all", "primary-school", "lower-secondary", "upper-secondary", "high-school", "older"]; | ||||||
|     "all", "primary-school", "lower-secondary", "upper-secondary", "high-school", "older" |  | ||||||
| ]; |  | ||||||
| 
 | 
 | ||||||
| export const AGE_TO_THEMES: Record<string, string[]> = { | export const AGE_TO_THEMES: Record<string, string[]> = { | ||||||
|     "all": THEMES_KEYS, |     all: THEMES_KEYS, | ||||||
|     "primary-school": ["wegostem", "computational_thinking", "physical_computing"], |     "primary-school": ["wegostem", "computational_thinking", "physical_computing"], | ||||||
|     "lower-secondary": ["socialrobot", "art", "wegostem", "computational_thinking", "physical_computing"], |     "lower-secondary": ["socialrobot", "art", "wegostem", "computational_thinking", "physical_computing"], | ||||||
|     "upper-secondary": ["kiks", "art", "socialrobot", "agriculture", |     "upper-secondary": [ | ||||||
|         "computational_thinking", "math_with_python", "python_programming", |         "kiks", | ||||||
|         "stem", "care", "chatbot", "algorithms", "basics_ai"], |         "art", | ||||||
|     "high-school": [ |         "socialrobot", | ||||||
|         "kiks", "art", "agriculture", "computational_thinking", "math_with_python", "python_programming", |         "agriculture", | ||||||
|         "stem", "care", "chatbot", "algorithms", "basics_ai" |         "computational_thinking", | ||||||
|  |         "math_with_python", | ||||||
|  |         "python_programming", | ||||||
|  |         "stem", | ||||||
|  |         "care", | ||||||
|  |         "chatbot", | ||||||
|  |         "algorithms", | ||||||
|  |         "basics_ai", | ||||||
|     ], |     ], | ||||||
|     "older": [ |     "high-school": [ | ||||||
|         "kiks", "computational_thinking", "algorithms", "basics_ai" |         "kiks", | ||||||
|     ] |         "art", | ||||||
|  |         "agriculture", | ||||||
|  |         "computational_thinking", | ||||||
|  |         "math_with_python", | ||||||
|  |         "python_programming", | ||||||
|  |         "stem", | ||||||
|  |         "care", | ||||||
|  |         "chatbot", | ||||||
|  |         "algorithms", | ||||||
|  |         "basics_ai", | ||||||
|  |     ], | ||||||
|  |     older: ["kiks", "computational_thinking", "algorithms", "basics_ai"], | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -8,7 +8,7 @@ | ||||||
|     onMounted(async () => { |     onMounted(async () => { | ||||||
|         try { |         try { | ||||||
|             await auth.handleLoginCallback(); |             await auth.handleLoginCallback(); | ||||||
|             await router.replace("/"); // Redirect to home (or dashboard) |             await router.replace("/user"); // Redirect to theme page | ||||||
|         } catch (error) { |         } catch (error) { | ||||||
|             console.error("OIDC callback error:", error); |             console.error("OIDC callback error:", error); | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -1,11 +1,7 @@ | ||||||
| <script setup lang="ts"> | <script setup lang="ts"></script> | ||||||
| 
 |  | ||||||
| </script> |  | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <main></main> |     <main></main> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <style scoped> | <style scoped></style> | ||||||
| 
 |  | ||||||
| </style> |  | ||||||
|  |  | ||||||
|  | @ -6,8 +6,8 @@ import {ref, watch} from "vue"; | ||||||
| 
 | 
 | ||||||
|     const { t, locale } = useI18n(); |     const { t, locale } = useI18n(); | ||||||
| 
 | 
 | ||||||
|     const selectedThemeKey = ref<string>('all'); |     const selectedThemeKey = ref<string>("all"); | ||||||
|     const selectedAgeKey = ref<string>('all'); |     const selectedAgeKey = ref<string>("all"); | ||||||
| 
 | 
 | ||||||
|     const allThemes = ref(Object.keys(THEMESITEMS)); |     const allThemes = ref(Object.keys(THEMESITEMS)); | ||||||
|     const availableThemes = ref([...allThemes.value]); |     const availableThemes = ref([...allThemes.value]); | ||||||
|  | @ -17,18 +17,17 @@ import {ref, watch} from "vue"; | ||||||
| 
 | 
 | ||||||
|     // Reset selection when language changes |     // Reset selection when language changes | ||||||
|     watch(locale, () => { |     watch(locale, () => { | ||||||
|         selectedThemeKey.value = 'all'; |         selectedThemeKey.value = "all"; | ||||||
|         selectedAgeKey.value = 'all'; |         selectedAgeKey.value = "all"; | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     watch(selectedThemeKey, () => { |     watch(selectedThemeKey, () => { | ||||||
|         if (selectedThemeKey.value === "all") { |         if (selectedThemeKey.value === "all") { | ||||||
|             availableAges.value = [...allAges.value]; // Reset to all ages |             availableAges.value = [...allAges.value]; // Reset to all ages | ||||||
|         } else { |         } else { | ||||||
|             const themes = THEMESITEMS[selectedThemeKey.value]; |             const themes = THEMESITEMS[selectedThemeKey.value]; | ||||||
|             availableAges.value = allAges.value.filter(age => |             availableAges.value = allAges.value.filter((age) => | ||||||
|                 AGE_TO_THEMES[age]?.some(theme => themes.includes(theme)) |                 AGE_TO_THEMES[age]?.some((theme) => themes.includes(theme)), | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
|  | @ -38,32 +37,31 @@ import {ref, watch} from "vue"; | ||||||
|             availableThemes.value = [...allThemes.value]; // Reset to all themes |             availableThemes.value = [...allThemes.value]; // Reset to all themes | ||||||
|         } else { |         } else { | ||||||
|             const themes = AGE_TO_THEMES[selectedAgeKey.value]; |             const themes = AGE_TO_THEMES[selectedAgeKey.value]; | ||||||
|             availableThemes.value = allThemes.value.filter(theme => |             availableThemes.value = allThemes.value.filter((theme) => | ||||||
|                 THEMESITEMS[theme]?.some(theme => themes.includes(theme)) |                 THEMESITEMS[theme]?.some((theme) => themes.includes(theme)), | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     }); |     }); | ||||||
| 
 |  | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <template> | <template> | ||||||
|     <div class="main-container"> |     <div class="main-container"> | ||||||
|         <h1 class="title">{{ t("themes") }}</h1> |         <h1 class="title">{{ t("themes") }}</h1> | ||||||
|         <v-container class="dropdowns"> |         <v-container class="dropdowns"> | ||||||
|             <v-select class="v-select" |             <v-select | ||||||
|  |                 class="v-select" | ||||||
|                 :label="t('choose-theme')" |                 :label="t('choose-theme')" | ||||||
|                       :items="availableThemes.map(theme => ({ title: t(`theme-options.${theme}`), value: theme }))" |                 :items="availableThemes.map((theme) => ({ title: t(`theme-options.${theme}`), value: theme }))" | ||||||
|                 v-model="selectedThemeKey" |                 v-model="selectedThemeKey" | ||||||
|                 item-title="title" |                 item-title="title" | ||||||
|                 item-value="value" |                 item-value="value" | ||||||
|                 variant="outlined" |                 variant="outlined" | ||||||
|             /> |             /> | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|             <v-select |             <v-select | ||||||
|                 class="v-select" |                 class="v-select" | ||||||
|                 :label="t('choose-age')" |                 :label="t('choose-age')" | ||||||
|                 :items="availableAges.map(age => ({ key: age, label: t(`age-options.${age}`), value: age }))" |                 :items="availableAges.map((age) => ({ key: age, label: t(`age-options.${age}`), value: age }))" | ||||||
|                 v-model="selectedAgeKey" |                 v-model="selectedAgeKey" | ||||||
|                 item-title="label" |                 item-title="label" | ||||||
|                 item-value="key" |                 item-value="key" | ||||||
|  | @ -71,7 +69,10 @@ import {ref, watch} from "vue"; | ||||||
|             ></v-select> |             ></v-select> | ||||||
|         </v-container> |         </v-container> | ||||||
| 
 | 
 | ||||||
|         <BrowseThemes :selectedTheme="selectedThemeKey ?? ''" :selectedAge="selectedAgeKey ?? ''"/> |         <BrowseThemes | ||||||
|  |             :selectedTheme="selectedThemeKey ?? ''" | ||||||
|  |             :selectedAge="selectedAgeKey ?? ''" | ||||||
|  |         /> | ||||||
|     </div> |     </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
|  | @ -94,7 +95,6 @@ import {ref, watch} from "vue"; | ||||||
|         justify-content: center; |         justify-content: center; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     .dropdowns { |     .dropdowns { | ||||||
|         display: flex; |         display: flex; | ||||||
|         justify-content: space-between; |         justify-content: space-between; | ||||||
|  | @ -107,7 +107,6 @@ import {ref, watch} from "vue"; | ||||||
|         min-width: 100px; |         min-width: 100px; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|     @media (max-width: 768px) { |     @media (max-width: 768px) { | ||||||
|         .main-container { |         .main-container { | ||||||
|             padding: 1rem; |             padding: 1rem; | ||||||
|  | @ -121,5 +120,4 @@ import {ref, watch} from "vue"; | ||||||
|             width: 80%; |             width: 80%; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| </style> | </style> | ||||||
|  |  | ||||||
		Reference in a new issue
	
	 Gerald Schmittinger
						Gerald Schmittinger