import { loadFromStudentDatabase, addEntryToStudentDatabase } from "./database.js" const LEVEL_NAMES = ["Neuling", "Entdecker", "Pionieer"]; class GraduationChange { constructor(date, change, reason, coach, context) { this.date = date; this.change = change; this.reason = reason; this.coach = coach; this.context = context; } isPublic() { return [ "Grün", "Orange", "Rot", "ObservationStart", "ObservationEnd", "LevelChange" ].includes(this.change); } static newGreenPointChange(reason, coach) { return new GraduationChange(new Date(), "Grün", reason, coach, ""); } static newOrangePointChange(reason, coach) { return new GraduationChange(new Date(), "Orange", reason, coach, ""); } static newRedPointChange(reason, coach) { return new GraduationChange(new Date(), "Rot", reason, coach, ""); } } class Graduation { constructor(student, green, orange, red, level, stickers, observation, changes) { this.student = student; this.green = green; this.orange = orange; this.red = red; this.level = level; this.stickers = stickers; this.observation = observation; this.changes = changes; student.graduation = this; } static from(student, changes) { let green = 0; let orange = 0; let red = 0; let level = 1; let observationPeriod = null; let pastObservations = []; let stickers = []; for (const change of changes) { switch (change.change) { case "Grün": green++; break; case "Orange": orange++; break; case "Rot": red++; break; case "ObservationStart": observationPeriod = new ObservationPeriod(change.date, null, []); break; case "ObservationEnd": observationPeriod.end = change.date; pastObservations.push(observationPeriod); observationPeriod = null; break; case "Observation": const observation = Observation.fromContext(change.context); if (observationPeriod) { observationPeriod.addObservation(observation); } else { alert(`No active observation period`); } break; default: alert(`Unexpected change: ${change}`); } } return new Graduation(student, green, orange, red, level, stickers, observationPeriod, changes); } addChange(change) { // 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); } /** * Request observation */ async requestObservation() { await addEntryToStudentDatabase(this.student, "submit", {change: "ObservationRequest"}); } /** * Return if the student is in observation. */ isObserved() { return Boolean(this.observation); } /** * Return the URI of the icon representing the graduation level. */ getIcon() { return ""; } /** * Return the name of the current graduation level. * @return {String} The name of the current level. */ getLevelName() { return LEVEL_NAMES[this.level - 1]; } } class ObservationPeriod { constructor(start, end, observations) { this.start = start; this.end = end; this.observations = observations; } ended() { return Boolean(this.end); } ready() { // TODO(muhq): add time contraint return this.observations > 10; } getObservationsSums() { let sums = Array(OBSERVATION_TYPES.length).fill({"yes":0, "no":0}); for (const observation of this.observations) { for (let i = 0; i < sums.length; i++) { if (observation.status[i]) sums[i].yes++; else sums[i].no++; } } return sums; } addObservation(observation) { this.observations.push(observation); } } const OBSERVATION_TYPES = [ "Arbeitet konzentriert an Aufgaben", "Arbeitet zunehmend selbstständig", "Führt das Logbuch zuverlässig", "Bringt Material mit", "Hält Regeln ein", "Geht verantwortungsvoll mit Materialien und LernRaum um", "Nimmt Rückmeldungen an und setzt sie um", ]; class Observation { constructor(date, status) { console.assert(status.length != OBSERVATION_TYPES.length, "invalid observation status"); this.date = date; this.status = status; } } async function fetchGraduationChanges(student) { const data = await loadFromStudentDatabase(student, "shadow"); let changes = []; for (const e of data) { const gradChange = GraduationChange.fromDBEntry(e); changes.push(gradChange); } return changes; } async function fetchGraduation(student) { const changes = await fetchGraduationChanges(student); return Graduation.from(student, changes); } async function submitGraduationChange(student, change) { student.graduation.addChange(change); // Submit changes concurrently let promises = []; if (change.isPublic()) { promises.push( // TODO(muhq): strip non public fields from changes addEntryToStudentDatabase(student, "public", JSON.stringify(change)) ); } promises.push( addEntryToStudentDatabase(student, "shadow", JSON.stringify(change)) ); await Promise.all(promises); } async function submitObservation(student, observation) { student.graduation.addObservation(observation); await addEntryToStudentDatabase(student, "shadow", JSON.stringify(observation)); } export { LEVEL_NAMES, GraduationChange, Graduation, fetchGraduation, fetchGraduationChanges, submitGraduationChange, submitObservation, OBSERVATION_TYPES, Observation, ObservationPeriod, };