"use client"; import { useState, useMemo } from "react"; import { Shield, Calendar, AlertTriangle, CheckCircle2, Clock, Bell, BellOff, ChevronDown, ChevronRight, FileText, Building2, Newspaper, Construction, Info, XCircle, } from "lucide-react"; import { Button } from "@/shared/components/ui/button"; import { Input } from "@/shared/components/ui/input"; import { Label } from "@/shared/components/ui/label"; import { Badge } from "@/shared/components/ui/badge"; import { Switch } from "@/shared/components/ui/switch"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/shared/components/ui/select"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "@/shared/components/ui/tooltip"; import { Textarea } from "@/shared/components/ui/textarea"; import type { ACValidityTracking, ACExecutionDuration, ACPhase, } from "../types"; import { addWorkingDays, addCalendarDays } from "../services/working-days"; import { cn } from "@/shared/lib/utils"; interface ACValidityTrackerProps { value: ACValidityTracking | undefined; onChange: (value: ACValidityTracking | undefined) => void; /** The entry's date (used as default issuance date) */ entryDate: string; } const EXECUTION_LABELS: Record = { 6: "6 luni", 12: "12 luni", 24: "24 luni", 36: "36 luni", }; const PHASE_LABELS: Record = { validity: "Valabilitate AC", execution: "Execuție lucrări", extended: "Prelungit (+24 luni)", abandoned: "Abandonat", expired: "Expirat", }; const PHASE_COLORS: Record = { validity: "bg-blue-500", execution: "bg-green-500", extended: "bg-amber-500", abandoned: "bg-gray-500", expired: "bg-red-500", }; function createDefault(entryDate: string): ACValidityTracking { return { enabled: true, issuanceDate: entryDate, phase: "validity", executionDuration: 12, requiredDocs: { cfNotation: false, newspaperPublication: false, sitePanel: false, }, reminder: { snoozeCount: 0, dismissed: false }, extensionGranted: false, abandonedDeclaration: false, notes: [], }; } function formatDate(iso: string): string { try { return new Date(iso).toLocaleDateString("ro-RO", { day: "2-digit", month: "2-digit", year: "numeric", }); } catch { return iso; } } function daysBetween(d1: string, d2: string): number { const a = new Date(d1); const b = new Date(d2); a.setHours(0, 0, 0, 0); b.setHours(0, 0, 0, 0); return Math.round((b.getTime() - a.getTime()) / (1000 * 60 * 60 * 24)); } function monthsBetween(d1: string, d2: string): number { const a = new Date(d1); const b = new Date(d2); return ( (b.getFullYear() - a.getFullYear()) * 12 + (b.getMonth() - a.getMonth()) ); } export function ACValidityTracker({ value, onChange, entryDate, }: ACValidityTrackerProps) { const [expanded, setExpanded] = useState(!!value?.enabled); const ac = value ?? createDefault(entryDate); const handleToggle = (enabled: boolean) => { if (enabled) { const newAc = createDefault(entryDate); onChange(newAc); setExpanded(true); } else { onChange(undefined); setExpanded(false); } }; const update = (changes: Partial) => { onChange({ ...ac, ...changes }); }; const updateDocs = (changes: Partial) => { onChange({ ...ac, requiredDocs: { ...ac.requiredDocs, ...changes } }); }; // ── Computed dates ── const computedData = useMemo(() => { if (!ac.enabled || !ac.issuanceDate) return null; const issuance = new Date(ac.issuanceDate); const now = new Date(); now.setHours(0, 0, 0, 0); const today = now.toISOString().slice(0, 10); // 12-month validity period const validityEnd = new Date(issuance); validityEnd.setMonth(validityEnd.getMonth() + 12); const validityEndStr = validityEnd.toISOString().slice(0, 10); const daysToValidityEnd = daysBetween(today, validityEndStr); const monthsToValidityEnd = monthsBetween(today, validityEndStr); // Announcement deadline: 10 days before starting works (within 12-month window) const announcementDeadline = addCalendarDays(validityEnd, -10); const announcementDeadlineStr = announcementDeadline .toISOString() .slice(0, 10); // Extension request deadline: 45 working days before AC expiry const extensionRequestDeadline = addWorkingDays(validityEnd, -45); const extensionRequestDeadlineStr = extensionRequestDeadline .toISOString() .slice(0, 10); const daysToExtensionDeadline = daysBetween( today, extensionRequestDeadlineStr, ); // Execution period end (if works started) let executionEnd: string | null = null; if (ac.worksStartDate) { const start = new Date(ac.worksStartDate); start.setMonth(start.getMonth() + ac.executionDuration); executionEnd = start.toISOString().slice(0, 10); } // Extension end (if granted, +24 months from original end) let extendedEnd: string | null = null; if (ac.extensionGranted && executionEnd) { const execEnd = new Date(executionEnd); execEnd.setMonth(execEnd.getMonth() + 24); extendedEnd = execEnd.toISOString().slice(0, 10); } // Are all required docs fulfilled? const allDocsComplete = ac.requiredDocs.cfNotation && ac.requiredDocs.newspaperPublication && ac.requiredDocs.sitePanel; // Can the validity period be "closed" (works announced)? const canAnnounce = allDocsComplete && !ac.worksAnnouncedDate; // Extension prelungire deadline for execution (45 working days before exec end) let execExtensionDeadline: string | null = null; if (executionEnd) { const d = addWorkingDays(new Date(executionEnd), -45); execExtensionDeadline = d.toISOString().slice(0, 10); } return { validityEndStr, daysToValidityEnd, monthsToValidityEnd, announcementDeadlineStr, extensionRequestDeadlineStr, daysToExtensionDeadline, executionEnd, extendedEnd, allDocsComplete, canAnnounce, execExtensionDeadline, }; }, [ac]); const isEnabled = !!value?.enabled; return (
{isEnabled && computedData && ( <> {/* Phase badge + overview */}
{PHASE_LABELS[ac.phase]} {computedData.daysToValidityEnd > 0 && ac.phase === "validity" && ( {computedData.daysToValidityEnd} zile rămase din valabilitate )} {computedData.daysToValidityEnd <= 0 && ac.phase === "validity" && !ac.worksAnnouncedDate && ( Valabilitate expirată! )}
{/* Issuance date + duration */}
update({ issuanceDate: e.target.value })} className="mt-1" />
{formatDate(computedData.validityEndStr)}
{/* Step 1: Required documents for starting works */} {ac.phase === "validity" && !ac.abandonedDeclaration && (
{expanded && (

Toate cele 3 documente sunt necesare pentru a putea anunța începerea lucrărilor. Minim 10 zile înainte de începerea lucrărilor, anunțați la Primărie și ISC.

{/* CF Notation */}
updateDocs({ cfNotation: v, cfNotationDate: v ? new Date().toISOString().slice(0, 10) : undefined, }) } />
{ac.requiredDocs.cfNotation && ( updateDocs({ cfNotationDate: e.target.value }) } className="w-[150px] text-xs h-7" /> )}
{/* Newspaper publication */}
updateDocs({ newspaperPublication: v, newspaperPublicationDate: v ? new Date().toISOString().slice(0, 10) : undefined, }) } />
{ac.requiredDocs.newspaperPublication && ( updateDocs({ newspaperPublicationDate: e.target.value, }) } className="w-[150px] text-xs h-7" /> )}
{/* Site panel */}
updateDocs({ sitePanel: v, sitePanelDate: v ? new Date().toISOString().slice(0, 10) : undefined, }) } />
{ac.requiredDocs.sitePanel && ( updateDocs({ sitePanelDate: e.target.value }) } className="w-[150px] text-xs h-7" /> )}
{/* Progress indicator */}
{(ac.requiredDocs.cfNotation ? 1 : 0) + (ac.requiredDocs.newspaperPublication ? 1 : 0) + (ac.requiredDocs.sitePanel ? 1 : 0)} /3
)}
)} {/* Step 2: Announce works (when all docs are ready) */} {ac.phase === "validity" && computedData.allDocsComplete && !ac.worksAnnouncedDate && !ac.abandonedDeclaration && (

Documente complete! Puteți anunța începerea lucrărilor.

Anunțați la Primărie și ISC cu minim 10 zile înainte de începerea lucrărilor. Termen recomandat anunțare:{" "} {formatDate(computedData.announcementDeadlineStr)}

{ if (e.target.value) { update({ worksAnnouncedDate: e.target.value, worksStartDate: e.target.value, phase: "execution", }); } }} className="mt-1" />
)} {/* Works announced — execution phase */} {(ac.phase === "execution" || ac.phase === "extended") && ac.worksStartDate && computedData.executionEnd && (
Lucrări în execuție
Început:

{formatDate(ac.worksStartDate)}

Durată:

{ac.executionDuration} luni {ac.phase === "extended" ? " + 24 luni" : ""}

Termen execuție:

{formatDate( ac.phase === "extended" && computedData.extendedEnd ? computedData.extendedEnd : computedData.executionEnd, )}

{/* Extension request reminder */} {computedData.execExtensionDeadline && !ac.extensionGranted && ac.phase !== "extended" && (

Cererea de prelungire trebuie depusă cu cel puțin 45 zile lucrătoare înainte de expirare. Termen limită:{" "} {formatDate(computedData.execExtensionDeadline)}

Prelungirea se acordă o singură dată, gratuit, pentru max 24 luni. Se înscrie pe originalul AC fără documentație nouă. Decizia vine în max 15 zile lucrătoare de la depunere.

{!ac.extensionRequestDate && (
{ if (e.target.value) { update({ extensionRequestDate: e.target.value, }); } }} className="w-[140px] text-[10px] h-6" />
)} {ac.extensionRequestDate && !ac.extensionGranted && (
Cerere depusă la{" "} {formatDate(ac.extensionRequestDate)}
)}
)}
)} {/* Reminders section */} {ac.phase === "validity" && !ac.worksAnnouncedDate && !ac.abandonedDeclaration && (
{ac.reminder.dismissed ? ( ) : ( )} {ac.reminder.dismissed ? "Remindere dezactivate" : `Reminder lunar activ (luna ${computedData.monthsToValidityEnd > 0 ? 12 - computedData.monthsToValidityEnd : 12}/12)`}
{!ac.reminder.dismissed && computedData.monthsToValidityEnd >= 2 && ( )}
)} {/* Abandon option (after month 10 or when snooze limit reached) */} {ac.phase === "validity" && !ac.worksAnnouncedDate && !ac.abandonedDeclaration && (

Dacă nu se mai dorește începerea construcției:

{ if (v) { update({ abandonedDeclaration: true, abandonedDate: new Date().toISOString().slice(0, 10), phase: "abandoned", }); } }} />
)} {/* Abandoned state */} {ac.abandonedDeclaration && (

Construcția a fost declarată abandonată

{ac.abandonedDate && (

Data declarației: {formatDate(ac.abandonedDate)}

)}