Baustein 3: Wochenplan als Startseite, Fortschritt, Wochen verschieben
- Wochenplan ist die Startseite des Azubis: Thema, Leitfrage, fuenf Tage mit Theorie und Praxis, Fortschrittsbalken, was noch offen ist - Ausbilder sieht je Azubi die laufende Woche mit Stand und offenen Punkten - /woche/<nr> fuer jede Woche, Ausbilder waehlt ueber ?azubi= den Stand; Zugriff wird serverseitig bei jedem Aufruf geprueft - Tabelle wochenplanung mit geplantem und tatsaechlichem Datum, Zustand und Notiz fuer den Azubi - Verschieben per Datumsfeld, wahlweise mit allen folgenden Wochen - Reihenfolge per Ziehen und Ablegen sowie per Tastatur (Alt + Pfeil) - Warnung bei sich ueberlappenden Terminen - Plan entsteht automatisch beim Anlegen eines Azubikontos - Planungs- und Fortschrittslogik als reine Funktionen, 36 Tests dafuer - Insgesamt 104 Tests Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
1af5613e9b
commit
103a603eb4
@@ -0,0 +1,136 @@
|
||||
import { inhalte, type Handout, type Aufgabe } from '../inhalte';
|
||||
import type { Checkliste, Kontrolle, Woche } from '../inhalte/schema';
|
||||
import { gelesenSet } from '../repos/fortschritt';
|
||||
import { planVon } from '../repos/wochenplanung';
|
||||
import { heute } from '../zeit';
|
||||
import { aktuelleWoche } from './wochen';
|
||||
import { leer, wochenFortschritt, type Fortschritt } from './fortschritt';
|
||||
import type { Wochenplanung } from '../db/schema';
|
||||
|
||||
/**
|
||||
* Setzt aus Inhalt (Datei), Planung (Datenbank) und Fortschritt (Datenbank)
|
||||
* die Wochenansicht zusammen. Alles, was die Startseite braucht, kommt hier her.
|
||||
*/
|
||||
|
||||
export type Tagessicht = {
|
||||
tag: string;
|
||||
theorie: Handout[];
|
||||
praxis: string;
|
||||
/** Der Tag, der im Kalender zu diesem Wochentag gehört. */
|
||||
datum: string;
|
||||
istHeute: boolean;
|
||||
};
|
||||
|
||||
export type Wochensicht = {
|
||||
woche: Woche;
|
||||
planung: Wochenplanung;
|
||||
fortschritt: Fortschritt;
|
||||
tage: Tagessicht[];
|
||||
handouts: { handout: Handout; gelesen: boolean }[];
|
||||
aufgaben: Aufgabe[];
|
||||
checklisten: Checkliste[];
|
||||
kontrolle: Kontrolle | null;
|
||||
vorherige: number | null;
|
||||
naechste: number | null;
|
||||
};
|
||||
|
||||
export function wochensicht(ausbildungId: string, azubiId: string, wochenNummer: number): Wochensicht | null {
|
||||
const alle = inhalte();
|
||||
const woche = alle.wocheNach.get(wochenNummer);
|
||||
if (!woche) return null;
|
||||
|
||||
const plan = planVon(ausbildungId);
|
||||
const planung = plan.find((z) => z.wochenNummer === wochenNummer);
|
||||
if (!planung) return null;
|
||||
|
||||
const gelesen = gelesenSet(azubiId);
|
||||
const heuteDatum = heute();
|
||||
|
||||
const handouts = woche.handouts
|
||||
.map((id) => alle.handoutNach.get(id))
|
||||
.filter((h) => h !== undefined)
|
||||
.map((handout) => ({ handout, gelesen: gelesen.has(handout.id) }));
|
||||
|
||||
const tage: Tagessicht[] = woche.tage.map((tag, stelle) => {
|
||||
const datum = tagVersetzt(planung.geplantVon, stelle);
|
||||
return {
|
||||
tag: tag.tag,
|
||||
praxis: tag.praxis,
|
||||
datum,
|
||||
istHeute: datum === heuteDatum,
|
||||
theorie: tag.theorie.map((id) => alle.handoutNach.get(id)).filter((h) => h !== undefined),
|
||||
};
|
||||
});
|
||||
|
||||
const aufgaben = woche.aufgaben.map((id) => alle.aufgabeNach.get(id)).filter((a) => a !== undefined);
|
||||
const checklisten = woche.checklisten.map((id) => alle.checklisteNach.get(id)).filter((c) => c !== undefined);
|
||||
const kontrolle = woche.lernzielkontrolle ? (alle.kontrolleNach.get(woche.lernzielkontrolle) ?? null) : null;
|
||||
|
||||
const fortschritt = wochenFortschritt({
|
||||
handouts: { erledigt: handouts.filter((h) => h.gelesen).length, gesamt: handouts.length },
|
||||
// Diese Bereiche werden mit ihren Bausteinen scharf geschaltet. Bis dahin
|
||||
// zeigen sie ehrlich an, was die Woche vorsieht und noch offen ist.
|
||||
karten: leer,
|
||||
aufgaben: { erledigt: 0, gesamt: aufgaben.length },
|
||||
checklisten: { erledigt: 0, gesamt: checklisten.length },
|
||||
kontrolle: { erledigt: 0, gesamt: kontrolle ? 1 : 0 },
|
||||
});
|
||||
|
||||
const nummern = plan.map((z) => z.wochenNummer);
|
||||
const stelle = plan.findIndex((z) => z.wochenNummer === wochenNummer);
|
||||
|
||||
return {
|
||||
woche,
|
||||
planung,
|
||||
fortschritt,
|
||||
tage,
|
||||
handouts,
|
||||
aufgaben,
|
||||
checklisten,
|
||||
kontrolle,
|
||||
vorherige: stelle > 0 ? (nummern[stelle - 1] ?? null) : null,
|
||||
naechste: stelle < nummern.length - 1 ? (nummern[stelle + 1] ?? null) : null,
|
||||
};
|
||||
}
|
||||
|
||||
/** Die Woche, die gerade dran ist. */
|
||||
export function aktuelleWochensicht(ausbildungId: string, azubiId: string): Wochensicht | null {
|
||||
const plan = planVon(ausbildungId);
|
||||
const dran = aktuelleWoche(plan, heute());
|
||||
if (!dran) return null;
|
||||
return wochensicht(ausbildungId, azubiId, dran.wochenNummer);
|
||||
}
|
||||
|
||||
/** Kurzstand für die Ausbilderübersicht – ohne den ganzen Wochenaufbau. */
|
||||
export type Kurzstand = {
|
||||
wochenNummer: number;
|
||||
titel: string;
|
||||
geplantVon: string;
|
||||
geplantBis: string;
|
||||
status: Wochenplanung['status'];
|
||||
fortschritt: Fortschritt;
|
||||
handoutsGelesen: number;
|
||||
handoutsGesamt: number;
|
||||
};
|
||||
|
||||
export function kurzstand(ausbildungId: string, azubiId: string): Kurzstand | null {
|
||||
const sicht = aktuelleWochensicht(ausbildungId, azubiId);
|
||||
if (!sicht) return null;
|
||||
|
||||
return {
|
||||
wochenNummer: sicht.woche.nummer,
|
||||
titel: sicht.woche.titel,
|
||||
geplantVon: sicht.planung.geplantVon,
|
||||
geplantBis: sicht.planung.geplantBis,
|
||||
status: sicht.planung.status,
|
||||
fortschritt: sicht.fortschritt,
|
||||
handoutsGelesen: sicht.handouts.filter((h) => h.gelesen).length,
|
||||
handoutsGesamt: sicht.handouts.length,
|
||||
};
|
||||
}
|
||||
|
||||
function tagVersetzt(montag: string, tage: number): string {
|
||||
const d = new Date(`${montag}T12:00:00Z`);
|
||||
d.setUTCDate(d.getUTCDate() + tage);
|
||||
return d.toISOString().slice(0, 10);
|
||||
}
|
||||
Reference in New Issue
Block a user