Skip to content
Snippets Groups Projects
Commit 8a889e30 authored by Thabo Bals's avatar Thabo Bals
Browse files

attendance arrays

parent 3236fb8b
No related branches found
No related tags found
1 merge request!101Ordered attendance
import fs from "node:fs/promises"; import fs from "node:fs/promises";
import { FinishedTranscriptMeta, Resolution } from "./parsing"; import { FinishedTranscriptMeta } from "./parsing";
import { Attendance, generateAttendanceHtmlWrapper } from "./rendering"; import { generateAttendanceHtmlWrapper } from "./rendering";
export class Attendance {
presents: number[] = [];
noshows: number[] = [];
noshow_excuseds: number[] = [];
get present(): number {
return this.presents.length;
}
get noshow(): number {
return this.noshows.length;
}
get noshow_excused(): number {
return this.noshow_excuseds.length;
}
sum(): number {
return this.present + this.noshow + this.noshow_excused;
}
union(other: Attendance) {
this.presents = this.presents.concat(other.presents).sort();
this.noshows = this.noshows.concat(other.noshows).sort();
this.noshow_excuseds = this.noshow_excuseds
.concat(other.noshow_excuseds)
.sort();
}
}
export async function generateAttendancePage( export async function generateAttendancePage(
outputDir: string, outputDir: string,
...@@ -49,25 +79,25 @@ function _generateAttendancePart( ...@@ -49,25 +79,25 @@ function _generateAttendancePart(
): Map<string, Attendance> { ): Map<string, Attendance> {
const attendanceMap = new Map<string, Attendance>(); const attendanceMap = new Map<string, Attendance>();
for (const { present, absent } of relevantTranscripts) { for (const { present, absent, number } of relevantTranscripts) {
present.forEach((name) => present.forEach((name) =>
_incrementAttendance(name, attendanceMap, true), _incrementAttendance(name, attendanceMap, true, number!),
); );
absent.forEach((name) => absent.forEach((name) =>
_incrementAttendance(name, attendanceMap, false), _incrementAttendance(name, attendanceMap, false, number!),
); );
} }
_mergeAttendance(attendanceMap); _mergeAttendance(attendanceMap, relevantTranscripts.length);
return attendanceMap; return attendanceMap;
} }
function _mergeAttendance(attendanceMap: Map<string, Attendance>) { function _mergeAttendance(
attendanceMap: Map<string, Attendance>,
maxAttendance: number,
) {
const names: string[] = [...attendanceMap.keys()]; const names: string[] = [...attendanceMap.keys()];
const maxAttendance: number = Math.max(
...[...attendanceMap.values()].map(_sumAttendance),
);
for (const shortName of names) { for (const shortName of names) {
if (shortName.includes(" ")) { if (shortName.includes(" ")) {
...@@ -83,16 +113,13 @@ function _mergeAttendance(attendanceMap: Map<string, Attendance>) { ...@@ -83,16 +113,13 @@ function _mergeAttendance(attendanceMap: Map<string, Attendance>) {
const longAttendance: Attendance = attendanceMap.get( const longAttendance: Attendance = attendanceMap.get(
nameMatches[0], nameMatches[0],
)!; )!;
longAttendance.present += shortAttendance.present; longAttendance.union(shortAttendance);
longAttendance.noshow += shortAttendance.noshow;
longAttendance.noshow_excused += shortAttendance.noshow_excused;
attendanceMap.delete(shortName); attendanceMap.delete(shortName);
} }
} }
let missingNames = [...attendanceMap.keys()].filter( let missingNames = [...attendanceMap.keys()].filter(
(name: string) => (name: string) => attendanceMap.get(name)!.sum() != maxAttendance,
_sumAttendance(attendanceMap.get(name)!) != maxAttendance,
); );
for (const missingName of missingNames) { for (const missingName of missingNames) {
const missingAttendance = attendanceMap.get(missingName); const missingAttendance = attendanceMap.get(missingName);
...@@ -112,15 +139,12 @@ function _mergeAttendance(attendanceMap: Map<string, Attendance>) { ...@@ -112,15 +139,12 @@ function _mergeAttendance(attendanceMap: Map<string, Attendance>) {
const otherName = potentialMatches.pop()!; const otherName = potentialMatches.pop()!;
const otherAttendance = attendanceMap.get(otherName)!; const otherAttendance = attendanceMap.get(otherName)!;
if ( if (
_sumAttendance(missingAttendance) missingAttendance.sum() + otherAttendance.sum()
+ _sumAttendance(otherAttendance)
> maxAttendance > maxAttendance
) { ) {
continue; continue;
} }
missingAttendance.present += otherAttendance.present; missingAttendance.union(otherAttendance);
missingAttendance.noshow += otherAttendance.noshow;
missingAttendance.noshow_excused += otherAttendance.noshow_excused;
attendanceMap.delete(otherName); attendanceMap.delete(otherName);
missingNames = missingNames.filter((e) => e != otherName); missingNames = missingNames.filter((e) => e != otherName);
} }
...@@ -131,30 +155,24 @@ function _incrementAttendance( ...@@ -131,30 +155,24 @@ function _incrementAttendance(
name: string, name: string,
attendanceMap: Map<string, Attendance>, attendanceMap: Map<string, Attendance>,
present: boolean, present: boolean,
transscriptNumber: number,
) { ) {
const cleanName = _cleanName(name); const cleanName = _cleanName(name);
const attendance: Attendance = attendanceMap.get(cleanName) ?? { const attendance: Attendance =
present: 0, attendanceMap.get(cleanName) ?? new Attendance();
noshow: 0,
noshow_excused: 0,
};
if (present) { if (present) {
attendance.present += 1; attendance.presents.push(transscriptNumber);
} else { } else {
if (_isExcused(name)) { if (_isExcused(name)) {
attendance.noshow_excused += 1; attendance.noshow_excuseds.push(transscriptNumber);
} else { } else {
attendance.noshow += 1; attendance.noshows.push(transscriptNumber);
} }
} }
attendanceMap.set(cleanName, attendance); attendanceMap.set(cleanName, attendance);
} }
function _sumAttendance(attendance: Attendance): number {
return attendance.present + attendance.noshow_excused + attendance.noshow;
}
function _isExcused(name: string): boolean { function _isExcused(name: string): boolean {
return name.search(/([(\[]).*?(([eE])(ntschuldigt)?).*?([)\]])/) !== -1; return name.search(/([(\[]).*?(([eE])(ntschuldigt)?).*?([)\]])/) !== -1;
} }
......
import { FinishedTranscriptMeta, Resolution, Todo } from "./parsing"; import { FinishedTranscriptMeta, Resolution, Todo } from "./parsing";
import { Attendance } from "./attendance";
export function renderContainerToAlert(context: String, title?: String) { export function renderContainerToAlert(context: String, title?: String) {
return function (tokens, idx) { return function (tokens, idx) {
...@@ -535,12 +536,6 @@ ${resolution.date} ${resolution.number}: beschlossen ...@@ -535,12 +536,6 @@ ${resolution.date} ${resolution.number}: beschlossen
return `<details><summary><small class="text-body-secondary fw-light">Hledger-Statement für die Buchhaltung</small></summary><pre><code id="reso-text-${resolution.number}">${hledgerText}</code></pre><button class="btn btn-outline-primary btn-sm" onclick="navigator.clipboard.writeText(document.getElementById(\'reso-text-${resolution.number}\').innerText)"><svg width="16" height="16" version="2.0"><use href="#clipboard-icon" /></svg> Hledger-Statement kopieren</button></details>`; return `<details><summary><small class="text-body-secondary fw-light">Hledger-Statement für die Buchhaltung</small></summary><pre><code id="reso-text-${resolution.number}">${hledgerText}</code></pre><button class="btn btn-outline-primary btn-sm" onclick="navigator.clipboard.writeText(document.getElementById(\'reso-text-${resolution.number}\').innerText)"><svg width="16" height="16" version="2.0"><use href="#clipboard-icon" /></svg> Hledger-Statement kopieren</button></details>`;
} }
export interface Attendance {
present: number;
noshow: number;
noshow_excused: number;
}
export function generateAttendanceHtmlWrapper( export function generateAttendanceHtmlWrapper(
attendanceParts: [ attendanceParts: [
Map<string, Attendance>, Map<string, Attendance>,
...@@ -689,7 +684,7 @@ export function generateAttendanceHtml( ...@@ -689,7 +684,7 @@ export function generateAttendanceHtml(
} }
function generateAttendanceRowHtml(name: string, data: Attendance): string { function generateAttendanceRowHtml(name: string, data: Attendance): string {
const sum = (data.present + data.noshow + data.noshow_excused) / 100; const sum = data.sum() / 100;
const bar = ` const bar = `
<div class="percentage-bar"> <div class="percentage-bar">
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment