diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 00000000..7c4f96a0 --- /dev/null +++ b/.mcp.json @@ -0,0 +1,13 @@ +{ + "mcpServers": { + "svelte": { + "type": "stdio", + "command": "npx", + "args": [ + "-y", + "@sveltejs/mcp" + ], + "env": {} + } + } +} \ No newline at end of file diff --git a/android/app/build.gradle b/android/app/build.gradle index 5de6a56d..f99979f2 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -10,8 +10,8 @@ android { applicationId "app.aristomate.gr" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion 35 - versionCode 60 - versionName '2.1.8 Lonely' + versionCode 62 + versionName '2.1.10 Flying Whales' testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" aaptOptions { // Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps. diff --git a/src/lib/components/calendar/CalendarGrid.svelte b/src/lib/components/calendar/CalendarGrid.svelte index 0ded7cf9..33e1fd6d 100644 --- a/src/lib/components/calendar/CalendarGrid.svelte +++ b/src/lib/components/calendar/CalendarGrid.svelte @@ -163,9 +163,6 @@ transition: background 0.15s ease; font-weight: 500; } - .header .month-title { - background: var(--ion-color-light); - } .header ion-icon { font-size: 1.15rem; @@ -200,7 +197,6 @@ gap: 0.15rem; } .day.selectable { - background: var(--ion-color-light); cursor: pointer; transform: scale(1.05); } diff --git a/src/lib/components/grades/chips.svelte b/src/lib/components/grades/chips.svelte index 7c59e3d5..96305336 100644 --- a/src/lib/components/grades/chips.svelte +++ b/src/lib/components/grades/chips.svelte @@ -1,13 +1,11 @@ + +
+
+ {course.courseTitle} + + {#if course.examPeriod != null} + + {#if course.examPeriod && course.gradeYear} + {course.examPeriod.name} {course.gradeYear.name} + {:else if course.registrationType === 1} + {$t('progress.exempted')} + {:else} + {$t('progress.declared')} + {/if} + + {:else} + - + {/if} +
+ {#if course.grade != null && !isNaN(course.grade)} + {#if course.grade * 10 >= 5} + +

{course.formattedGrade}

+
+ {:else} + +

{course.formattedGrade}

+
+ {/if} + {/if} +
+ + diff --git a/src/lib/components/grades/gradeCard.svelte b/src/lib/components/grades/gradeCard.svelte index b60b36a9..c9e7e92b 100644 --- a/src/lib/components/grades/gradeCard.svelte +++ b/src/lib/components/grades/gradeCard.svelte @@ -1,22 +1,25 @@ diff --git a/src/lib/components/grades/gradesPage.svelte b/src/lib/components/grades/gradesPage.svelte index 31bd075b..5956f450 100644 --- a/src/lib/components/grades/gradesPage.svelte +++ b/src/lib/components/grades/gradesPage.svelte @@ -12,6 +12,8 @@ import { flipped } from "./flipstore"; import { averagesPerSemester } from '$lib/functions/gradeAverages/averagesPerSemester'; import { writable } from 'svelte/store'; + import type { Writable } from 'svelte/store'; + import type { course } from '$lib/types/courseType'; import Fuse from 'fuse.js'; import { onMount } from 'svelte'; import { t } from "$lib/i18n"; @@ -34,8 +36,14 @@ classes: {id: string;finalGrade: number;coefficient: number;isPassed: number;registration: number;course: string}[]; } - let courseBySemester = writable([]); - let filteredSubjects = writable([]); + interface SemesterGroup { + semesterId: string; + average: string; + courses: course[]; + } + + let semesterGroups: Writable = writable([]); + let filteredSubjects: Writable = writable([]); let registrationsInDegree: Registration[]; const fuseOptions = { @@ -47,17 +55,8 @@ let searchQuery = ''; let subjects = 0; let passedSubjects = 0; - let coursesBySemester = {}; - let subjectsJSON: number | null | undefined; - - /** - * @type {string} - */ - let semesterId: any; - - /** - * @param {{ target: { value: string; }; }} event - */ + let coursesBySemester: { [key: string]: course[] } = {}; + let subjectsJSON: course[] = []; // Search function handleChange(event: { target: { value: string } }) { @@ -69,25 +68,22 @@ $flipped = !$flipped; } - async function getSubjects(subjectsJSON: any) { - coursesBySemester = await coursesPerSemester(subjectsJSON); - // @ts-ignore - passedSubjects = subjects - .filter((/** @type {{ grade: number; }} */ course) => course.grade * 10 >= 5) - .filter(/** @type {{parentCourse: string;}} */ (course) => course.parentCourse === null); - - // @ts-ignore - subjects = subjects.length; - // @ts-ignore - passedSubjects = passedSubjects.length; + async function getSubjects(courses: course[]) { + coursesBySemester = await coursesPerSemester(courses); + const passed = courses + .filter((course) => course.grade * 10 >= 5) + .filter((course) => course.parentCourse == null); + + subjects = courses.length; + passedSubjects = passed.length; } - async function gatherGrades(subjectsJSON: any) { + async function gatherGrades(subjectsJSON: course[]) { const courses = await coursesPerSemester(subjectsJSON); const semesterAverage = await averagesPerSemester(subjectsJSON); // keep semester id, average, and courses in an array - const semesters = Object.keys(courses).map((key) => { + const semesters: SemesterGroup[] = Object.keys(courses).map((key) => { return { semesterId: key, average: semesterAverage[key] ? semesterAverage[key] : '-', @@ -95,32 +91,30 @@ }; }); - semesters.sort((a, b) => a.semesterId - b.semesterId); + semesters.sort((a, b) => Number(a.semesterId) - Number(b.semesterId)); - courseBySemester.set(semesters); + semesterGroups.set(semesters); return semesters; } async function gatherProgressionData(){ - const registration_options = "$select=id,semester,classes&$expand=classes($select=id,finalGrade,coefficient,isPassed,course;$filter=isPassed eq 1)&$orderBy=semester&$top=-1" - const all_registrations: Registration[] = (await neoUniversisGet(`students/me/registrations?${registration_options}`, { lifetime: 1200 })).value - - const calculateGrade_options = "$select=id,course,calculateGrade,isPassed,courseTitle&$filter=calculateGrade eq 0,isPassed eq 1&$top=-1" - const nonCalculatedGrades: {"id": string;"course": string;"calculateGrade": 0;"isPassed": 1;}[] = (await neoUniversisGet(`students/me/courses?${calculateGrade_options}`, { lifetime: 1200 })).value - - const disallowed_courses = new Set(nonCalculatedGrades.map(item => item.course)) - registrationsInDegree = all_registrations.map(registration => ({ + const registrationOptions = "$select=id,semester,classes&$expand=classes($select=id,finalGrade,coefficient,isPassed,course;$filter=isPassed eq 1)&$orderBy=semester&$top=-1" + const allRegistrations: Registration[] = (await neoUniversisGet(`students/me/registrations?${registrationOptions}`, { lifetime: 1200 })).value + + const calculateGradeOptions = "$select=id,course,calculateGrade,isPassed,courseTitle&$filter=calculateGrade eq 0,isPassed eq 1&$top=-1" + const nonCalculatedGrades: { id: string; course: string; calculateGrade: 0; isPassed: 1 }[] = (await neoUniversisGet(`students/me/courses?${calculateGradeOptions}`, { lifetime: 1200 })).value + + const disallowedCourses = new Set(nonCalculatedGrades.map(item => item.course)) + registrationsInDegree = allRegistrations.map(registration => ({ ...registration, - classes: registration.classes.filter(class_instance => !disallowed_courses.has(class_instance.course) && class_instance.isPassed == 1) + classes: registration.classes.filter(classInstance => !disallowedCourses.has(classInstance.course) && classInstance.isPassed == 1) })) - } + } async function gatherData() { - subjects = (await neoUniversisGet('students/me/courses?$top=-1', { lifetime: 600 })).value; - - subjectsJSON = subjects; + subjectsJSON = (await neoUniversisGet('students/me/courses?$top=-1', { lifetime: 600 })).value; await getSubjects(subjectsJSON); await gatherGrades(subjectsJSON); @@ -130,12 +124,12 @@ // Filter the results based on the searchQuery $: { - const courses = $courseBySemester; + const courses = $semesterGroups; if (searchQuery.length === 0) { filteredSubjects.set(courses); } else { - const subjects = courses.reduce((acc, curr) => acc.concat(curr.courses), []); - const fuse = new Fuse(subjects, fuseOptions); + const allCourses = courses.reduce((acc, curr) => acc.concat(curr.courses), []); + const fuse = new Fuse(allCourses, fuseOptions); const searchResults = fuse.search(searchQuery); const filtered = courses.map((semester) => { @@ -170,7 +164,7 @@ /> {#if Object.entries(coursesBySemester).length > 0} - + {/if} @@ -188,12 +182,8 @@ {/if} - - - - - - {:catch error} + + {:catch error} {/await} diff --git a/src/lib/components/grades/statsCard.svelte b/src/lib/components/grades/statsCard.svelte index 665df18d..2b975ce1 100644 --- a/src/lib/components/grades/statsCard.svelte +++ b/src/lib/components/grades/statsCard.svelte @@ -5,12 +5,13 @@ import * as allIonicIcons from 'ionicons/icons'; import Chip from '$components/shared/Chips.svelte'; import { t } from '$lib/i18n'; + import type { course } from '$lib/types/courseType'; - export let subjects; - export let passedSubjects; - export let searchQuery; - export let flip; - export let subjectsJSON: null | undefined; + export let subjects: number; + export let passedSubjects: number; + export let searchQuery: string; + export let flip: () => void; + export let subjectsJSON: course[]; interface Registration { id: number; @@ -20,7 +21,7 @@ interface AveragesResult { avg: number; weighted_avg: number; - grades: never[]; + grades: number[]; ects: number; } @@ -33,7 +34,7 @@ let chart: Chart<'line', any, any>; let chartElement: HTMLCanvasElement; - let gradesObject = { + let gradesObject: { average: number; weightedAverage: number; grades: number[]; ects: number } = { average: 0, weightedAverage: 0, grades: [], diff --git a/src/lib/components/shared/Chips.svelte b/src/lib/components/shared/Chips.svelte index 099f2ac4..2a183041 100644 --- a/src/lib/components/shared/Chips.svelte +++ b/src/lib/components/shared/Chips.svelte @@ -1,6 +1,6 @@ - +
@@ -121,6 +122,7 @@
+
- \ No newline at end of file diff --git a/src/routes/personalInfo/infoItem.svelte b/src/routes/personalInfo/infoItem.svelte deleted file mode 100644 index 531d29bd..00000000 --- a/src/routes/personalInfo/infoItem.svelte +++ /dev/null @@ -1,144 +0,0 @@ - - - - - {#if gender === 'Άντρας'} - man - {:else} - woman - {/if} - {givenName} {familyName} - - {aem} - - - - - - {#if departmentName} - - - - {departmentName} - - {/if} - - {#if username} - - - - {username} - - {/if} - - {#if apm} - - - - {apm} - - {/if} - - {#if birthDate} - - - - {birthDate} - - {/if} - - {#if email} - - - - {email} - - {/if} - - {#if gender} - - - - {gender} - - {/if} - - {#if semester} - - - - {semester} - - {/if} - - {#if study_level} - - - - {study_level} - - {/if} - - - diff --git a/src/routes/personalInfo/personalInfo.svelte b/src/routes/personalInfo/personalInfo.svelte index 05d6e4f4..777af421 100644 --- a/src/routes/personalInfo/personalInfo.svelte +++ b/src/routes/personalInfo/personalInfo.svelte @@ -1,29 +1,41 @@ @@ -56,23 +94,90 @@ {#await getPersonalInfo()} {:then} - + + + {#if gender === 'Άντρας'} + man + {:else} + woman + {/if} + {givenName} {familyName} + + {aem} + + + + + + {#if departmentName} + + + + {departmentName} + + {/if} + + {#if username} + + + + {username} + + {/if} + + {#if apm} + + + + {apm} + + {/if} + + {#if birthDate} + + + + {birthDate} + + {/if} + + {#if email} + + + + {email} + + {/if} + + {#if gender} + + + + {gender} + + {/if} + + {#if semester} + + + + {semester} + + {/if} + + {#if study_level} + + + + {study_level} + + {/if} + {:catch error} {/await} - + @@ -81,4 +186,19 @@ --padding-end: 0.6rem; --padding-start: 0.6rem; } + + .info { + display: flex; + flex-direction: column; + align-items: center; + } + + ion-icon { + color: var(--app-color-icons); + } + + ion-card-subtitle { + font-size: 1.2rem; + padding-left: 5px; + } diff --git a/src/routes/personalInfo/settings.svelte b/src/routes/personalInfo/settings.svelte index b27334c2..70496ee4 100644 --- a/src/routes/personalInfo/settings.svelte +++ b/src/routes/personalInfo/settings.svelte @@ -18,11 +18,8 @@ import About from './about.svelte'; import Faq from './faq.svelte'; import { darkMode } from '$lib/globalFunctions/darkMode'; + import { logOut } from '$lib/globalFunctions/logOut'; - /** - * @type {any} - */ - export let logOut; let languageModalOpen = false; onMount(() => {