Files
alpenwerk-hr/lib/dashboard-filter.ts
Maximilian Stubhan 10f8f1f2d5 Keep a note on the overview until somebody ticks it off
A note with a follow-up date is a task, and the overview is where tasks
are looked for. Until now it lived only in the employee file, which is
the one place you go when you already know who you are looking for.

Follow-ups behave differently from everything else on that card, and the
difference is the point: an entry on Monday is over on Tuesday, an
unfinished task is not. So there is no lower bound on the date — what
was due and never ticked off stays, marked overdue in red, sorted to the
top because it is sorted by date. A task that drops out of the list by
itself is a forgotten task.

Only "Erledigt" removes it. A note without a follow-up date never
appears: it is a record, not a task.

Checked against the live database — an overdue one and an upcoming one
appear, one without a date and one beyond the chosen period do not, and
ticking the overdue one off removes exactly it. The probe notes were
deleted again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 19:44:48 +02:00

48 lines
1.9 KiB
TypeScript

// Was auf der Übersicht als „anstehend" gilt — Zeitraum und Art.
//
// Die Auswahl steht in der Adresse, nicht im Browser: die Übersicht wird auf
// dem Server gebaut, und ein Zeitraum von 90 statt 60 Tagen bringt Zeilen ins
// Spiel, die im Browser gar nicht liegen. Nebenbei lässt sich eine so
// eingestellte Seite verschicken und wiederfinden.
export const ZEITRAEUME = [30, 60, 90, 180] as const;
export type Zeitraum = (typeof ZEITRAEUME)[number];
export const STANDARD_ZEITRAUM: Zeitraum = 60;
export const ANSTEHEND_ARTEN = [
{ value: "hire", label: "Eintritt" },
{ value: "exit", label: "Austritt" },
{ value: "return", label: "Rückkehr" },
{ value: "note", label: "Wiedervorlage" },
] as const;
export type AnstehendArt = (typeof ANSTEHEND_ARTEN)[number]["value"];
const ALLE_ARTEN: AnstehendArt[] = ANSTEHEND_ARTEN.map((a) => a.value);
/** Alles, was nicht in der Liste steht, führt auf den Standard zurück. */
export function parseZeitraum(wert: string | undefined): Zeitraum {
const zahl = Number(wert);
return (ZEITRAEUME as readonly number[]).includes(zahl) ? (zahl as Zeitraum) : STANDARD_ZEITRAUM;
}
/**
* Keine Angabe heisst „alle" — nicht „keine". Wer die Übersicht aufruft, ohne
* etwas auszuwählen, will alles sehen; eine leere Karte wäre die falsche
* Antwort auf eine nicht gestellte Frage. Aus demselben Grund führt auch eine
* Auswahl, in der nur Unbekanntes steht, zurück auf alle.
*/
export function parseArten(wert: string | undefined): AnstehendArt[] {
const gewaehlt = (wert ?? "")
.split(",")
.map((s) => s.trim())
.filter((s): s is AnstehendArt => (ALLE_ARTEN as string[]).includes(s));
return gewaehlt.length > 0 ? gewaehlt : ALLE_ARTEN;
}
/** Steht in der Adresse etwas anderes als der Standard? */
export function istEingeschraenkt(zeitraum: Zeitraum, arten: AnstehendArt[]): boolean {
return zeitraum !== STANDARD_ZEITRAUM || arten.length !== ALLE_ARTEN.length;
}