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:
@@ -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++;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user