import { getGraduationDb, DatabaseEntry } from "./database-ENV.ts"; import type { Student } from "./student-common.ts"; import NeulingPng from "../assets/Neuling.png"; import EntdeckerPng from "../assets/Entdecker.png"; import NavigatorPng from "../assets/Navigator.png"; import PioneerPng from "../assets/Pioneer.png"; const LEVEL_NAMES = ["Neuling", "Entdecker", "Navigator", "Pionieer"]; const LEVEL_IMAGES = [ new URL(NeulingPng), new URL(EntdeckerPng), new URL(NavigatorPng), new URL(PioneerPng), ]; class GraduationChange { date: Date; studentId: number; change: string; reason: string; coach: string; context: any; constructor( date: Date, studentId: number, change: string, reason: string, coach: string, context?: any, ) { this.date = date; this.studentId = studentId; this.change = change; this.reason = reason; this.coach = coach; this.context = context || {}; } dbFields() { return { studentId: this.studentId, change: this.change, reason: this.reason, context: this.context, }; } static fromDBEntry(e: DatabaseEntry) { const { date, coach, json } = e; const change = JSON.parse(json); return new GraduationChange( new Date(date), change.change, change.student, change.reason, coach, change.context, ); } static newLevelChange(level: number, reason?: string, coach?: string) { const ctx = { level: level }; return new GraduationChange(new Date(), -1, "LevelChange", reason || "", coach || "", ctx); } static newGreenPointChange(mandatory: boolean, reason?: string, coach?: string) { const ctx = { mandatory: mandatory }; return new GraduationChange(new Date(), -1, "Grün", reason || "", coach || "", ctx); } static newOrangePointChange(mandatory: boolean, reason?: string, coach?: string) { const ctx = { mandatory: mandatory }; return new GraduationChange(new Date(), -1, "Orange", reason || "", coach || "", ctx); } static newRedPointChange(mandatory: boolean, reason?: string, coach?: string) { const ctx = { mandatory: mandatory }; return new GraduationChange(new Date(), -1, "Rot", reason || "", coach || "", ctx); } } class Graduation { student: Student; green: number; orange: number; red: number; mandatory: number; level: number; changes: Array; constructor( student: Student, green: number, orange: number, red: number, mandatory: number, level: number, changes: Array, ) { this.student = student; this.green = green; this.orange = orange; this.red = red; this.level = level; this.mandatory = mandatory; this.changes = changes; student.graduation = this; } static from(student: Student, changes: Array) { let green = 0; let orange = 0; let red = 0; let mandatory = 0; let level = 1; // The parsing logic assumes that changes are ordered chronologically changes.sort((a, b) => a.date.valueOf() - b.date.valueOf()); for (const change of changes) { switch (change.change) { case "Grün": green++; break; case "Orange": orange++; break; case "Rot": red++; break; case "LevelChange": level = Number(change.context.level); break; default: throw new Error(`Unexpected change: ${change}`); } if (change.context.mandatory) { mandatory++; } } return new Graduation(student, green, orange, red, mandatory, level, changes); } addChange(change: GraduationChange) { change.studentId = this.student.id; // TODO(muhq): Implement incremental addition let changes = this.changes; changes.push(change); // This updates the student.graduation reference as well Graduation.from(this.student, changes); } /** * Return the URI of the icon representing the graduation level. */ getIcon() { return LEVEL_IMAGES[this.level - 1]; } /** * Return the name of the current graduation level. */ getLevelName() { return LEVEL_NAMES[this.level - 1]; } /** * Return the combined value of all points. */ getNettoPoints(): number { return this.green - this.orange - this.red; } } async function submitGraduationChange(graduation: Graduation, change: GraduationChange) { graduation.addChange(change); const db = await getGraduationDb(); return db.saveEntry(JSON.stringify(change.dbFields())); } export { LEVEL_NAMES, LEVEL_IMAGES, GraduationChange, Graduation, submitGraduationChange };