feat(registratura): AC validity 12/24 months + reminder config in Ghid termene

- Add ACValidityPeriod type (12 | 24) and validityMonths field to ACValidityTracking
- Replace hardcoded 12-month validity with configurable dropdown (12/24 luni)
- Update computed dates, reminder counter, and tooltip to use selected period
- Add "Configurare remindere si alerte" section in Ghid termene with:
  - Threshold table (urgent 5z, depasit 0z, CU alert 30z, AC monthly, prelungire 45z lucr, anuntare 10z cal, transmitere 1z)
  - Pause/resume explanation for clarification requests
- Update AC expiry description to mention configurable 12/24 month validity

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-12 19:38:15 +02:00
parent 55c807dd1b
commit b0f27053ae
3 changed files with 162 additions and 10 deletions
@@ -39,6 +39,7 @@ import {
import { Textarea } from "@/shared/components/ui/textarea";
import type {
ACValidityTracking,
ACValidityPeriod,
ACExecutionDuration,
ACPhase,
} from "../types";
@@ -52,6 +53,11 @@ interface ACValidityTrackerProps {
entryDate: string;
}
const VALIDITY_LABELS: Record<ACValidityPeriod, string> = {
12: "12 luni",
24: "24 luni",
};
const EXECUTION_LABELS: Record<ACExecutionDuration, string> = {
6: "6 luni",
12: "12 luni",
@@ -158,9 +164,10 @@ export function ACValidityTracker({
now.setHours(0, 0, 0, 0);
const today = now.toISOString().slice(0, 10);
// 12-month validity period
// Configurable validity period (12 or 24 months)
const validityMonths = ac.validityMonths ?? 12;
const validityEnd = new Date(issuance);
validityEnd.setMonth(validityEnd.getMonth() + 12);
validityEnd.setMonth(validityEnd.getMonth() + validityMonths);
const validityEndStr = validityEnd.toISOString().slice(0, 10);
const daysToValidityEnd = daysBetween(today, validityEndStr);
const monthsToValidityEnd = monthsBetween(today, validityEndStr);
@@ -243,10 +250,10 @@ export function ACValidityTracker({
</TooltipTrigger>
<TooltipContent side="right" className="max-w-sm">
<p className="text-xs">
Urmărirea completă a ciclului de viață al AC: valabilitate 12
luni, anunțare lucrări, documente obligatorii, durată
execuție, prelungire. Conform Legii 50/1991 și normelor
aferente.
Urmărirea completă a ciclului de viață al AC: valabilitate
12 sau 24 luni (configurabil), anunțare lucrări, documente
obligatorii, durată execuție, prelungire. Conform Legii
50/1991 și normelor aferente.
</p>
</TooltipContent>
</Tooltip>
@@ -288,8 +295,8 @@ export function ACValidityTracker({
)}
</div>
{/* Issuance date + duration */}
<div className="grid gap-3 sm:grid-cols-3">
{/* Issuance date + validity period + duration */}
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
<div>
<Label className="text-xs">Data emitere AC</Label>
<Input
@@ -299,6 +306,28 @@ export function ACValidityTracker({
className="mt-1"
/>
</div>
<div>
<Label className="text-xs">Perioadă valabilitate</Label>
<Select
value={String(ac.validityMonths ?? 12)}
onValueChange={(v) =>
update({
validityMonths: parseInt(v, 10) as ACValidityPeriod,
})
}
>
<SelectTrigger className="mt-1">
<SelectValue />
</SelectTrigger>
<SelectContent>
{([12, 24] as ACValidityPeriod[]).map((d) => (
<SelectItem key={d} value={String(d)}>
{VALIDITY_LABELS[d]}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
<div>
<Label className="text-xs">Valabilitate până la</Label>
<div className="mt-1 rounded border bg-muted/50 px-3 py-2 text-sm font-mono">
@@ -633,7 +662,7 @@ export function ACValidityTracker({
<span className="text-muted-foreground">
{ac.reminder.dismissed
? "Remindere dezactivate"
: `Reminder lunar activ (luna ${computedData.monthsToValidityEnd > 0 ? 12 - computedData.monthsToValidityEnd : 12}/12)`}
: `Reminder lunar activ (luna ${computedData.monthsToValidityEnd > 0 ? (ac.validityMonths ?? 12) - computedData.monthsToValidityEnd : (ac.validityMonths ?? 12)}/${ac.validityMonths ?? 12})`}
</span>
</div>
<div className="flex gap-1">
@@ -257,6 +257,125 @@ export function DeadlineConfigOverview() {
</div>
</div>
{/* ── Reminder & alert configuration ── */}
<div className="rounded-lg border bg-card">
<div className="flex items-center gap-3 px-4 py-3">
<Timer className="h-4 w-4 text-orange-500" />
<span className="text-sm font-medium">Configurare remindere si alerte</span>
</div>
<Separator />
<div className="px-4 py-3 space-y-4">
<p className="text-xs text-muted-foreground">
Praguri si intervale folosite de sistem pentru a genera alerte si notificari. Valorile se aplica automat tuturor inregistrarilor.
</p>
{/* Thresholds table */}
<div className="overflow-hidden rounded-md border">
<table className="w-full text-xs">
<thead>
<tr className="bg-muted/50">
<th className="px-3 py-2 text-left font-medium">Parametru</th>
<th className="px-3 py-2 text-left font-medium">Valoare</th>
<th className="px-3 py-2 text-left font-medium">Descriere</th>
</tr>
</thead>
<tbody className="divide-y">
<tr>
<td className="px-3 py-2 font-medium">Prag &quot;Urgent&quot;</td>
<td className="px-3 py-2">
<Badge variant="outline" className="bg-yellow-50 text-yellow-700 border-yellow-300 text-[10px] dark:bg-yellow-900/20 dark:text-yellow-300 dark:border-yellow-700">
5 zile
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
Termenele cu 5 sau mai putine zile ramase sunt marcate ca urgente (galben) si incluse in digest-ul zilnic.
</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">Prag &quot;Depasit&quot;</td>
<td className="px-3 py-2">
<Badge variant="outline" className="bg-red-50 text-red-700 border-red-300 text-[10px] dark:bg-red-900/20 dark:text-red-300 dark:border-red-700">
0 zile
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
Termenele depasite (dupa data scadenta) sunt marcate rosu si raportate zilnic pana la rezolvare.
</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">Alerta expirare CU</td>
<td className="px-3 py-2">
<Badge variant="outline" className="bg-amber-50 text-amber-700 border-amber-300 text-[10px] dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-700">
30 zile (implicit)
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
Se poate configura per inregistrare (campul &quot;Zile alerta expirare&quot;). Implicit 30 zile inainte de expirare.
</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">Reminder lunar AC</td>
<td className="px-3 py-2">
<Badge variant="outline" className="bg-indigo-50 text-indigo-700 border-indigo-300 text-[10px] dark:bg-indigo-900/20 dark:text-indigo-300 dark:border-indigo-700">
Lunar
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
In faza de valabilitate AC, se afiseaza reminder lunar. Se poate amana (+1 luna) sau dezactiva (dismiss) per AC.
</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">Cerere prelungire AC</td>
<td className="px-3 py-2">
<Badge variant="outline" className="bg-amber-50 text-amber-700 border-amber-300 text-[10px] dark:bg-amber-900/20 dark:text-amber-300 dark:border-amber-700">
45 zile lucr.
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
Alerta automata: cererea de prelungire trebuie depusa cu minim 45 zile lucratoare inainte de expirarea AC/executiei.
</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">Anuntare lucrari AC</td>
<td className="px-3 py-2">
<Badge variant="outline" className="bg-green-50 text-green-700 border-green-300 text-[10px] dark:bg-green-900/20 dark:text-green-300 dark:border-green-700">
10 zile cal.
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
Lucrarile trebuie anuntate la Primarie si ISC cu minim 10 zile calendaristice inainte de incepere.
</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">Transmitere in termen</td>
<td className="px-3 py-2">
<Badge variant="outline" className="border-dashed text-[10px] text-muted-foreground">
1 zi (fundal)
</Badge>
</td>
<td className="px-3 py-2 text-muted-foreground">
Verificare automata in fundal: actul administrativ trebuie transmis in 1 zi de la emitere. Se creeaza automat la inchidere.
</td>
</tr>
</tbody>
</table>
</div>
{/* Pause/resume info */}
<div className="rounded-md border bg-muted/20 px-3 py-2.5 space-y-1.5">
<p className="text-xs font-medium flex items-center gap-1.5">
<Clock className="h-3.5 w-3.5 text-blue-500" />
Suspendare / reluare termene (clarificari)
</p>
<p className="text-[11px] text-muted-foreground leading-relaxed">
Cand se primeste o solicitare de clarificari (document intrat conex), termenele active ale inregistrarii mama se suspenda automat.
La depunerea completarilor (document iesit conex), termenele se reiau, iar data scadenta se decaleaza cu numarul de zile suspendate.
Suspendarea se poate face si manual din fisa termenului.
</p>
</div>
</div>
</div>
{/* ── Document expiry overview ── */}
<div className="rounded-lg border bg-card">
<div className="flex items-center gap-3 px-4 py-3">
@@ -280,7 +399,7 @@ export function DeadlineConfigOverview() {
<div className="text-xs">
<span className="font-medium">Autorizatie de Construire (AC)</span>
<span className="ml-1 text-muted-foreground">
validitate 12 luni de la emitere, executie 6/12/24/36 luni, prelungire +24 luni.
valabilitate 12 sau 24 luni (configurabil per AC), executie 6/12/24/36 luni, prelungire +24 luni.
Reminder lunar automat (snooze/dismiss disponibil).
</span>
</div>
+4
View File
@@ -226,6 +226,8 @@ export interface ACReminder {
dismissed: boolean;
}
export type ACValidityPeriod = 12 | 24;
/** Full AC validity tracking state */
export interface ACValidityTracking {
/** Whether AC tracking is enabled for this entry */
@@ -234,6 +236,8 @@ export interface ACValidityTracking {
issuanceDate: string;
/** Current phase */
phase: ACPhase;
/** Validity period in months (default 12, can be 24 for special cases) */
validityMonths?: ACValidityPeriod;
/** Execution duration selected (months) */
executionDuration: ACExecutionDuration;
/** Date works were announced to City Hall & ISC */