diff --git a/app/controllers/grades_controller.ts b/app/controllers/grades_controller.ts index b0c4088..a95cc9e 100644 --- a/app/controllers/grades_controller.ts +++ b/app/controllers/grades_controller.ts @@ -3,7 +3,7 @@ import { inject } from '@adonisjs/core' import type { HttpContext } from '@adonisjs/core/http' import { DateTime } from 'luxon' -const PERIODS = ['MONTH', 'SEMESTER', 'YEAR'] +const PERIODS = ['MONTH', 'TRIMESTER', 'YEAR'] @inject() export default class GradesController { @@ -37,5 +37,22 @@ export default class GradesController { return this.gradeService.getPeriodGrade(userId, startDate, months) } - // TODO: Radar chart for subjects + // GET /averages + async averages({ auth, request, response }: HttpContext) { + const period = request.input('period', PERIODS[0]).toUpperCase() + if (!PERIODS.includes(period)) { + return response.badRequest({ + message: `Invalid period. Allowed values are: ${PERIODS.join(', ')}`, + }) + } + + const userId = auth.user!.id + if (period === PERIODS[0]) { + const startDate = DateTime.now().minus({ month: 1 }) + return this.gradeService.getSubjectsAverages(userId, startDate, 1) + } + const months = period === PERIODS[1] ? 3 : 12 + const startDate = DateTime.now().minus({ months }) + return this.gradeService.getSubjectsAverages(userId, startDate, months) + } } diff --git a/app/services/grade_service.ts b/app/services/grade_service.ts index 84149e3..09b0b21 100644 --- a/app/services/grade_service.ts +++ b/app/services/grade_service.ts @@ -3,14 +3,16 @@ import { DateTime } from 'luxon' export class GradeService { private calculateAverage(colles: Colle[]) { - const total = colles.reduce((sum, colle) => sum + colle.grade, 0) - return parseFloat((total / colles.length).toFixed(2)) + const total = colles + .map((colle) => parseFloat(colle.grade?.toString())) + .filter(Boolean) + .reduce((sum, grade) => sum + grade, 0) + return (total / colles.length).toFixed(2) } private calculateSubjectAverage(colles: Colle[], subject: string) { - const subjectColles = colles.filter((colle) => colle.subject.name === subject) - const total = subjectColles.reduce((sum, colle) => sum + colle.grade, 0) - return parseFloat((total / subjectColles.length).toFixed(2)) + const subjectColles = colles.filter((colle) => colle.subject.name === subject && colle.grade) + return this.calculateAverage(subjectColles) } private getSubjects(colles: Colle[]) { @@ -21,7 +23,22 @@ export class GradeService { return colles.filter((colle) => colle.date >= startDate && colle.date < endDate) } - private getColles(userId: number, startDate: DateTime, months: number = 0) { + public async getSubjectsAverages(userId: number, startDate: DateTime, months: number = 0) { + const colles = await this.getColles(userId, startDate, months) + const subjects = this.getSubjects(colles) + const subjectAverages: SubjectPerformance[] = [] + for (const subject of subjects) { + const average = this.calculateSubjectAverage(colles, subject) + subjectAverages.push({ subject, average }) + } + const globalAverage = this.calculateAverage(colles) + return { + globalAverage, + subjectAverages, + } + } + + public getColles(userId: number, startDate: DateTime, months: number = 0) { const endDate = startDate.plus({ months }) return Colle.query() .where('studentId', userId) @@ -43,7 +60,7 @@ export class GradeService { const colles = await this.getColles(userId, startDate, 1) const subjects = this.getSubjects(colles) - const results: PeriodResult[] = [] + const results: any = [] let periodStartDate = startDate for (let week = 1; week <= 4; week++) { @@ -77,14 +94,14 @@ export class GradeService { const colles = await this.getColles(userId, startDate, months) const subjects = this.getSubjects(colles) - const results: PeriodResult[] = [] + const results: any = [] let periodStartDate = startDate let index = 1 while (periodStartDate < startDate.plus({ months })) { const periodEndDate = periodStartDate.endOf('month') - const periodColles = this.getPeriodColles(colles, periodStartDate, periodEndDate) + const periodColles = this.getPeriodColles(colles, startDate, periodEndDate) const periodAverage = this.calculateAverage(periodColles) const subjectAverages = await this.getSubjectAverages( @@ -121,14 +138,17 @@ export class GradeService { subjects: string[], periodColles: Colle[], allColles: Colle[], - previousResults: PeriodResult[], + previousResults: Record[], unitIndex: number, userId: number, periodStart: DateTime ) { const results = await Promise.all( subjects.map(async (subject) => { - if (periodColles.length > 0) { + const subjectColles = periodColles.filter( + (colle) => colle.subject.name === subject && colle.grade + ) + if (subjectColles.length > 0) { return { subject, average: this.calculateSubjectAverage(periodColles, subject), @@ -137,11 +157,9 @@ export class GradeService { // Try to use the previous unit's average if (unitIndex > 1) { - const prev = previousResults[unitIndex - 2].subjectAverages?.find( - (s) => s.subject === subject - ) + const prev = previousResults[unitIndex - 2]?.[subject] if (prev) { - return { subject, average: prev.average } + return { subject, average: prev } } } @@ -163,11 +181,5 @@ export class GradeService { interface SubjectPerformance { subject: string - average: number -} - -interface PeriodResult { - period: string - average: number - subjectAverages: SubjectPerformance[] + average: string } diff --git a/start/routes.ts b/start/routes.ts index d63898d..abfc8b2 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -62,6 +62,7 @@ router const GradesController = () => import('#controllers/grades_controller') router.get('/grades', [GradesController, 'index']).use(middleware.auth()) +router.get('/averages', [GradesController, 'averages']).use(middleware.auth()) const InternalsController = () => import('#controllers/internals_controller') router