/** * Attendance — tracks who was in each TG. * * Usage: * import { Attendance } from "@systems/attendance"; * * Attendance.snapshot(slot) * Attendance.players(slot) * Attendance.allSubmitted(slot, date) */ import fs from "fs"; import { Paths } from "@paths"; import { UserKey, HistoryKey } from "@types"; import { Store } from "@systems/store"; interface AttendanceData { [historyKey: HistoryKey]: UserKey[]; } let _data: AttendanceData = {}; function load(): void { _data = Store.readOrDefault(Paths.data("attendance.json"), {}); } function save(): void { Store.write(Paths.data("attendance.json"), _data); } load(); export const Attendance = { /** * Snapshot attendance from poll state at lock time. */ snapshot(slot: number, lockedYesKeys: Set): void { const date = new Date().toISOString().slice(0, 10); const historyKey = `${date}-${slot}` as HistoryKey; _data[historyKey] = [...lockedYesKeys]; save(); }, /** * Get players who attended a specific TG. */ players(historyKey: HistoryKey): UserKey[] { return _data[historyKey] ?? []; }, /** * Check if a specific player attended. */ includes(historyKey: HistoryKey, userKey: UserKey): boolean { return (_data[historyKey] ?? []).includes(userKey); }, /** * Check if all attendees have submitted scores. */ allSubmitted(historyKey: HistoryKey): boolean { const players = _data[historyKey] ?? []; if (players.length === 0) return false; try { const result = JSON.parse( fs.readFileSync(Paths.data("tg-history", `${historyKey}.json`), "utf8") ); const submitted = new Set(result.scores?.map((s: any) => s.userKey) ?? []); return players.every((p) => submitted.has(p)); } catch { return false; } }, /** * Get all history keys (for listing past TGs). */ all(): HistoryKey[] { return Object.keys(_data) as HistoryKey[]; }, };