Aufgabe mit Typ, Status, Priorität, Aufwand, Fälligkeit und Herkunft; Projekt als eigene Klammer darum. Zwei Entwurfsentscheidungen: - Die Inbox ist kein eigener Zustand, sondern schlicht eine Aufgabe ohne Bereich. Einsortieren heißt: einen Bereich setzen. Ein zusätzliches Feld könnte mit der Zuordnung auseinanderlaufen. - Projekt ist ein eigenes Modell, kein Aufgabentyp. Ein Projekt hat selbst weder Aufwand noch Fälligkeit, sondern leitet beides aus dem ab, was drinsteckt. ARBEITSPAKET und MEILENSTEIN sind Typen der Aufgaben *innerhalb* eines Projekts. @@unique([quelle, quelleRef]) ist die Grundlage für die Integrationen ab M6: sie upserten darüber, statt zu doppeln. Von Hand erfasste Aufgaben tragen quelleRef = null; PostgreSQL sieht NULL-Werte als verschieden an, sie behindern sich also nicht. Verworfene Aufgaben zählen bewusst gar nicht in den Fortschritt eines Projekts — sonst sähe es fertig aus, weil die Hälfte gestrichen wurde. Fälligkeit wird in Kalendertagen in Europe/Berlin gerechnet, nicht in 24-Stunden-Schritten: was heute um 23:00 fällig ist, ist heute fällig. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
97 lines
2.9 KiB
TypeScript
97 lines
2.9 KiB
TypeScript
import type { AufgabenStatus, AufgabenTyp, Quelle } from '@/generated/prisma/enums'
|
|
import {
|
|
faelligkeitEinordnen,
|
|
faelligkeitText,
|
|
istUeberfaellig,
|
|
type Faelligkeit,
|
|
} from '@/lib/aufgabe'
|
|
import { alsDatum, alsTagesschluessel } from '@/lib/zeit'
|
|
|
|
/**
|
|
* Bereitet eine Aufgabe für die Anzeige auf.
|
|
*
|
|
* Reine Funktion mit dem Zeitpunkt als Parameter: Formatierung und
|
|
* Fälligkeitsrechnung passieren serverseitig in Europe/Berlin, damit im
|
|
* Browser nichts nachgerechnet wird und alle Listen gleich aussehen.
|
|
*/
|
|
|
|
export type AufgabeRoh = {
|
|
id: string
|
|
titel: string
|
|
notiz: string | null
|
|
typ: AufgabenTyp
|
|
status: AufgabenStatus
|
|
prioritaet: number
|
|
aufwandMinuten: number | null
|
|
faelligAm: Date | null
|
|
quelle: Quelle
|
|
quelleUrl: string | null
|
|
bereich: { id: string; name: string; farbe: string } | null
|
|
projekt: { id: string; name: string } | null
|
|
}
|
|
|
|
export type AufgabeAnzeige = {
|
|
id: string
|
|
titel: string
|
|
notiz: string | null
|
|
typ: AufgabenTyp
|
|
status: AufgabenStatus
|
|
prioritaet: number
|
|
aufwandMinuten: number | null
|
|
/** ISO-Datum für das Formularfeld, sonst leer. */
|
|
faelligWert: string
|
|
/** "heute fällig", "seit 3 Tagen überfällig", "ohne Termin". */
|
|
faelligText: string
|
|
/** Ausgeschriebenes Datum für den Titelhinweis, sonst null. */
|
|
faelligDatum: string | null
|
|
faelligkeit: Faelligkeit['art']
|
|
ueberfaellig: boolean
|
|
quelle: Quelle
|
|
quelleUrl: string | null
|
|
bereich: { id: string; name: string; farbe: string } | null
|
|
projekt: { id: string; name: string } | null
|
|
}
|
|
|
|
/**
|
|
* ISO-Datum in Europe/Berlin, passend für ein <input type="date">.
|
|
* Der Wert des Feldes ist ein reines Datum ohne Zeitzone, also der Berliner
|
|
* Kalendertag — dieselbe Rechnung wie überall sonst im Planer.
|
|
*/
|
|
function alsDatumswert(zeitpunkt: Date | null): string {
|
|
return zeitpunkt ? alsTagesschluessel(zeitpunkt) : ''
|
|
}
|
|
|
|
export function fuerAnzeige(aufgabe: AufgabeRoh, jetzt: Date): AufgabeAnzeige {
|
|
const faelligkeit = faelligkeitEinordnen(aufgabe.faelligAm, jetzt)
|
|
|
|
return {
|
|
id: aufgabe.id,
|
|
titel: aufgabe.titel,
|
|
notiz: aufgabe.notiz,
|
|
typ: aufgabe.typ,
|
|
status: aufgabe.status,
|
|
prioritaet: aufgabe.prioritaet,
|
|
aufwandMinuten: aufgabe.aufwandMinuten,
|
|
faelligWert: alsDatumswert(aufgabe.faelligAm),
|
|
faelligText: faelligkeitText(faelligkeit),
|
|
faelligDatum: aufgabe.faelligAm ? alsDatum(aufgabe.faelligAm) : null,
|
|
faelligkeit: faelligkeit.art,
|
|
ueberfaellig: istUeberfaellig(aufgabe.faelligAm, aufgabe.status, jetzt),
|
|
quelle: aufgabe.quelle,
|
|
quelleUrl: aufgabe.quelleUrl,
|
|
bereich: aufgabe.bereich,
|
|
projekt: aufgabe.projekt,
|
|
}
|
|
}
|
|
|
|
/** Wie dringend die Fälligkeit aussieht — steuert die Farbe des Kennzeichens. */
|
|
export function faelligkeitFarbe(
|
|
anzeige: AufgabeAnzeige,
|
|
): 'neutral' | 'warnung' | 'gefahr' {
|
|
if (anzeige.ueberfaellig) return 'gefahr'
|
|
if (anzeige.faelligkeit === 'heute' || anzeige.faelligkeit === 'morgen') {
|
|
return 'warnung'
|
|
}
|
|
return 'neutral'
|
|
}
|