feat: add radar chart
This commit is contained in:
parent
fb00495840
commit
7093b344ed
3 changed files with 54 additions and 24 deletions
|
|
@ -3,7 +3,7 @@ import { inject } from '@adonisjs/core'
|
||||||
import type { HttpContext } from '@adonisjs/core/http'
|
import type { HttpContext } from '@adonisjs/core/http'
|
||||||
import { DateTime } from 'luxon'
|
import { DateTime } from 'luxon'
|
||||||
|
|
||||||
const PERIODS = ['MONTH', 'SEMESTER', 'YEAR']
|
const PERIODS = ['MONTH', 'TRIMESTER', 'YEAR']
|
||||||
|
|
||||||
@inject()
|
@inject()
|
||||||
export default class GradesController {
|
export default class GradesController {
|
||||||
|
|
@ -37,5 +37,22 @@ export default class GradesController {
|
||||||
return this.gradeService.getPeriodGrade(userId, startDate, months)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,14 +3,16 @@ import { DateTime } from 'luxon'
|
||||||
|
|
||||||
export class GradeService {
|
export class GradeService {
|
||||||
private calculateAverage(colles: Colle[]) {
|
private calculateAverage(colles: Colle[]) {
|
||||||
const total = colles.reduce((sum, colle) => sum + colle.grade, 0)
|
const total = colles
|
||||||
return parseFloat((total / colles.length).toFixed(2))
|
.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) {
|
private calculateSubjectAverage(colles: Colle[], subject: string) {
|
||||||
const subjectColles = colles.filter((colle) => colle.subject.name === subject)
|
const subjectColles = colles.filter((colle) => colle.subject.name === subject && colle.grade)
|
||||||
const total = subjectColles.reduce((sum, colle) => sum + colle.grade, 0)
|
return this.calculateAverage(subjectColles)
|
||||||
return parseFloat((total / subjectColles.length).toFixed(2))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private getSubjects(colles: Colle[]) {
|
private getSubjects(colles: Colle[]) {
|
||||||
|
|
@ -21,7 +23,22 @@ export class GradeService {
|
||||||
return colles.filter((colle) => colle.date >= startDate && colle.date < endDate)
|
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 })
|
const endDate = startDate.plus({ months })
|
||||||
return Colle.query()
|
return Colle.query()
|
||||||
.where('studentId', userId)
|
.where('studentId', userId)
|
||||||
|
|
@ -43,7 +60,7 @@ export class GradeService {
|
||||||
const colles = await this.getColles(userId, startDate, 1)
|
const colles = await this.getColles(userId, startDate, 1)
|
||||||
const subjects = this.getSubjects(colles)
|
const subjects = this.getSubjects(colles)
|
||||||
|
|
||||||
const results: PeriodResult[] = []
|
const results: any = []
|
||||||
let periodStartDate = startDate
|
let periodStartDate = startDate
|
||||||
|
|
||||||
for (let week = 1; week <= 4; week++) {
|
for (let week = 1; week <= 4; week++) {
|
||||||
|
|
@ -77,14 +94,14 @@ export class GradeService {
|
||||||
const colles = await this.getColles(userId, startDate, months)
|
const colles = await this.getColles(userId, startDate, months)
|
||||||
const subjects = this.getSubjects(colles)
|
const subjects = this.getSubjects(colles)
|
||||||
|
|
||||||
const results: PeriodResult[] = []
|
const results: any = []
|
||||||
let periodStartDate = startDate
|
let periodStartDate = startDate
|
||||||
|
|
||||||
let index = 1
|
let index = 1
|
||||||
|
|
||||||
while (periodStartDate < startDate.plus({ months })) {
|
while (periodStartDate < startDate.plus({ months })) {
|
||||||
const periodEndDate = periodStartDate.endOf('month')
|
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 periodAverage = this.calculateAverage(periodColles)
|
||||||
const subjectAverages = await this.getSubjectAverages(
|
const subjectAverages = await this.getSubjectAverages(
|
||||||
|
|
@ -121,14 +138,17 @@ export class GradeService {
|
||||||
subjects: string[],
|
subjects: string[],
|
||||||
periodColles: Colle[],
|
periodColles: Colle[],
|
||||||
allColles: Colle[],
|
allColles: Colle[],
|
||||||
previousResults: PeriodResult[],
|
previousResults: Record<string, number>[],
|
||||||
unitIndex: number,
|
unitIndex: number,
|
||||||
userId: number,
|
userId: number,
|
||||||
periodStart: DateTime
|
periodStart: DateTime
|
||||||
) {
|
) {
|
||||||
const results = await Promise.all(
|
const results = await Promise.all(
|
||||||
subjects.map(async (subject) => {
|
subjects.map(async (subject) => {
|
||||||
if (periodColles.length > 0) {
|
const subjectColles = periodColles.filter(
|
||||||
|
(colle) => colle.subject.name === subject && colle.grade
|
||||||
|
)
|
||||||
|
if (subjectColles.length > 0) {
|
||||||
return {
|
return {
|
||||||
subject,
|
subject,
|
||||||
average: this.calculateSubjectAverage(periodColles, subject),
|
average: this.calculateSubjectAverage(periodColles, subject),
|
||||||
|
|
@ -137,11 +157,9 @@ export class GradeService {
|
||||||
|
|
||||||
// Try to use the previous unit's average
|
// Try to use the previous unit's average
|
||||||
if (unitIndex > 1) {
|
if (unitIndex > 1) {
|
||||||
const prev = previousResults[unitIndex - 2].subjectAverages?.find(
|
const prev = previousResults[unitIndex - 2]?.[subject]
|
||||||
(s) => s.subject === subject
|
|
||||||
)
|
|
||||||
if (prev) {
|
if (prev) {
|
||||||
return { subject, average: prev.average }
|
return { subject, average: prev }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,11 +181,5 @@ export class GradeService {
|
||||||
|
|
||||||
interface SubjectPerformance {
|
interface SubjectPerformance {
|
||||||
subject: string
|
subject: string
|
||||||
average: number
|
average: string
|
||||||
}
|
|
||||||
|
|
||||||
interface PeriodResult {
|
|
||||||
period: string
|
|
||||||
average: number
|
|
||||||
subjectAverages: SubjectPerformance[]
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ router
|
||||||
|
|
||||||
const GradesController = () => import('#controllers/grades_controller')
|
const GradesController = () => import('#controllers/grades_controller')
|
||||||
router.get('/grades', [GradesController, 'index']).use(middleware.auth())
|
router.get('/grades', [GradesController, 'index']).use(middleware.auth())
|
||||||
|
router.get('/averages', [GradesController, 'averages']).use(middleware.auth())
|
||||||
|
|
||||||
const InternalsController = () => import('#controllers/internals_controller')
|
const InternalsController = () => import('#controllers/internals_controller')
|
||||||
router
|
router
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue