56 lines
1.8 KiB
TypeScript
56 lines
1.8 KiB
TypeScript
/** Kalendertag lokal als `YYYY-MM-DD` (für Vergleich mit DB). */
|
|
export function localDateKey(d: Date): string {
|
|
const y = d.getFullYear();
|
|
const m = String(d.getMonth() + 1).padStart(2, "0");
|
|
const day = String(d.getDate()).padStart(2, "0");
|
|
return `${y}-${m}-${day}`;
|
|
}
|
|
|
|
/** UI-Wert für `<input type="date" />` aus API-Wert. */
|
|
export function deadlineToDateInput(deadlineAt: string | null | undefined): string {
|
|
if (!deadlineAt) return "";
|
|
const s = deadlineAt.trim();
|
|
if (/^\d{4}-\d{2}-\d{2}$/.test(s)) return s;
|
|
const t = new Date(s);
|
|
if (Number.isNaN(t.getTime())) return "";
|
|
return localDateKey(t);
|
|
}
|
|
|
|
export type DeadlineTone = "none" | "upcoming" | "today" | "overdue";
|
|
|
|
/** Blau = künftig (nicht heute), Orange = heute fällig, Rot = überschritten. */
|
|
export function deadlineTone(deadlineAt: string | null | undefined): DeadlineTone {
|
|
if (!deadlineAt) return "none";
|
|
const key = deadlineToDateInput(deadlineAt);
|
|
if (!key) return "none";
|
|
const today = localDateKey(new Date());
|
|
if (key < today) return "overdue";
|
|
if (key === today) return "today";
|
|
return "upcoming";
|
|
}
|
|
|
|
export function deadlineBadgeClass(tone: DeadlineTone): string {
|
|
switch (tone) {
|
|
case "upcoming":
|
|
return "text-blue-500/70 text-blue-800 dark:text-blue-200";
|
|
case "today":
|
|
return "text-orange-500/80 text-orange-900 dark:text-orange-100";
|
|
case "overdue":
|
|
return "text-destructive/80 text-destructive";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
export function formatDeadlineLabel(deadlineAt: string): string {
|
|
const key = deadlineToDateInput(deadlineAt);
|
|
if (!key) return deadlineAt;
|
|
try {
|
|
const [y, m, d] = key.split("-").map(Number);
|
|
const dt = new Date(y, m - 1, d);
|
|
return dt.toLocaleDateString(undefined, { dateStyle: "medium" });
|
|
} catch {
|
|
return key;
|
|
}
|
|
}
|