tg.ts
· 4.1 KiB · TypeScript
Raw
/**
* TG — thin dispatcher for TG-related operations.
* Orchestrates Score, Attendance, WRank, and Bringer.
*
* Usage:
* import { TG } from "@systems/tg";
*
* TG.currentWeek()
* TG.resetWeek()
* TG.getAttendance({ historyKey })
* TG.getScore({ character, slot })
* TG.getWeeklySummary({ character })
*/
import { Nation, Character, UserKey, SlotHour, TGScore } from "@types";
import { WRank } from "@systems/wrank";
import { Bringer } from "@systems/bringer";
import { Score, WeeklySummary } from "@systems/score";
import { Attendance } from "@systems/attendance";
import { Config } from "@systems/config";
import { TGKey } from "@systems/tg-key";
export const TG = {
// ── Week ──────────────────────────────────────────────────────────────────
currentWeek() {
return WRank.currentWeek();
},
/**
* Reset to a new week — carry Bringer forward, clear ranks.
* Called every Monday 00:00 by the Scheduler.
*/
resetWeek(): void {
const now = new Date();
const newWeekKey = WRank.weekKey(now);
const prevWeekKey = WRank.weekKey(new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000));
// Access internal data via WRank
const prevWeek = WRank.weekFromKey(prevWeekKey);
const newWeek = WRank.currentWeek(); // ensures new week exists
if (prevWeek) {
const goal = Config.get({ section: "wrank", key: "goal" });
for (const nation of [Nation.Capella, Nation.Procyon]) {
const entries = prevWeek.entries[nation];
const rank1 = entries.find((e) => e.currentRank === 1);
// Rank 1 with >= goal TGs becomes Bringer — no exceptions
// Officers use Bringer.override() for manual adjustments
if (rank1 && rank1.tgCount >= goal) {
newWeek.bringer[nation] = rank1.characterName;
} else {
newWeek.bringer[nation] = null;
}
// Overrides do NOT carry forward — each week starts clean
delete (newWeek.bringer as any)[`${nation}Override`];
}
}
WRank.save();
console.log(`[TG] Week reset to ${newWeekKey}. Bringer:`, newWeek.bringer);
},
// ── Attendance ────────────────────────────────────────────────────────────
getAttendance({ historyKey, nation }: {
historyKey: TGKey;
nation?: Nation;
}): UserKey[] {
const players = Attendance.players(historyKey);
if (!nation) return players;
// Filter by nation requires character lookup — caller handles if needed
return players;
},
allSubmitted(historyKey: TGKey): boolean {
return Attendance.allSubmitted(historyKey);
},
// ── Score ─────────────────────────────────────────────────────────────────
getScore({ character, slot, date }: {
character: Character;
slot: SlotHour;
date?: string;
}): TGScore | null {
return Score.get({ character, slot });
},
getWeeklySummary({ character }: { character: Character }): WeeklySummary {
return Score.getWeeklySummary({ character });
},
submitScore(params: Parameters<typeof Score.submit>[0]): void {
Score.submit(params);
},
// ── Bringer ───────────────────────────────────────────────────────────────
getBringer({ nation }: { nation: Nation }): string | null {
return Bringer.get({ nation });
},
// ── W.Rank ────────────────────────────────────────────────────────────────
getEntry(character: Character) {
return WRank.entry(character.name, character.nation);
},
};
| 1 | /** |
| 2 | * TG — thin dispatcher for TG-related operations. |
| 3 | * Orchestrates Score, Attendance, WRank, and Bringer. |
| 4 | * |
| 5 | * Usage: |
| 6 | * import { TG } from "@systems/tg"; |
| 7 | * |
| 8 | * TG.currentWeek() |
| 9 | * TG.resetWeek() |
| 10 | * TG.getAttendance({ historyKey }) |
| 11 | * TG.getScore({ character, slot }) |
| 12 | * TG.getWeeklySummary({ character }) |
| 13 | */ |
| 14 | |
| 15 | import { Nation, Character, UserKey, SlotHour, TGScore } from "@types"; |
| 16 | import { WRank } from "@systems/wrank"; |
| 17 | import { Bringer } from "@systems/bringer"; |
| 18 | import { Score, WeeklySummary } from "@systems/score"; |
| 19 | import { Attendance } from "@systems/attendance"; |
| 20 | import { Config } from "@systems/config"; |
| 21 | import { TGKey } from "@systems/tg-key"; |
| 22 | |
| 23 | export const TG = { |
| 24 | // ── Week ────────────────────────────────────────────────────────────────── |
| 25 | |
| 26 | currentWeek() { |
| 27 | return WRank.currentWeek(); |
| 28 | }, |
| 29 | |
| 30 | /** |
| 31 | * Reset to a new week — carry Bringer forward, clear ranks. |
| 32 | * Called every Monday 00:00 by the Scheduler. |
| 33 | */ |
| 34 | resetWeek(): void { |
| 35 | const now = new Date(); |
| 36 | const newWeekKey = WRank.weekKey(now); |
| 37 | const prevWeekKey = WRank.weekKey(new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000)); |
| 38 | |
| 39 | // Access internal data via WRank |
| 40 | const prevWeek = WRank.weekFromKey(prevWeekKey); |
| 41 | const newWeek = WRank.currentWeek(); // ensures new week exists |
| 42 | |
| 43 | if (prevWeek) { |
| 44 | const goal = Config.get({ section: "wrank", key: "goal" }); |
| 45 | for (const nation of [Nation.Capella, Nation.Procyon]) { |
| 46 | const entries = prevWeek.entries[nation]; |
| 47 | const rank1 = entries.find((e) => e.currentRank === 1); |
| 48 | |
| 49 | // Rank 1 with >= goal TGs becomes Bringer — no exceptions |
| 50 | // Officers use Bringer.override() for manual adjustments |
| 51 | if (rank1 && rank1.tgCount >= goal) { |
| 52 | newWeek.bringer[nation] = rank1.characterName; |
| 53 | } else { |
| 54 | newWeek.bringer[nation] = null; |
| 55 | } |
| 56 | |
| 57 | // Overrides do NOT carry forward — each week starts clean |
| 58 | delete (newWeek.bringer as any)[`${nation}Override`]; |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | WRank.save(); |
| 63 | console.log(`[TG] Week reset to ${newWeekKey}. Bringer:`, newWeek.bringer); |
| 64 | }, |
| 65 | |
| 66 | // ── Attendance ──────────────────────────────────────────────────────────── |
| 67 | |
| 68 | getAttendance({ historyKey, nation }: { |
| 69 | historyKey: TGKey; |
| 70 | nation?: Nation; |
| 71 | }): UserKey[] { |
| 72 | const players = Attendance.players(historyKey); |
| 73 | if (!nation) return players; |
| 74 | // Filter by nation requires character lookup — caller handles if needed |
| 75 | return players; |
| 76 | }, |
| 77 | |
| 78 | allSubmitted(historyKey: TGKey): boolean { |
| 79 | return Attendance.allSubmitted(historyKey); |
| 80 | }, |
| 81 | |
| 82 | // ── Score ───────────────────────────────────────────────────────────────── |
| 83 | |
| 84 | getScore({ character, slot, date }: { |
| 85 | character: Character; |
| 86 | slot: SlotHour; |
| 87 | date?: string; |
| 88 | }): TGScore | null { |
| 89 | return Score.get({ character, slot }); |
| 90 | }, |
| 91 | |
| 92 | getWeeklySummary({ character }: { character: Character }): WeeklySummary { |
| 93 | return Score.getWeeklySummary({ character }); |
| 94 | }, |
| 95 | |
| 96 | submitScore(params: Parameters<typeof Score.submit>[0]): void { |
| 97 | Score.submit(params); |
| 98 | }, |
| 99 | |
| 100 | // ── Bringer ─────────────────────────────────────────────────────────────── |
| 101 | |
| 102 | getBringer({ nation }: { nation: Nation }): string | null { |
| 103 | return Bringer.get({ nation }); |
| 104 | }, |
| 105 | |
| 106 | // ── W.Rank ──────────────────────────────────────────────────────────────── |
| 107 | |
| 108 | getEntry(character: Character) { |
| 109 | return WRank.entry(character.name, character.nation); |
| 110 | }, |
| 111 | }; |