fix: dashboard stats exclude closed entries + auto-tracked deadlines

- aggregateDeadlines() now skips entries with status "inchis"
- Auto-tracked/background deadlines excluded from active/urgent/overdue counts
- Only user-created deadlines affect badge numbers
- Milestone dots vertically centered on progress bar (top-[5px], h-2.5)
- Milestone tooltips now show full date ("Data maximă: 15 februarie 2026")
- Countdown text shows date on hover too

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-12 19:13:49 +02:00
parent c892e8d820
commit 0f928b08e9
2 changed files with 32 additions and 7 deletions
@@ -36,6 +36,18 @@ interface DeadlineDashboardProps {
) => void; ) => void;
} }
function formatFullDate(iso: string): string {
try {
return new Date(iso).toLocaleDateString("ro-RO", {
day: "2-digit",
month: "long",
year: "numeric",
});
} catch {
return iso;
}
}
const VARIANT_DOT: Record<string, string> = { const VARIANT_DOT: Record<string, string> = {
green: "bg-green-500", green: "bg-green-500",
yellow: "bg-amber-500", yellow: "bg-amber-500",
@@ -327,6 +339,7 @@ interface ProgressMilestone {
label: string; label: string;
isPassed: boolean; isPassed: boolean;
typeId: string; typeId: string;
dueDate: string; // ISO date for tooltip
} }
function computeMilestones( function computeMilestones(
@@ -359,6 +372,7 @@ function computeMilestones(
label: getMilestoneLabel(def.id, dlDue < now), label: getMilestoneLabel(def.id, dlDue < now),
isPassed: dlDue < now, isPassed: dlDue < now,
typeId: def.id, typeId: def.id,
dueDate: dl.dueDate,
}); });
} }
@@ -498,13 +512,13 @@ function DeadlineRow({
{milestones.map((ms) => ( {milestones.map((ms) => (
<div <div
key={ms.typeId} key={ms.typeId}
className="absolute top-[4px] -ml-[4px]" className="absolute top-[5px] -ml-[5px]"
style={{ left: `${ms.position * 100}%` }} style={{ left: `${ms.position * 100}%` }}
title={ms.label} title={`${ms.label}\nData maximă: ${formatFullDate(ms.dueDate)}`}
> >
<div <div
className={cn( className={cn(
"h-2 w-2 rounded-full border", "h-2.5 w-2.5 rounded-full border",
ms.isPassed ms.isPassed
? "border-muted-foreground/50 bg-muted-foreground/30" ? "border-muted-foreground/50 bg-muted-foreground/30"
: "border-amber-500 bg-amber-400", : "border-amber-500 bg-amber-400",
@@ -524,6 +538,7 @@ function DeadlineRow({
"text-xs font-medium", "text-xs font-medium",
VARIANT_TEXT[status.variant], VARIANT_TEXT[status.variant],
)} )}
title={`Data maximă: ${formatFullDate(deadline.dueDate)}`}
> >
{status.daysRemaining < 0 {status.daysRemaining < 0
? `${Math.abs(status.daysRemaining)}z depasit` ? `${Math.abs(status.daysRemaining)}z depasit`
@@ -225,6 +225,9 @@ export function aggregateDeadlines(entries: RegistryEntry[]): {
now.setHours(0, 0, 0, 0); now.setHours(0, 0, 0, 0);
for (const entry of entries) { for (const entry of entries) {
// Skip closed entries — their deadlines are no longer actionable
if (entry.status === "inchis") continue;
// Check missing recipient registration for outgoing entries // Check missing recipient registration for outgoing entries
if ( if (
entry.direction === "iesit" && entry.direction === "iesit" &&
@@ -249,14 +252,21 @@ export function aggregateDeadlines(entries: RegistryEntry[]): {
} }
for (const dl of entry.trackedDeadlines ?? []) { for (const dl of entry.trackedDeadlines ?? []) {
// Skip auto-tracked/background sub-deadlines from top-level stats
const dlDef = getDeadlineType(dl.typeId);
if (dlDef?.backgroundOnly) continue;
const status = getDeadlineDisplayStatus(dl); const status = getDeadlineDisplayStatus(dl);
all.push({ deadline: dl, entry, status }); all.push({ deadline: dl, entry, status });
if (dl.resolution === "pending") { if (dl.resolution === "pending") {
// Only count user-created (non-auto-track) deadlines in main stats
if (!dlDef?.autoTrack) {
active++; active++;
if (status.variant === "yellow") urgent++; if (status.variant === "yellow") urgent++;
if (status.variant === "red") overdue++; if (status.variant === "red") overdue++;
if (status.variant === "blue") tacit++; if (status.variant === "blue") tacit++;
}
} else if (dl.resolution === "aprobat-tacit") { } else if (dl.resolution === "aprobat-tacit") {
tacit++; tacit++;
} }