style: fix linting issues met Prettier
This commit is contained in:
		
							parent
							
								
									56d34adbc0
								
							
						
					
					
						commit
						7ad808cf3b
					
				
					 34 changed files with 244 additions and 214 deletions
				
			
		|  | @ -9,7 +9,7 @@ import { EnvVars, getNumericEnvVar } from './util/envvars.js'; | |||
| import apiRouter from './routes/router.js'; | ||||
| import swaggerMiddleware from './swagger.js'; | ||||
| import swaggerUi from 'swagger-ui-express'; | ||||
| import {errorHandler} from "./middleware/error-handling/error-handler"; | ||||
| import { errorHandler } from './middleware/error-handling/error-handler'; | ||||
| 
 | ||||
| const logger: Logger = getLogger(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import { EnvVars, getEnvVar } from '../util/envvars.js'; | |||
| import { Language } from '../entities/content/language.js'; | ||||
| import attachmentService from '../services/learning-objects/attachment-service.js'; | ||||
| import { NotFoundError } from '@mikro-orm/core'; | ||||
| import {BadRequestException} from "../exceptions/bad-request-exception.js"; | ||||
| import { BadRequestException } from '../exceptions/bad-request-exception.js'; | ||||
| 
 | ||||
| function getLearningObjectIdentifierFromRequest(req: Request): LearningObjectIdentifier { | ||||
|     if (!req.params.hruid) { | ||||
|  |  | |||
|  | @ -8,8 +8,8 @@ import { | |||
|     personalizedForGroup, | ||||
|     personalizedForStudent, | ||||
| } from '../services/learning-paths/learning-path-personalization-util.js'; | ||||
| import {BadRequestException} from "../exceptions/bad-request-exception.js"; | ||||
| import {NotFoundException} from "../exceptions/not-found-exception.js"; | ||||
| import { BadRequestException } from '../exceptions/bad-request-exception.js'; | ||||
| import { NotFoundException } from '../exceptions/not-found-exception.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Fetch learning paths based on query parameters. | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ export async function createStudentHandler(req: Request, res: Response) { | |||
| 
 | ||||
|     if (!newUser) { | ||||
|         res.status(500).json({ | ||||
|             error: 'Something went wrong while creating student' | ||||
|             error: 'Something went wrong while creating student', | ||||
|         }); | ||||
|         return; | ||||
|     } | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| import {EntityRepository, FilterQuery} from '@mikro-orm/core'; | ||||
| import {EntityAlreadyExistsException} from "../exceptions/entity-already-exists-exception"; | ||||
| import { EntityRepository, FilterQuery } from '@mikro-orm/core'; | ||||
| import { EntityAlreadyExistsException } from '../exceptions/entity-already-exists-exception'; | ||||
| 
 | ||||
| export abstract class DwengoEntityRepository<T extends object> extends EntityRepository<T> { | ||||
|     public async save(entity: T, options?: {preventOverwrite?: boolean}): Promise<void> { | ||||
|         if (options?.preventOverwrite && await this.findOne(entity)) { | ||||
|     public async save(entity: T, options?: { preventOverwrite?: boolean }): Promise<void> { | ||||
|         if (options?.preventOverwrite && (await this.findOne(entity))) { | ||||
|             throw new EntityAlreadyExistsException(`A ${this.getEntityName()} with this identifier already exists.`); | ||||
|         } | ||||
|         await this.getEntityManager().persistAndFlush(entity); | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ExceptionWithHttpState} from "./exception-with-http-state.js"; | ||||
| import { ExceptionWithHttpState } from './exception-with-http-state.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Exception for HTTP 400 Bad Request | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ExceptionWithHttpState} from "./exception-with-http-state.js"; | ||||
| import { ExceptionWithHttpState } from './exception-with-http-state.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Exception for HTTP 409 Conflict | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ConflictException} from "./conflict-exception"; | ||||
| import { ConflictException } from './conflict-exception'; | ||||
| 
 | ||||
| export class EntityAlreadyExistsException extends ConflictException { | ||||
|     constructor(message: string) { | ||||
|  |  | |||
|  | @ -2,8 +2,10 @@ | |||
|  * Exceptions which are associated with a HTTP error code. | ||||
|  */ | ||||
| export abstract class ExceptionWithHttpState extends Error { | ||||
|     constructor(public status: number, public error: string) { | ||||
|     constructor( | ||||
|         public status: number, | ||||
|         public error: string | ||||
|     ) { | ||||
|         super(error); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ExceptionWithHttpState} from "./exception-with-http-state.js"; | ||||
| import { ExceptionWithHttpState } from './exception-with-http-state.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Exception for HTTP 403 Forbidden | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ExceptionWithHttpState} from "./exception-with-http-state.js"; | ||||
| import { ExceptionWithHttpState } from './exception-with-http-state.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Exception for HTTP 404 Not Found | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ExceptionWithHttpState} from "./exception-with-http-state.js"; | ||||
| import { ExceptionWithHttpState } from './exception-with-http-state.js'; | ||||
| 
 | ||||
| /** | ||||
|  * Exception for HTTP 401 Unauthorized | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { Student } from '../entities/users/student.entity.js'; | ||||
| import {getStudentRepository} from "../data/repositories"; | ||||
| import { getStudentRepository } from '../data/repositories'; | ||||
| 
 | ||||
| export interface StudentDTO { | ||||
|     id: string; | ||||
|  | @ -27,6 +27,6 @@ export function mapToStudent(studentData: StudentDTO): Student { | |||
|     return getStudentRepository().create({ | ||||
|         username: studentData.username, | ||||
|         firstName: studentData.firstName, | ||||
|         lastName: studentData.lastName | ||||
|         lastName: studentData.lastName, | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| import { Teacher } from '../entities/users/teacher.entity.js'; | ||||
| import {getTeacherRepository} from "../data/repositories"; | ||||
| import { getTeacherRepository } from '../data/repositories'; | ||||
| 
 | ||||
| export interface TeacherDTO { | ||||
|     id: string; | ||||
|  | @ -27,6 +27,6 @@ export function mapToTeacher(teacherData: TeacherDTO): Teacher { | |||
|     return getTeacherRepository().create({ | ||||
|         username: teacherData.username, | ||||
|         firstName: teacherData.firstName, | ||||
|         lastName: teacherData.lastName | ||||
|         lastName: teacherData.lastName, | ||||
|     }); | ||||
| } | ||||
|  |  | |||
|  | @ -6,8 +6,8 @@ import * as express from 'express'; | |||
| import * as jwt from 'jsonwebtoken'; | ||||
| import { AuthenticatedRequest } from './authenticated-request.js'; | ||||
| import { AuthenticationInfo } from './authentication-info.js'; | ||||
| import {UnauthorizedException} from "../../exceptions/unauthorized-exception"; | ||||
| import {ForbiddenException} from "../../exceptions/forbidden-exception"; | ||||
| import { UnauthorizedException } from '../../exceptions/unauthorized-exception'; | ||||
| import { ForbiddenException } from '../../exceptions/forbidden-exception'; | ||||
| 
 | ||||
| const JWKS_CACHE = true; | ||||
| const JWKS_RATE_LIMIT = true; | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import {NextFunction, Request, Response} from "express"; | ||||
| import {getLogger, Logger} from "../../logging/initalize"; | ||||
| import {ExceptionWithHttpState} from "../../exceptions/exception-with-http-state"; | ||||
| import { NextFunction, Request, Response } from 'express'; | ||||
| import { getLogger, Logger } from '../../logging/initalize'; | ||||
| import { ExceptionWithHttpState } from '../../exceptions/exception-with-http-state'; | ||||
| 
 | ||||
| const logger: Logger = getLogger(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -92,4 +92,3 @@ export async function getLearningObjectsFromPath(hruid: string, language: string | |||
| export async function getLearningObjectIdsFromPath(hruid: string, language: string): Promise<string[]> { | ||||
|     return (await fetchLearningObjects(hruid, false, language)) as string[]; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -27,7 +27,7 @@ export async function createStudent(userData: StudentDTO): Promise<StudentDTO | | |||
|     const studentRepository = getStudentRepository(); | ||||
| 
 | ||||
|     const newStudent = mapToStudent(userData); | ||||
|     await studentRepository.save(newStudent, {preventOverwrite: true}); | ||||
|     await studentRepository.save(newStudent, { preventOverwrite: true }); | ||||
|     return mapToStudentDTO(newStudent); | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,9 +1,4 @@ | |||
| import { | ||||
|     getClassRepository, | ||||
|     getLearningObjectRepository, | ||||
|     getQuestionRepository, | ||||
|     getTeacherRepository, | ||||
| } from '../data/repositories.js'; | ||||
| import { getClassRepository, getLearningObjectRepository, getQuestionRepository, getTeacherRepository } from '../data/repositories.js'; | ||||
| import { ClassDTO, mapToClassDTO } from '../interfaces/class.js'; | ||||
| import { getClassStudents } from './classes.js'; | ||||
| import { StudentDTO } from '../interfaces/student.js'; | ||||
|  | @ -31,7 +26,7 @@ export async function createTeacher(userData: TeacherDTO): Promise<TeacherDTO | | |||
|     const teacherRepository = getTeacherRepository(); | ||||
| 
 | ||||
|     const newTeacher = mapToTeacher(userData); | ||||
|     await teacherRepository.save(newTeacher, {preventOverwrite: true}); | ||||
|     await teacherRepository.save(newTeacher, { preventOverwrite: true }); | ||||
| 
 | ||||
|     return mapToTeacherDTO(newTeacher); | ||||
| } | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ describe('StudentRepository', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('should return the queried student after he was added', async () => { | ||||
|         await studentRepository.insert(studentRepository.create({username, firstName, lastName})); | ||||
|         await studentRepository.insert(studentRepository.create({ username, firstName, lastName })); | ||||
| 
 | ||||
|         const retrievedStudent = await studentRepository.findByUsername(username); | ||||
|         expect(retrievedStudent).toBeTruthy(); | ||||
|  |  | |||
|  | @ -29,7 +29,7 @@ describe('TeacherRepository', () => { | |||
|     }); | ||||
| 
 | ||||
|     it('should return the queried teacher after he was added', async () => { | ||||
|         await teacherRepository.insert(teacherRepository.create({username, firstName, lastName})); | ||||
|         await teacherRepository.insert(teacherRepository.create({ username, firstName, lastName })); | ||||
| 
 | ||||
|         const retrievedTeacher = await teacherRepository.findByUsername(username); | ||||
|         expect(retrievedTeacher).toBeTruthy(); | ||||
|  |  | |||
|  | @ -1,47 +1,56 @@ | |||
| <script setup lang="ts"> | ||||
| import ThemeCard from "@/components/ThemeCard.vue"; | ||||
| import { ref, watchEffect, computed } from "vue"; | ||||
| import { useI18n } from "vue-i18n"; | ||||
| import { AGE_TO_THEMES, THEMESITEMS } from "@/utils/constants.ts"; | ||||
| import { useThemeQuery } from "@/queries/themes.ts"; | ||||
|     import ThemeCard from "@/components/ThemeCard.vue"; | ||||
|     import { ref, watchEffect, computed } from "vue"; | ||||
|     import { useI18n } from "vue-i18n"; | ||||
|     import { AGE_TO_THEMES, THEMESITEMS } from "@/utils/constants.ts"; | ||||
|     import { useThemeQuery } from "@/queries/themes.ts"; | ||||
| 
 | ||||
| const props = defineProps({ | ||||
|     const props = defineProps({ | ||||
|         selectedTheme: { type: String, required: true }, | ||||
|     selectedAge: { type: String, required: true } | ||||
| }); | ||||
|         selectedAge: { type: String, required: true }, | ||||
|     }); | ||||
| 
 | ||||
| const { locale } = useI18n(); | ||||
| const language = computed(() => locale.value); | ||||
|     const { locale } = useI18n(); | ||||
|     const language = computed(() => locale.value); | ||||
| 
 | ||||
| const { data: allThemes, isLoading, error } = useThemeQuery(language); | ||||
|     const { data: allThemes, isLoading, error } = useThemeQuery(language); | ||||
| 
 | ||||
| const allCards = ref([]); | ||||
| const cards = ref([]); | ||||
|     const allCards = ref([]); | ||||
|     const cards = ref([]); | ||||
| 
 | ||||
| watchEffect(() => { | ||||
|     watchEffect(() => { | ||||
|         const themes = allThemes.value ?? []; | ||||
|         allCards.value = themes; | ||||
| 
 | ||||
|         if (props.selectedTheme) { | ||||
|         cards.value = themes.filter((theme) => | ||||
|             cards.value = themes.filter( | ||||
|                 (theme) => | ||||
|                     THEMESITEMS[props.selectedTheme]?.includes(theme.key) && | ||||
|             AGE_TO_THEMES[props.selectedAge]?.includes(theme.key) | ||||
|                     AGE_TO_THEMES[props.selectedAge]?.includes(theme.key), | ||||
|             ); | ||||
|         } else { | ||||
|             cards.value = themes; | ||||
|         } | ||||
| }); | ||||
|     }); | ||||
| </script> | ||||
| 
 | ||||
| 
 | ||||
| <template> | ||||
|     <v-container> | ||||
|         <div v-if="isLoading" class="text-center py-10"> | ||||
|             <v-progress-circular indeterminate color="primary" /> | ||||
|         <div | ||||
|             v-if="isLoading" | ||||
|             class="text-center py-10" | ||||
|         > | ||||
|             <v-progress-circular | ||||
|                 indeterminate | ||||
|                 color="primary" | ||||
|             /> | ||||
|             <p>Loading...</p> | ||||
|         </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> | ||||
|             <p>Error loading: {{ error.message }}</p> | ||||
|         </div> | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ | |||
|         { name: "English", code: "en" }, | ||||
|         { name: "Nederlands", code: "nl" }, | ||||
|         { 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 | ||||
|  |  | |||
|  | @ -1,14 +1,14 @@ | |||
| <script setup lang="ts"> | ||||
| import { useI18n } from "vue-i18n"; | ||||
|     import { useI18n } from "vue-i18n"; | ||||
| 
 | ||||
| const { t } = useI18n(); | ||||
|     const { t } = useI18n(); | ||||
| 
 | ||||
| defineProps<{ | ||||
|     defineProps<{ | ||||
|         path: string; | ||||
|         title: string; | ||||
|         description: string; | ||||
|         image: string; | ||||
| }>(); | ||||
|     }>(); | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|  | @ -31,7 +31,10 @@ defineProps<{ | |||
|         </v-card-title> | ||||
|         <v-card-text class="description flex-grow-1">{{ description }}</v-card-text> | ||||
|         <v-card-actions> | ||||
|             <v-btn :to="`theme/${path}`" variant="text"> | ||||
|             <v-btn | ||||
|                 :to="`theme/${path}`" | ||||
|                 variant="text" | ||||
|             > | ||||
|                 {{ t("read-more") }} | ||||
|             </v-btn> | ||||
|         </v-card-actions> | ||||
|  | @ -39,36 +42,36 @@ defineProps<{ | |||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| .theme-card { | ||||
|     .theme-card { | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         height: 100%; | ||||
|         padding: 1rem; | ||||
|         cursor: pointer; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| .theme-card:hover { | ||||
|     .theme-card:hover { | ||||
|         background-color: rgba(0, 0, 0, 0.03); | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| .title-container { | ||||
|     .title-container { | ||||
|         display: flex; | ||||
|         align-items: center; | ||||
|         gap: 10px; | ||||
|         text-align: left; | ||||
|         justify-content: flex-start; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| .title-image { | ||||
|     .title-image { | ||||
|         flex-shrink: 0; | ||||
|         border-radius: 5px; | ||||
|         margin-left: 0; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| .title { | ||||
|     .title { | ||||
|         flex-grow: 1; | ||||
|         white-space: normal; | ||||
|         overflow-wrap: break-word; | ||||
|         word-break: break-word; | ||||
| } | ||||
|     } | ||||
| </style> | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {apiConfig} from "@/config.ts"; | ||||
| import { apiConfig } from "@/config.ts"; | ||||
| 
 | ||||
| export class BaseController { | ||||
|     protected baseUrl: string; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {ThemeController} from "@/controllers/themes.ts"; | ||||
| import { ThemeController } from "@/controllers/themes.ts"; | ||||
| 
 | ||||
| export function controllerGetter<T>(Factory: new () => T): () => T { | ||||
|     let instance: T | undefined; | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| import {BaseController} from "@/controllers/base-controller.ts"; | ||||
| import { BaseController } from "@/controllers/base-controller.ts"; | ||||
| 
 | ||||
| export class ThemeController extends BaseController { | ||||
|     constructor() { | ||||
|  |  | |||
|  | @ -10,7 +10,7 @@ import i18n from "./i18n/i18n.ts"; | |||
| // Components
 | ||||
| import App from "./App.vue"; | ||||
| import router from "./router"; | ||||
| import { VueQueryPlugin, QueryClient } from '@tanstack/vue-query'; | ||||
| import { VueQueryPlugin, QueryClient } from "@tanstack/vue-query"; | ||||
| 
 | ||||
| const app = createApp(App); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,11 +1,12 @@ | |||
| import { useQuery } from '@tanstack/vue-query'; | ||||
| import { getThemeController } from '@/controllers/controllers'; | ||||
| import {type MaybeRefOrGetter, toValue} from "vue"; | ||||
| import { useQuery } from "@tanstack/vue-query"; | ||||
| import { getThemeController } from "@/controllers/controllers"; | ||||
| import { type MaybeRefOrGetter, toValue } from "vue"; | ||||
| 
 | ||||
| const themeController = getThemeController(); | ||||
| 
 | ||||
| export const useThemeQuery = (language: MaybeRefOrGetter<string>) => useQuery({ | ||||
|         queryKey: ['themes', language], | ||||
| export const useThemeQuery = (language: MaybeRefOrGetter<string>) => | ||||
|     useQuery({ | ||||
|         queryKey: ["themes", language], | ||||
|         queryFn: () => { | ||||
|             const lang = toValue(language); | ||||
|             return themeController.getAll(lang); | ||||
|  | @ -13,9 +14,9 @@ export const useThemeQuery = (language: MaybeRefOrGetter<string>) => useQuery({ | |||
|         enabled: () => Boolean(toValue(language)), | ||||
|     }); | ||||
| 
 | ||||
| export const useThemeHruidsQuery = (themeKey: string | null) => useQuery({ | ||||
|         queryKey: ['theme-hruids', themeKey], | ||||
| export const useThemeHruidsQuery = (themeKey: string | null) => | ||||
|     useQuery({ | ||||
|         queryKey: ["theme-hruids", themeKey], | ||||
|         queryFn: () => themeController.getHruidsByKey(themeKey!), | ||||
|         enabled: Boolean(themeKey), | ||||
|     }); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,37 +1,64 @@ | |||
| export const THEMES_KEYS = [ | ||||
|     "kiks", "art", "socialrobot", "agriculture", "wegostem", | ||||
|     "computational_thinking", "math_with_python", "python_programming", | ||||
|     "stem", "care", "chatbot", "physical_computing", "algorithms", "basics_ai" | ||||
|     "kiks", | ||||
|     "art", | ||||
|     "socialrobot", | ||||
|     "agriculture", | ||||
|     "wegostem", | ||||
|     "computational_thinking", | ||||
|     "math_with_python", | ||||
|     "python_programming", | ||||
|     "stem", | ||||
|     "care", | ||||
|     "chatbot", | ||||
|     "physical_computing", | ||||
|     "algorithms", | ||||
|     "basics_ai", | ||||
| ]; | ||||
| 
 | ||||
| export const THEMESITEMS: Record<string, string[]> = { | ||||
|     "all": THEMES_KEYS, | ||||
|     "culture": ["art", "wegostem", "chatbot"], | ||||
|     all: THEMES_KEYS, | ||||
|     culture: ["art", "wegostem", "chatbot"], | ||||
|     "electricity-and-mechanics": ["socialrobot", "wegostem", "stem", "physical_computing"], | ||||
|     "nature-and-climate": ["kiks", "agriculture"], | ||||
|     "agriculture": ["agriculture"], | ||||
|     "society": ["kiks", "socialrobot", "care", "chatbot"], | ||||
|     "math": ["kiks", "math_with_python", "python_programming", "stem", "care", "basics_ai"], | ||||
|     "technology": ["socialrobot", "wegostem", "computational_thinking", "stem", "physical_computing", "basics_ai"], | ||||
|     "algorithms": ["math_with_python", "python_programming", "stem", "algorithms", "basics_ai"], | ||||
|     agriculture: ["agriculture"], | ||||
|     society: ["kiks", "socialrobot", "care", "chatbot"], | ||||
|     math: ["kiks", "math_with_python", "python_programming", "stem", "care", "basics_ai"], | ||||
|     technology: ["socialrobot", "wegostem", "computational_thinking", "stem", "physical_computing", "basics_ai"], | ||||
|     algorithms: ["math_with_python", "python_programming", "stem", "algorithms", "basics_ai"], | ||||
| }; | ||||
| 
 | ||||
| export const AGEITEMS = [ | ||||
|     "all", "primary-school", "lower-secondary", "upper-secondary", "high-school", "older" | ||||
| ]; | ||||
| export const AGEITEMS = ["all", "primary-school", "lower-secondary", "upper-secondary", "high-school", "older"]; | ||||
| 
 | ||||
| export const AGE_TO_THEMES: Record<string, string[]> = { | ||||
|     "all": THEMES_KEYS, | ||||
|     all: THEMES_KEYS, | ||||
|     "primary-school": ["wegostem", "computational_thinking", "physical_computing"], | ||||
|     "lower-secondary": ["socialrobot", "art", "wegostem", "computational_thinking", "physical_computing"], | ||||
|     "upper-secondary": ["kiks", "art", "socialrobot", "agriculture", | ||||
|         "computational_thinking", "math_with_python", "python_programming", | ||||
|         "stem", "care", "chatbot", "algorithms", "basics_ai"], | ||||
|     "high-school": [ | ||||
|         "kiks", "art", "agriculture", "computational_thinking", "math_with_python", "python_programming", | ||||
|         "stem", "care", "chatbot", "algorithms", "basics_ai" | ||||
|     "upper-secondary": [ | ||||
|         "kiks", | ||||
|         "art", | ||||
|         "socialrobot", | ||||
|         "agriculture", | ||||
|         "computational_thinking", | ||||
|         "math_with_python", | ||||
|         "python_programming", | ||||
|         "stem", | ||||
|         "care", | ||||
|         "chatbot", | ||||
|         "algorithms", | ||||
|         "basics_ai", | ||||
|     ], | ||||
|     "older": [ | ||||
|         "kiks", "computational_thinking", "algorithms", "basics_ai" | ||||
|     ] | ||||
|     "high-school": [ | ||||
|         "kiks", | ||||
|         "art", | ||||
|         "agriculture", | ||||
|         "computational_thinking", | ||||
|         "math_with_python", | ||||
|         "python_programming", | ||||
|         "stem", | ||||
|         "care", | ||||
|         "chatbot", | ||||
|         "algorithms", | ||||
|         "basics_ai", | ||||
|     ], | ||||
|     older: ["kiks", "computational_thinking", "algorithms", "basics_ai"], | ||||
| }; | ||||
|  |  | |||
|  | @ -1,11 +1,7 @@ | |||
| <script setup lang="ts"> | ||||
| 
 | ||||
| </script> | ||||
| <script setup lang="ts"></script> | ||||
| 
 | ||||
| <template> | ||||
| <main></main> | ||||
|     <main></main> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| 
 | ||||
| </style> | ||||
| <style scoped></style> | ||||
|  |  | |||
|  | @ -1,13 +1,13 @@ | |||
| <script setup lang="ts"> | ||||
| import {ref, watch} from "vue"; | ||||
|     import {useI18n} from "vue-i18n"; | ||||
|     import {THEMESITEMS, AGE_TO_THEMES} from "@/utils/constants.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 { t, locale } = useI18n(); | ||||
| 
 | ||||
|     const selectedThemeKey = ref<string>('all'); | ||||
|     const selectedAgeKey = ref<string>('all'); | ||||
|     const selectedThemeKey = ref<string>("all"); | ||||
|     const selectedAgeKey = ref<string>("all"); | ||||
| 
 | ||||
|     const allThemes = ref(Object.keys(THEMESITEMS)); | ||||
|     const availableThemes = ref([...allThemes.value]); | ||||
|  | @ -17,18 +17,17 @@ import {ref, watch} from "vue"; | |||
| 
 | ||||
|     // Reset selection when language changes | ||||
|     watch(locale, () => { | ||||
|         selectedThemeKey.value = 'all'; | ||||
|         selectedAgeKey.value = 'all'; | ||||
|         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)) | ||||
|             availableAges.value = allAges.value.filter((age) => | ||||
|                 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 | ||||
|         } else { | ||||
|             const themes = AGE_TO_THEMES[selectedAgeKey.value]; | ||||
|             availableThemes.value = allThemes.value.filter(theme => | ||||
|                 THEMESITEMS[theme]?.some(theme => themes.includes(theme)) | ||||
|             availableThemes.value = allThemes.value.filter((theme) => | ||||
|                 THEMESITEMS[theme]?.some((theme) => themes.includes(theme)), | ||||
|             ); | ||||
|         } | ||||
|     }); | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <template> | ||||
|     <div class="main-container"> | ||||
|         <h1 class="title">{{ t("themes") }}</h1> | ||||
|         <v-container class="dropdowns"> | ||||
|             <v-select class="v-select" | ||||
|             <v-select | ||||
|                 class="v-select" | ||||
|                 :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" | ||||
|                 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 }))" | ||||
|                 :items="availableAges.map((age) => ({ key: age, label: t(`age-options.${age}`), value: age }))" | ||||
|                 v-model="selectedAgeKey" | ||||
|                 item-title="label" | ||||
|                 item-value="key" | ||||
|  | @ -71,55 +69,55 @@ import {ref, watch} from "vue"; | |||
|             ></v-select> | ||||
|         </v-container> | ||||
| 
 | ||||
|         <BrowseThemes :selectedTheme="selectedThemeKey ?? ''" :selectedAge="selectedAgeKey ?? ''"/> | ||||
|         <BrowseThemes | ||||
|             :selectedTheme="selectedThemeKey ?? ''" | ||||
|             :selectedAge="selectedAgeKey ?? ''" | ||||
|         /> | ||||
|     </div> | ||||
| </template> | ||||
| 
 | ||||
| <style scoped> | ||||
| .main-container { | ||||
|     .main-container { | ||||
|         min-height: 100vh; | ||||
|         min-width: 100vw; | ||||
|         display: flex; | ||||
|         flex-direction: column; | ||||
|         align-items: flex-start; | ||||
|         justify-content: flex-start; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| .title { | ||||
|     .title { | ||||
|         max-width: 50rem; | ||||
|         margin-left: 1rem; | ||||
|         margin-top: 1rem; | ||||
|         text-align: center; | ||||
|         display: flex; | ||||
|         justify-content: center; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| .dropdowns { | ||||
|     .dropdowns { | ||||
|         display: flex; | ||||
|         justify-content: space-between; | ||||
|         gap: 5rem; | ||||
|         width: 80%; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| .v-select { | ||||
|     .v-select { | ||||
|         flex: 1; | ||||
|         min-width: 100px; | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
| @media (max-width: 768px) { | ||||
|     @media (max-width: 768px) { | ||||
|         .main-container { | ||||
|             padding: 1rem; | ||||
|         } | ||||
| } | ||||
|     } | ||||
| 
 | ||||
| @media (max-width: 700px) { | ||||
|     @media (max-width: 700px) { | ||||
|         .dropdowns { | ||||
|             flex-direction: column; | ||||
|             gap: 1rem; | ||||
|             width: 80%; | ||||
|         } | ||||
| } | ||||
| 
 | ||||
|     } | ||||
| </style> | ||||
|  |  | |||
		Reference in a new issue
	
	 Lint Action
						Lint Action