diff --git a/package-lock.json b/package-lock.json index 320349527..df695ab69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,7 +68,7 @@ "lottie-react-native": "^6.7.0", "lucide-react-native": "^0.378.0", "openid-client": "^5.7.0", - "pawdirecte": "^1.6.0", + "pawdirecte": "^1.7.0", "pawnilim": "^0.2.0", "pawnote": "^1.2.2", "pawrd": "^0.6.1", @@ -13635,9 +13635,10 @@ } }, "node_modules/pawdirecte": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/pawdirecte/-/pawdirecte-1.6.0.tgz", - "integrity": "sha512-0ZkMwfdpKQuPPO1Uvs8N+mBNY8q01kCeTjWFmlamNXl2DPqHWA6ISDqwt1iXKXdeUM8MZcNqpiLnD+CDapNsYQ==", + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/pawdirecte/-/pawdirecte-1.7.0.tgz", + "integrity": "sha512-hGBJ7lb+XNAh/rfi9PORhB3lV1S08ylnJgf5gYwpHYPvmguk4rni4khg3rODN6+PsGWWh7Nr49FfZsTdyW1NLg==", + "license": "GPL-3.0-or-later", "dependencies": { "@literate.ink/utilities": "1.0.0-11713907881.1", "js-base64": "^3.7.7" diff --git a/package.json b/package.json index 7901b48b3..1980e2421 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "lottie-react-native": "^6.7.0", "lucide-react-native": "^0.378.0", "openid-client": "^5.7.0", - "pawdirecte": "^1.6.0", + "pawdirecte": "^1.7.0", "pawnilim": "^0.2.0", "pawnote": "^1.2.2", "pawrd": "^0.6.1", diff --git a/src/services/ecoledirecte/attendance.ts b/src/services/ecoledirecte/attendance.ts index f5409e13e..dac596c97 100644 --- a/src/services/ecoledirecte/attendance.ts +++ b/src/services/ecoledirecte/attendance.ts @@ -2,13 +2,13 @@ import ecoledirecte, {AttendanceItem, AttendanceItemKind} from "pawdirecte"; import type { EcoleDirecteAccount } from "@/stores/account/types"; import { ErrorServiceUnauthenticated } from "../shared/errors"; import type { Attendance } from "../shared/Attendance"; -import {dateStringAsTimeInterval, getDuration} from "@/services/ecoledirecte/time-interval"; +import {dateStringAsTimeInterval, getDuration, getDurationInHours} from "@/services/ecoledirecte/time-interval"; import {Punishment} from "@/services/shared/Punishment"; import {Absence} from "@/services/shared/Absence"; import {Delay} from "@/services/shared/Delay"; const decodeDelay = (item: AttendanceItem): Delay => { - const timeInterval = dateStringAsTimeInterval(item.displayDate); + const timeInterval = dateStringAsTimeInterval(item.displayDate); const duration = (timeInterval?.end && timeInterval.start) ? getDuration(timeInterval).getTime() / (60 * 1000): 0; return { id: item.id.toString(), @@ -22,7 +22,7 @@ const decodeDelay = (item: AttendanceItem): Delay => { const decodeAbsence = (item: AttendanceItem): Absence => { const timeInterval = dateStringAsTimeInterval(item.displayDate); - const duration = (timeInterval?.end && timeInterval.start) ? getDuration(timeInterval): new Date(); + const duration = (timeInterval?.end && timeInterval.start) ? getDurationInHours(timeInterval) : ""; const fromTimestamp = timeInterval?.start ? new Date(timeInterval.start).getTime(): 0; const toTimestamp = timeInterval?.end ? new Date(timeInterval.end).getTime(): 0; return { @@ -30,7 +30,7 @@ const decodeAbsence = (item: AttendanceItem): Absence => { fromTimestamp, toTimestamp, justified: item.justified, - hours: duration.getHours() + "h" + duration.getMinutes(), + hours: duration, administrativelyFixed: item.justified, reasons: item.reason, }; diff --git a/src/services/ecoledirecte/chats.ts b/src/services/ecoledirecte/chats.ts index a91e4a02a..3f1789b71 100644 --- a/src/services/ecoledirecte/chats.ts +++ b/src/services/ecoledirecte/chats.ts @@ -18,6 +18,10 @@ export const getChats = async (account: EcoleDirecteAccount): Promise => })); }; +const cleanMessage = (message: string) => { + return message.replace(/>\s+/g, '>').replace(/ /g, ' '); +} + export const getChatMessages = async (account: EcoleDirecteAccount, chat: Chat): Promise => { if (!account.instance) throw new ErrorServiceUnauthenticated("ecoledirecte"); @@ -26,7 +30,7 @@ export const getChatMessages = async (account: EcoleDirecteAccount, chat: Chat): return { id: message.id.toString(), - content: message.content, + content: cleanMessage(message.content), author: message.sender, date: message.date, subject: chat.subject, diff --git a/src/services/ecoledirecte/grades.ts b/src/services/ecoledirecte/grades.ts index 14538e4b0..a1b8dfd6a 100644 --- a/src/services/ecoledirecte/grades.ts +++ b/src/services/ecoledirecte/grades.ts @@ -22,39 +22,26 @@ const decodePeriod = (p: PawdirectePeriod): Period => { }; }; -const decodeGradeKind = (kind: GradeKind): GradeInformation | undefined => { - switch (kind) { - case GradeKind.Error: +const decodeGradeValue = ( + value: ecoledirecte.GradeValue | undefined, +): GradeValue => { + if (typeof value === "undefined") + return { value: null, disabled: true }; + + switch (value.kind) { case GradeKind.Grade: - return undefined; + return { value: value.points ?? 0, disabled: false }; case GradeKind.Absent: - return GradeInformation.Absent; + return { value: value.points ?? 0, disabled: true, information: GradeInformation.Absent }; case GradeKind.Exempted: - return GradeInformation.Exempted; + return { value: value.points ?? 0, disabled: true, information: GradeInformation.Exempted }; case GradeKind.NotGraded: - return GradeInformation.NotGraded; + return { value: value.points ?? 0, disabled: true, information: GradeInformation.NotGraded }; default: - return undefined; + return { value: value.points ?? 0, disabled: true }; } }; -const decodeGradeValue = ( - value: ecoledirecte.GradeValue | undefined, -): GradeValue => { - if (!value) - return { - disabled: true, - information: GradeInformation.NotGraded, - value: 0, - }; - - return { - disabled: value.kind === GradeKind.Error, - information: decodeGradeKind(value.kind), - value: value?.points, - }; -}; - const getGradeValue = (value: number | string | undefined): GradeValue => { return { disabled: false, diff --git a/src/services/ecoledirecte/homework.ts b/src/services/ecoledirecte/homework.ts index abc69e8e1..2ff1a98b4 100644 --- a/src/services/ecoledirecte/homework.ts +++ b/src/services/ecoledirecte/homework.ts @@ -7,6 +7,10 @@ import { log } from "@/utils/logger/logger"; import { AttachmentType } from "../shared/Attachment"; import { formatDate } from "@/services/ecoledirecte/format-date"; +const cleanContent = (message: string) => { + return message.replace(/>\s+/g, '>').replace(/ /g, ' '); +} + export const getHomeworkForWeek = async ( account: EcoleDirecteAccount, weekNumber: number, @@ -36,7 +40,7 @@ export const getHomeworkForWeek = async ( name: att.name, })), color: "#000000", // TODO - content: homework.content, + content: cleanContent(homework.content), done: homework.done, due: date.getTime(), id: homework.id.toString(), diff --git a/src/services/ecoledirecte/time-interval.ts b/src/services/ecoledirecte/time-interval.ts index 40ca30e1c..2c008610b 100644 --- a/src/services/ecoledirecte/time-interval.ts +++ b/src/services/ecoledirecte/time-interval.ts @@ -6,49 +6,76 @@ export type Timeinterval = { const months = ["janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre"]; /** - * @param str "A string containing a date formatted as "mercredi 21 février 2024 de 00:00", will return the date for the specified day and hour" - */ -export function dateAsISO860 (str: string): string { +* @param str "A string containing a date formatted as "mercredi 21 février 2024 de 08:10", will return the date for the specified day and hour" +*/ +export function dateAsISO860(str: string): string { const parts = str.split(" "); - const hour = parts[5].split(":"); - return (new Date(Number(parts[3]), months.indexOf(parts[2]), Number(parts[1]), Number(hour[0]), Number(hour[1]))).toISOString(); + const timeIndex = parts.findIndex(part => part.includes(":")); + const hour = parts[timeIndex].split(":"); + const monthIndex = parts.findIndex(part => months.includes(part)); + + return (new Date( + Number(parts[monthIndex + 1]), + months.indexOf(parts[monthIndex]), + Number(parts[monthIndex - 1]), + Number(hour[0]), + Number(hour[1]) + )).toISOString(); } -export function dateStringAsTimeInterval ( +export function dateStringAsTimeInterval( str: string, ): Timeinterval | undefined { if (str.includes("du")) { - /** - * @example - * str is equal to "du mercredi 21 février 2024 au jeudi 22 février 2024" - */ - const parts = str.split("au"); - const start = dateAsISO860(parts[0].replace("du", "").trim()); - const end = dateAsISO860(parts[1].trim()); - return { start: start, end: end } as Timeinterval; + /** + * @example + * str is equal to "du mercredi 21 février 2024 au jeudi 22 février 2024" + * or "du mercredi 27 novembre 2024 à 08:10 au vendredi 06 décembre 2024 à 08:10" + */ + const [startPart, endPart] = str.split("au").map(part => part.trim()); + let start = startPart.replace("du", "").trim(); + let end = endPart.trim(); + + if (!start.includes(":")) { + start += " de 00:00"; + } else { + start = start.replace(" à ", " de "); + } + + if (!end.includes(":")) { + end += " de 23:59"; + } else { + end = end.replace(" à ", " de "); + } + + return { + start: dateAsISO860(start), + end: dateAsISO860(end) + } as Timeinterval; } + if (str.includes("le")) { - /** - * @example - * str is equal to "le mercredi 21 février 2024 de 08:55 à 09:45" - * or "le mercredi 21 février 2024" - */ - const parts = str.split("à"); - - let startDate: string; - let endDate: string; - - // C'est une journée complète ("le mercredi 21 février 2024") - if (!str.includes(":")) { - startDate = `${parts[0].replace("le", "").trim()} de 00:00`; - endDate = `${parts[0].split("de")[0].replace("le", "").trim()} de 23:59`; - } else { - startDate = parts[0].replace("le", "").trim(); - endDate = `${parts[0].split("de")[0].replace("le", "").trim()} de ${parts[1].trim()}`; - } - const start = dateAsISO860(startDate); - const end = dateAsISO860(endDate); - return { start: start, end: end } as Timeinterval; + /** + * @example + * str is equal to "le mercredi 21 février 2024 de 08:10 à 16:10" + * or "le jeudi 22 février 2024" + */ + const parts = str.split("à"); + let startDate: string; + let endDate: string; + + // It's a full day ("le mercredi 21 février 2024") + if (!str.includes(":")) { + startDate = `${parts[0].replace("le", "").trim()} de 00:00`; + endDate = `${parts[0].split("de")[0].replace("le", "").trim()} de 23:59`; + } else { + startDate = parts[0].replace("le", "").trim(); + endDate = `${parts[0].split("de")[0].replace("le", "").trim()} de ${parts[1].trim()}`; + } + + const start = dateAsISO860(startDate); + const end = dateAsISO860(endDate); + return { start: start, end: end } as Timeinterval; } return undefined; } @@ -60,3 +87,19 @@ export function dateStringAsTimeInterval ( export const getDuration = (interval: Timeinterval): Date => { return new Date(new Date(interval.end).getTime() - new Date(interval.start).getTime()); }; + +/** +* Get the duration of interval in hours. +* @param interval +*/ +/** + * Get the duration of interval in hours. + * @param interval + */ +export const getDurationInHours = (interval: Timeinterval): string => { + const diff = new Date(interval.end).getTime() - new Date(interval.start).getTime(); + const hours = Math.floor(diff / (1000 * 60 * 60)); + const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)); + + return `${hours}h${minutes.toString().padStart(2, '0')}`; +}; \ No newline at end of file diff --git a/src/services/ecoledirecte/timetable.ts b/src/services/ecoledirecte/timetable.ts index 65b219627..b3a6ca7b0 100644 --- a/src/services/ecoledirecte/timetable.ts +++ b/src/services/ecoledirecte/timetable.ts @@ -18,7 +18,7 @@ const decodeTimetableClass = (c: ecoledirecte.TimetableItem): TimetableClass => subject: c.subjectName, title: c.subjectName, room: c.room || void 0, - teacher: c.teacher ?? void 0, + teacher: c.teacher || void 0, // TODO: add more states status: c.updated ? TimetableClassStatus.MODIFIED : c.cancelled ? TimetableClassStatus.CANCELED : void 0, statusText: c.updated ? TimetableClassStatus.MODIFIED : c.cancelled ? TimetableClassStatus.CANCELED : void 0, @@ -30,6 +30,7 @@ const decodeTimetableClass = (c: ecoledirecte.TimetableItem): TimetableClass => subject: c.subjectName, id: c.id, title: c.subjectName ?? "Sans titre", + teacher: c.teacher || void 0, room: c.room || void 0, ...base }; @@ -39,6 +40,7 @@ const decodeTimetableClass = (c: ecoledirecte.TimetableItem): TimetableClass => subject: c.subjectName, id: c.id, title: c.subjectName ?? "Sans titre", + teacher: c.teacher || void 0, room: c.room || void 0, ...base }; @@ -48,6 +50,7 @@ const decodeTimetableClass = (c: ecoledirecte.TimetableItem): TimetableClass => subject: c.subjectName, id: c.id, title: "Congés", + teacher: c.teacher || void 0, room: void 0, ...base }; @@ -57,6 +60,7 @@ const decodeTimetableClass = (c: ecoledirecte.TimetableItem): TimetableClass => subject: "", id: c.id, title: "Sanction", + teacher: c.teacher || void 0, room: "PERMANENCE", ...base }; diff --git a/src/views/account/Grades/Grades.tsx b/src/views/account/Grades/Grades.tsx index 5e2eb5187..06d6537c9 100644 --- a/src/views/account/Grades/Grades.tsx +++ b/src/views/account/Grades/Grades.tsx @@ -118,9 +118,11 @@ const Grades: Screen<"Grades"> = ({ route, navigation }) => { }); } - gradesPerSubject.sort((a, b) => - a.average.subjectName.localeCompare(b.average.subjectName) - ); + if (account.service !== AccountService.EcoleDirecte) { + gradesPerSubject.sort((a, b) => + a.average.subjectName.localeCompare(b.average.subjectName) + ); + } setGradesPerSubject(gradesPerSubject); }, 1); }, [selectedPeriod, averages, grades]); diff --git a/src/views/account/Grades/Subject/SubjectList.tsx b/src/views/account/Grades/Subject/SubjectList.tsx index f727cfc5c..d05981f90 100644 --- a/src/views/account/Grades/Subject/SubjectList.tsx +++ b/src/views/account/Grades/Subject/SubjectList.tsx @@ -135,9 +135,9 @@ const SubjectGradeItem: React.FC = ({ subject, grade, ind fontFamily: "medium", }} > - {typeof grade.student.value === "number" + {grade.student.disabled === true ? "N. not" : (typeof grade.student.value === "number" ? grade.student.value.toFixed(2) - : "N. not"} + : "N. not")} - {startHours > 11 && + {startHours >= 11 && startHours < 14 ? ( ) : ( @@ -203,8 +203,8 @@ const SeparatorCourse: React.FC<{ color: colors.text, }} > - {(startHours > 11 && - startHours < 14) + {startHours >= 11 && + startHours < 14 ? "Pause méridienne" : "Pas de cours"}