diff --git a/src/modules/registratura/components/imminent-actions.tsx b/src/modules/registratura/components/imminent-actions.tsx index 8db7eda..9c691ae 100644 --- a/src/modules/registratura/components/imminent-actions.tsx +++ b/src/modules/registratura/components/imminent-actions.tsx @@ -1,11 +1,10 @@ "use client"; import { useMemo } from "react"; -import { AlertTriangle, Bell, Clock, Timer, ChevronRight } from "lucide-react"; +import { AlertTriangle, Bell, Timer, ChevronRight } from "lucide-react"; import { Badge } from "@/shared/components/ui/badge"; import { cn } from "@/shared/lib/utils"; import type { RegistryEntry } from "../types"; -import { getDeadlineType } from "../services/deadline-catalog"; interface ImminentActionsProps { entries: RegistryEntry[]; @@ -14,13 +13,16 @@ interface ImminentActionsProps { interface ActionItem { entry: RegistryEntry; - type: "expiry" | "ac-validity" | "deadline-overdue" | "deadline-soon"; + type: "expiry" | "ac-validity"; label: string; detail: string; daysLeft: number; - color: "red" | "amber" | "blue"; + color: "red" | "amber"; } +/** Max lookahead window in days */ +const HORIZON_DAYS = 60; + function formatDate(iso: string): string { try { return new Date(iso).toLocaleDateString("ro-RO", { @@ -43,35 +45,34 @@ export function ImminentActions({ entries, onNavigate }: ImminentActionsProps) { for (const entry of entries) { if (entry.status !== "deschis") continue; - // Expiry date alerts + // Document expiry alerts (already expired or within horizon) if (entry.expiryDate) { const expiry = new Date(entry.expiryDate); expiry.setHours(0, 0, 0, 0); const daysLeft = Math.ceil((expiry.getTime() - nowMs) / (1000 * 60 * 60 * 24)); - const alertDays = entry.expiryAlertDays ?? 30; if (daysLeft < 0) { items.push({ entry, type: "expiry", label: `Expirat de ${Math.abs(daysLeft)} zile`, - detail: `Valabilitate: ${formatDate(entry.expiryDate)}`, + detail: `Valabil până: ${formatDate(entry.expiryDate)}`, daysLeft, color: "red", }); - } else if (daysLeft <= alertDays) { + } else if (daysLeft <= HORIZON_DAYS) { items.push({ entry, type: "expiry", - label: `Expiră în ${daysLeft} zile`, - detail: `Valabilitate: ${formatDate(entry.expiryDate)}`, + label: daysLeft === 0 ? "Expiră azi" : `Expiră în ${daysLeft} zile`, + detail: `Valabil până: ${formatDate(entry.expiryDate)}`, daysLeft, - color: daysLeft <= 7 ? "red" : "amber", + color: daysLeft <= 14 ? "red" : "amber", }); } } - // AC validity alerts + // AC validity alerts (already expired or within horizon) if (entry.acValidity?.enabled && !entry.acValidity.reminder.dismissed) { const ac = entry.acValidity; const validityMonths = ac.validityMonths ?? 12; @@ -81,54 +82,30 @@ export function ImminentActions({ entries, onNavigate }: ImminentActionsProps) { validityEnd.setHours(0, 0, 0, 0); const daysLeft = Math.ceil((validityEnd.getTime() - nowMs) / (1000 * 60 * 60 * 24)); - if (daysLeft <= 90) { + if (daysLeft < 0) { items.push({ entry, type: "ac-validity", - label: daysLeft < 0 - ? `AC expirat de ${Math.abs(daysLeft)} zile` - : `AC expiră în ${daysLeft} zile`, - detail: `Valabilitate ${validityMonths} luni de la ${formatDate(ac.issuanceDate)}`, + label: `AC expirat de ${Math.abs(daysLeft)} zile`, + detail: `${validityMonths} luni de la ${formatDate(ac.issuanceDate)}`, + daysLeft, + color: "red", + }); + } else if (daysLeft <= HORIZON_DAYS) { + items.push({ + entry, + type: "ac-validity", + label: daysLeft === 0 ? "AC expiră azi" : `AC expiră în ${daysLeft} zile`, + detail: `${validityMonths} luni de la ${formatDate(ac.issuanceDate)}`, daysLeft, color: daysLeft <= 30 ? "red" : "amber", }); } } - - // Tracked deadlines - const pending = (entry.trackedDeadlines ?? []).filter(d => d.resolution === "pending"); - for (const dl of pending) { - const due = new Date(dl.dueDate); - due.setHours(0, 0, 0, 0); - const daysLeft = Math.ceil((due.getTime() - nowMs) / (1000 * 60 * 60 * 24)); - const typeDef = getDeadlineType(dl.typeId); - const typeLabel = typeDef?.label ?? dl.typeId; - - if (daysLeft < 0) { - items.push({ - entry, - type: "deadline-overdue", - label: `Termen depășit: ${typeLabel}`, - detail: `Scadent: ${formatDate(dl.dueDate)} (${Math.abs(daysLeft)} zile depășit)`, - daysLeft, - color: "red", - }); - } else if (daysLeft <= 5) { - items.push({ - entry, - type: "deadline-soon", - label: `Termen iminent: ${typeLabel}`, - detail: `Scadent: ${formatDate(dl.dueDate)} (${daysLeft === 0 ? "azi" : `${daysLeft} zile`})`, - daysLeft, - color: daysLeft <= 1 ? "red" : "amber", - }); - } - } } - // Sort: most urgent first (most negative daysLeft) + // Most urgent first items.sort((a, b) => a.daysLeft - b.daysLeft); - return items; }, [entries]); @@ -137,8 +114,6 @@ export function ImminentActions({ entries, onNavigate }: ImminentActionsProps) { const ICON_MAP = { expiry: Timer, "ac-validity": Bell, - "deadline-overdue": AlertTriangle, - "deadline-soon": Clock, } as const; const COLOR_MAP = { @@ -146,19 +121,11 @@ export function ImminentActions({ entries, onNavigate }: ImminentActionsProps) { border: "border-red-200 dark:border-red-900", bg: "bg-red-50/60 dark:bg-red-950/20", text: "text-red-700 dark:text-red-400", - badge: "bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-400", }, amber: { border: "border-amber-200 dark:border-amber-900", bg: "bg-amber-50/60 dark:bg-amber-950/20", text: "text-amber-700 dark:text-amber-400", - badge: "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-400", - }, - blue: { - border: "border-blue-200 dark:border-blue-900", - bg: "bg-blue-50/60 dark:bg-blue-950/20", - text: "text-blue-700 dark:text-blue-400", - badge: "bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-400", }, } as const; @@ -167,14 +134,17 @@ export function ImminentActions({ entries, onNavigate }: ImminentActionsProps) {
- Acțiuni iminente + De reînnoit {actions.length} + + următoarele {HORIZON_DAYS} zile +
- {actions.slice(0, 8).map((action, i) => { + {actions.map((action, i) => { const Icon = ICON_MAP[action.type]; const colors = COLOR_MAP[action.color]; return ( @@ -199,19 +169,13 @@ export function ImminentActions({ entries, onNavigate }: ImminentActionsProps) {

- {action.entry.subject} - {action.detail ? ` — ${action.detail}` : ""} + {action.entry.subject} — {action.detail}

); })} - {actions.length > 8 && ( -

- + {actions.length - 8} alte acțiuni -

- )} );