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 { Textarea } from "@/shared/components/ui/textarea";
import type { import type {
ACValidityTracking, ACValidityTracking,
ACValidityPeriod,
ACExecutionDuration, ACExecutionDuration,
ACPhase, ACPhase,
} from "../types"; } from "../types";
@@ -52,6 +53,11 @@ interface ACValidityTrackerProps {
entryDate: string; entryDate: string;
} }
const VALIDITY_LABELS: Record<ACValidityPeriod, string> = {
12: "12 luni",
24: "24 luni",
};
const EXECUTION_LABELS: Record<ACExecutionDuration, string> = { const EXECUTION_LABELS: Record<ACExecutionDuration, string> = {
6: "6 luni", 6: "6 luni",
12: "12 luni", 12: "12 luni",
@@ -158,9 +164,10 @@ export function ACValidityTracker({
now.setHours(0, 0, 0, 0); now.setHours(0, 0, 0, 0);
const today = now.toISOString().slice(0, 10); 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); const validityEnd = new Date(issuance);
validityEnd.setMonth(validityEnd.getMonth() + 12); validityEnd.setMonth(validityEnd.getMonth() + validityMonths);
const validityEndStr = validityEnd.toISOString().slice(0, 10); const validityEndStr = validityEnd.toISOString().slice(0, 10);
const daysToValidityEnd = daysBetween(today, validityEndStr); const daysToValidityEnd = daysBetween(today, validityEndStr);
const monthsToValidityEnd = monthsBetween(today, validityEndStr); const monthsToValidityEnd = monthsBetween(today, validityEndStr);
@@ -243,10 +250,10 @@ export function ACValidityTracker({
</TooltipTrigger> </TooltipTrigger>
<TooltipContent side="right" className="max-w-sm"> <TooltipContent side="right" className="max-w-sm">
<p className="text-xs"> <p className="text-xs">
Urmărirea completă a ciclului de viață al AC: valabilitate 12 Urmărirea completă a ciclului de viață al AC: valabilitate
luni, anunțare lucrări, documente obligatorii, durată 12 sau 24 luni (configurabil), anunțare lucrări, documente
execuție, prelungire. Conform Legii 50/1991 și normelor obligatorii, durată execuție, prelungire. Conform Legii
aferente. 50/1991 și normelor aferente.
</p> </p>
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
@@ -288,8 +295,8 @@ export function ACValidityTracker({
)} )}
</div> </div>
{/* Issuance date + duration */} {/* Issuance date + validity period + duration */}
<div className="grid gap-3 sm:grid-cols-3"> <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
<div> <div>
<Label className="text-xs">Data emitere AC</Label> <Label className="text-xs">Data emitere AC</Label>
<Input <Input
@@ -299,6 +306,28 @@ export function ACValidityTracker({
className="mt-1" className="mt-1"
/> />
</div> </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> <div>
<Label className="text-xs">Valabilitate până la</Label> <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"> <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"> <span className="text-muted-foreground">
{ac.reminder.dismissed {ac.reminder.dismissed
? "Remindere dezactivate" ? "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> </span>
</div> </div>
<div className="flex gap-1"> <div className="flex gap-1">
@@ -257,6 +257,125 @@ export function DeadlineConfigOverview() {
</div> </div>
</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 ── */} {/* ── Document expiry overview ── */}
<div className="rounded-lg border bg-card"> <div className="rounded-lg border bg-card">
<div className="flex items-center gap-3 px-4 py-3"> <div className="flex items-center gap-3 px-4 py-3">
@@ -280,7 +399,7 @@ export function DeadlineConfigOverview() {
<div className="text-xs"> <div className="text-xs">
<span className="font-medium">Autorizatie de Construire (AC)</span> <span className="font-medium">Autorizatie de Construire (AC)</span>
<span className="ml-1 text-muted-foreground"> <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). Reminder lunar automat (snooze/dismiss disponibil).
</span> </span>
</div> </div>
+4
View File
@@ -226,6 +226,8 @@ export interface ACReminder {
dismissed: boolean; dismissed: boolean;
} }
export type ACValidityPeriod = 12 | 24;
/** Full AC validity tracking state */ /** Full AC validity tracking state */
export interface ACValidityTracking { export interface ACValidityTracking {
/** Whether AC tracking is enabled for this entry */ /** Whether AC tracking is enabled for this entry */
@@ -234,6 +236,8 @@ export interface ACValidityTracking {
issuanceDate: string; issuanceDate: string;
/** Current phase */ /** Current phase */
phase: ACPhase; phase: ACPhase;
/** Validity period in months (default 12, can be 24 for special cases) */
validityMonths?: ACValidityPeriod;
/** Execution duration selected (months) */ /** Execution duration selected (months) */
executionDuration: ACExecutionDuration; executionDuration: ACExecutionDuration;
/** Date works were announced to City Hall & ISC */ /** Date works were announced to City Hall & ISC */