import type { Metadata } from 'next' import Link from 'next/link' import { CalendarRange } from 'lucide-react' import { Wochenraster } from '@/app/(app)/woche/wochenraster' import { Card, CardInhalt } from '@/components/ui/card' import { faelligkeitEinordnen, faelligkeitText, istUeberfaellig } from '@/lib/aufgabe' import { belegteMinuten, arbeitsfensterAmTag, kapazitaetAmTag, } from '@/lib/kalender/belegung' import { fensterHuelle, rasterBauen } from '@/lib/woche' import { alsDatum, gleicherTag, tagesBeginn } from '@/lib/zeit' import { verlangeAnmeldung } from '@/server/berechtigung' import { db } from '@/server/db' import { planbareAufgabenLaden, wocheLaden } from '@/server/abfragen/woche' import { jetzt } from '@/server/zeitgeber' export const metadata: Metadata = { title: 'Woche' } const WOCHENTAGE = [ 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag', 'Sonntag', ] export default async function WocheSeite({ searchParams, }: { searchParams: Promise<{ versatz?: string }> }) { const benutzer = await verlangeAnmeldung('/woche') const parameter = await searchParams // Über den Versatz lässt sich blättern; er steht in der Adresse, damit eine // bestimmte Woche als Lesezeichen taugt. const versatz = Number.parseInt(parameter.versatz ?? '0', 10) const sichereWochen = Number.isFinite(versatz) ? Math.max(-52, Math.min(52, versatz)) : 0 const heute = jetzt() const zeitpunkt = new Date(heute.getTime() + sichereWochen * 7 * 86_400_000) const [daten, aufgaben, bereiche, konto] = await Promise.all([ wocheLaden(benutzer.id, zeitpunkt), planbareAufgabenLaden(), db.bereich.findMany({ where: { aktiv: true }, orderBy: [{ reihenfolge: 'asc' }, { name: 'asc' }], }), // Für den ersten Wurf: der Zeitblock landet im ersten verbundenen // Kalender. Die Auswahl je Bereich kommt, sobald es mehrere gibt. db.kalenderkonto.findFirst({ where: { benutzerId: benutzer.id, aktiv: true }, orderBy: { erstelltAm: 'asc' }, select: { id: true, anzeigename: true }, }), ]) const huelle = fensterHuelle(bereiche) const raster = rasterBauen(zeitpunkt, huelle.von, huelle.bis) // Kapazität und Belegung je Tag: alle Bereiche zusammengenommen, denn ein // Termin blockiert die Zeit für alles gleichermaßen. const spalten = raster.spalten.map((spalte) => { const tag = spalte.tagesBeginn const kapazitaet = bereiche.reduce((summe, b) => summe + kapazitaetAmTag(b, tag), 0) const belegend = [ ...daten.termine.map((t) => ({ beginn: t.beginn, ende: t.ende, ganztaegig: t.ganztaegig, zeigtAls: t.zeigtAls, })), ...daten.zeitbloecke.map((z) => ({ beginn: z.beginn, ende: z.ende, ganztaegig: false, zeigtAls: 'GEBUCHT' as const, })), ] // Gegen die Hülle rechnen, nicht gegen ein einzelnes Arbeitsfenster: // die Tageskapazität ist hier die Summe über alle Bereiche. const fenster = arbeitsfensterAmTag(tag, huelle.von, huelle.bis) const belegt = belegteMinuten(belegend, fenster) return { schluessel: spalte.schluessel, tagesBeginnMs: spalte.tagesBeginn.getTime(), name: WOCHENTAGE[spalte.wochentag] ?? '', datum: alsDatum(tag).split(', ')[1] ?? '', heute: gleicherTag(tag, heute), kapazitaet, belegt, ueberbucht: kapazitaet > 0 && belegt > kapazitaet, } }) const montag = tagesBeginn(raster.spalten[0]?.tagesBeginn ?? zeitpunkt) const sonntag = raster.spalten[6]?.tagesBeginn ?? zeitpunkt return ( /* Die Wochenansicht braucht mehr Breite als der Inhaltsrahmen von 64rem hergibt – bei sieben Spalten plus Aufgabenliste wäre sonst der Sonntag abgeschnitten. Deshalb bricht genau diese Seite aus und nimmt bis zu 100rem, mittig und mit demselben Seitenabstand wie überall. */
{alsDatum(montag)} bis {alsDatum(sonntag)} {konto ? ` · schreibt nach ${konto.anzeigename}` : ''}
Aufgabe aus der linken Spalte in ein Zeitfenster ziehen, um sie einzuplanen. Ein Zeitblock lässt sich am Griff verschieben; das Kreuz plant ihn wieder aus. Graue Balken sind Termine aus dem Kalender — sie lassen sich hier nicht verschieben.