diff --git a/src/modules/registratura/components/deadline-add-dialog.tsx b/src/modules/registratura/components/deadline-add-dialog.tsx
index 5177f85..38117e9 100644
--- a/src/modules/registratura/components/deadline-add-dialog.tsx
+++ b/src/modules/registratura/components/deadline-add-dialog.tsx
@@ -32,11 +32,11 @@ interface DeadlineAddDialogProps {
direction: RegistryDirection;
/** Document type — filters which deadline categories are available */
documentType?: string;
- /** Callback: typeId, startDate, options (CJ toggle etc.) */
+ /** Callback: typeId, startDate, options (CJ / Comisie toggles etc.) */
onAdd: (
typeId: string,
startDate: string,
- options?: { isCJ?: boolean },
+ options?: { isCJ?: boolean; isComisie?: boolean },
) => void;
}
@@ -58,6 +58,7 @@ export function DeadlineAddDialog({
);
const [startDate, setStartDate] = useState(entryDate);
const [isCJ, setIsCJ] = useState(false);
+ const [isComisie, setIsComisie] = useState(false);
// ── Prelungire helper state ──
const [cuIssueDate, setCuIssueDate] = useState("");
@@ -104,6 +105,7 @@ export function DeadlineAddDialog({
setSelectedType(null);
setStartDate(entryDate);
setIsCJ(false);
+ setIsComisie(false);
setCuIssueDate("");
setCuDurationMonths(null);
onOpenChange(false);
@@ -127,6 +129,7 @@ export function DeadlineAddDialog({
setStep("category");
setSelectedCategory(null);
setIsCJ(false);
+ setIsComisie(false);
} else if (step === "date") {
setStep("type");
setSelectedType(null);
@@ -140,8 +143,10 @@ export function DeadlineAddDialog({
const isCUType =
selectedType.id === "cu-emitere-l50" ||
selectedType.id === "cu-emitere-l350";
+ const isAvizeType = selectedCategory === "avize";
onAdd(selectedType.id, startDate, {
isCJ: isCUType ? isCJ : undefined,
+ isComisie: isAvizeType ? isComisie : undefined,
});
handleClose();
};
@@ -238,6 +243,30 @@ export function DeadlineAddDialog({
)}
+ {/* Comisie toggle for Avize category */}
+ {selectedCategory === "avize" && (
+
+ setIsComisie(e.target.checked)}
+ className="h-4 w-4 rounded border-gray-300"
+ />
+
+
+
+ Necesita analiza in comisie
+
+
+ Cand e activ: institutia poate solicita completari oricand
+ inainte de analiza in comisie. Cand e dezactivat: se creeaza
+ automat limita de 5 zile lucratoare pentru solicitare
+ completari.
+
+
+
+ )}
+
{def?.isBackwardDeadline ? "Termen limita" : "Start"}:{" "}
{formatDate(deadline.startDate)}
diff --git a/src/modules/registratura/components/deadline-resolve-dialog.tsx b/src/modules/registratura/components/deadline-resolve-dialog.tsx
index a80770b..bf93dd6 100644
--- a/src/modules/registratura/components/deadline-resolve-dialog.tsx
+++ b/src/modules/registratura/components/deadline-resolve-dialog.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useState } from 'react';
+import { useState, useMemo } from 'react';
import {
Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter,
} from '@/shared/components/ui/dialog';
@@ -18,9 +18,10 @@ interface DeadlineResolveDialogProps {
onResolve: (resolution: DeadlineResolution, note: string, chainNext: boolean) => void;
}
-const RESOLUTION_OPTIONS: Array<{ value: DeadlineResolution; label: string }> = [
+const ALL_RESOLUTION_OPTIONS: Array<{ value: DeadlineResolution; label: string }> = [
{ value: 'completed', label: 'Finalizat' },
{ value: 'aprobat-tacit', label: 'Aprobat tacit' },
+ { value: 'intrerupt', label: 'Intrerupt (completari solicitate)' },
{ value: 'respins', label: 'Respins' },
{ value: 'anulat', label: 'Anulat' },
];
@@ -32,7 +33,22 @@ export function DeadlineResolveDialog({ open, deadline, onOpenChange, onResolve
if (!deadline) return null;
const def = getDeadlineType(deadline.typeId);
- const hasChain = def?.chainNextTypeId && (resolution === 'completed' || resolution === 'aprobat-tacit');
+
+ // "intrerupt" option only for avize deadlines that have a chain (interruption mechanism)
+ const filteredOptions = useMemo(() => {
+ return ALL_RESOLUTION_OPTIONS.filter((opt) => {
+ if (opt.value === 'intrerupt') {
+ return def?.chainNextTypeId && def?.category === 'avize';
+ }
+ return true;
+ });
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [def?.chainNextTypeId, def?.category]);
+
+ // Chain fires on completed, aprobat-tacit, or intrerupt (for avize interruption)
+ const hasChain = def?.chainNextTypeId && (
+ resolution === 'completed' || resolution === 'aprobat-tacit' || resolution === 'intrerupt'
+ );
const handleResolve = () => {
onResolve(resolution, note, !!hasChain);
@@ -51,16 +67,16 @@ export function DeadlineResolveDialog({ open, deadline, onOpenChange, onResolve
{ if (!o) handleClose(); }}>
- Rezolvă — {def?.label ?? deadline.typeId}
+ Rezolva — {def?.label ?? deadline.typeId}
- Rezoluție
+ Rezolutie
setResolution(v as DeadlineResolution)}>
- {RESOLUTION_OPTIONS.map((opt) => (
+ {filteredOptions.map((opt) => (
{opt.label}
))}
@@ -68,31 +84,44 @@ export function DeadlineResolveDialog({ open, deadline, onOpenChange, onResolve
- Notă (opțional)
+ Nota (optional)
- {hasChain && def?.chainNextActionLabel && (
+ {hasChain && resolution !== 'intrerupt' && def?.chainNextActionLabel && (
- Termen înlănțuit disponibil
+ Termen inlantuit disponibil
- La rezolvare veți fi întrebat dacă doriți: {def.chainNextActionLabel}
+ La rezolvare se va crea automat: {def.chainNextActionLabel}
+
+
+ )}
+
+ {resolution === 'intrerupt' && def?.chainNextTypeId && (
+
+
+ Termen intrerupt — completari solicitate
+
+
+ Termenul initial se intrerupe. Se va crea automat un nou termen de 15 zile
+ calendaristice care incepe de la data depunerii completarilor. Actualizati
+ data start cand completarile sunt depuse.
)}
- Anulează
- Rezolvă
+ Anuleaza
+ Rezolva
diff --git a/src/modules/registratura/components/registry-entry-form.tsx b/src/modules/registratura/components/registry-entry-form.tsx
index 9776d96..a60f580 100644
--- a/src/modules/registratura/components/registry-entry-form.tsx
+++ b/src/modules/registratura/components/registry-entry-form.tsx
@@ -256,7 +256,7 @@ export function RegistryEntryForm({
const handleAddDeadline = (
typeId: string,
startDate: string,
- options?: { isCJ?: boolean; chainParentId?: string },
+ options?: { isCJ?: boolean; isComisie?: boolean; chainParentId?: string },
) => {
const tracked = createTrackedDeadline(
typeId,
@@ -300,6 +300,25 @@ export function RegistryEntryForm({
}
}
+ // Auto-create completari limit for avize (when Comisie toggle is OFF)
+ const addedDef = getDeadlineType(typeId);
+ if (addedDef?.category === "avize" && !options?.isComisie) {
+ const completariLimit = createTrackedDeadline(
+ "aviz-completari-limit",
+ startDate,
+ );
+ if (completariLimit) newDeadlines.push(completariLimit);
+ }
+
+ // Auto-create Cultura Phase 1 (depunere la comisie) when adding cultura-comisie
+ if (typeId === "aviz-cultura-comisie") {
+ const culturaPhase1 = createTrackedDeadline(
+ "aviz-cultura-depunere-comisie",
+ startDate,
+ );
+ if (culturaPhase1) newDeadlines.push(culturaPhase1);
+ }
+
// Auto-create comunicare catre beneficiar for all iesit deadlines
// (legal obligation: institution must communicate on the day of issuance)
if (direction === "iesit") {
@@ -325,7 +344,8 @@ export function RegistryEntryForm({
prev.map((d) => (d.id === resolved.id ? resolved : d)),
);
- if (chainNext) {
+ // Standard chain (completed / aprobat-tacit)
+ if (chainNext && resolution !== "intrerupt") {
const def = getDeadlineType(resolvingDeadline.typeId);
if (def?.chainNextTypeId) {
const resolvedDate = new Date().toISOString().slice(0, 10);
@@ -337,6 +357,34 @@ export function RegistryEntryForm({
if (chained) setTrackedDeadlines((prev) => [...prev, chained]);
}
}
+
+ // Interruption chain — institution requested completions, term interrupted
+ // Creates chained deadline with today as placeholder start date
+ // User must update start date when completions are actually submitted
+ if (resolution === "intrerupt") {
+ const def = getDeadlineType(resolvingDeadline.typeId);
+ if (def?.chainNextTypeId) {
+ const today = new Date().toISOString().slice(0, 10);
+ const chained = createTrackedDeadline(
+ def.chainNextTypeId,
+ today,
+ resolvingDeadline.id,
+ );
+ if (chained) {
+ chained.auditLog = [
+ ...(chained.auditLog ?? []),
+ {
+ action: "modified",
+ timestamp: new Date().toISOString(),
+ detail:
+ "ATENTIE: Actualizati data start cand se depun completarile/clarificarile",
+ },
+ ];
+ setTrackedDeadlines((prev) => [...prev, chained]);
+ }
+ }
+ }
+
setResolvingDeadline(null);
};
diff --git a/src/modules/registratura/services/deadline-catalog.ts b/src/modules/registratura/services/deadline-catalog.ts
index 706539f..560df4d 100644
--- a/src/modules/registratura/services/deadline-catalog.ts
+++ b/src/modules/registratura/services/deadline-catalog.ts
@@ -147,30 +147,89 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
// ═══════════════════════════════════════════════════════════════
// AVIZE
// ═══════════════════════════════════════════════════════════════
+
+ // ── Auto-tracked avize (system creates automatically) ──
+
{
- id: "aviz-ac-15",
- label: "Aviz pt AC (standard)",
+ id: "aviz-completari-limit",
+ label: "Limita solicitare completari (fara comisie)",
description:
- "Termen general de emitere a avizelor si acordurilor necesare Autorizatiei de Construire. Avizul isi pastreaza valabilitatea pe toata durata de valabilitate a CU.",
+ "Dupa primele 5 zile lucratoare de la depunerea documentatiei, institutia avizatoare nu mai are dreptul sa solicite completari. Se aplica doar pentru avize care NU trec prin comisie de specialitate.",
+ days: 5,
+ dayType: "working",
+ startDateLabel: "Data depunerii documentatiei",
+ requiresCustomStartDate: false,
+ tacitApprovalApplicable: false,
+ category: "avize",
+ legalReference: "Norme metodologice Legea 50/1991",
+ autoTrack: true,
+ directionFilter: ["iesit"],
+ },
+ {
+ id: "aviz-emitere-dupa-completari",
+ label: "Emitere aviz dupa completari",
+ description:
+ "Dupa depunerea completarilor/clarificarilor/modificarilor solicitate, institutia are un nou termen maxim de 15 zile calendaristice pentru emiterea (sau respingerea) avizului. Se aplica avizarea tacita.",
days: 15,
dayType: "calendar",
- startDateLabel: "Data depunerii solicitarii",
+ startDateLabel: "Data depunerii completarilor",
+ requiresCustomStartDate: true,
+ startDateHint:
+ "Data la care s-au depus completarile/clarificarile solicitate de institutie (dovada prin comunicare conexa cererii de aviz)",
+ tacitApprovalApplicable: true,
+ category: "avize",
+ legalReference: "Legea 50/1991, art. 7 alin. (1)",
+ autoTrack: true,
+ directionFilter: ["iesit"],
+ },
+ {
+ id: "aviz-cultura-depunere-comisie",
+ label: "Cultura — depunere la comisie",
+ description:
+ "In maximum 30 zile calendaristice de la depunerea documentatiei, aceasta trebuie supusa analizei comisiei nationale/zonale a monumentelor istorice. Se inchide cu eveniment de tip 'Convocare sedinta'.",
+ days: 30,
+ dayType: "calendar",
+ startDateLabel: "Data depunerii documentatiei",
+ requiresCustomStartDate: false,
+ tacitApprovalApplicable: false,
+ category: "avize",
+ legalReference: "Legea 50/1991, art. 7 alin. (3)",
+ autoTrack: true,
+ directionFilter: ["iesit"],
+ },
+
+ // ── User-selectable avize ──
+
+ {
+ id: "aviz-ac-15",
+ label: "Aviz pt AC (standard — L50)",
+ description:
+ "Termen de emitere a avizelor si acordurilor necesare Autorizatiei de Construire (Legea 50). Termenul incepe de la data transmiterii documentatiei (se ataseaza dovada: mail, confirmare primire). Se aplica avizarea tacita daca nu se primeste raspuns sau solicitare de completari.",
+ days: 15,
+ dayType: "calendar",
+ startDateLabel: "Data transmiterii documentatiei",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (1)",
directionFilter: ["iesit"],
},
{
id: "aviz-urbanism-30",
- label: "Aviz pt urbanism (PUG/PUZ/PUD)",
+ label: "Aviz pt urbanism (PUG/PUZ/PUD — L350)",
description:
- "Termen de emitere a avizelor/acordurilor pentru documentatii de urbanism.",
+ "Termen de emitere a avizelor/acordurilor pentru documentatii de urbanism (Legea 350). Termenul incepe de la data transmiterii documentatiei (se ataseaza dovada). Se aplica avizarea tacita daca nu se primeste raspuns sau solicitare de completari.",
days: 30,
dayType: "calendar",
- startDateLabel: "Data depunerii solicitarii",
+ startDateLabel: "Data transmiterii documentatiei",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
@@ -179,28 +238,36 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
id: "aviz-mediu",
label: "Aviz Protectia Mediului",
description:
- "Actul administrativ de mediu se emite in maximum 15 zile de la data incheierii procedurilor specifice de mediu.",
+ "Actul administrativ de mediu se emite in maximum 15 zile calendaristice de la data incheierii procedurilor specifice de mediu. Termenul NU incepe de la depunere, ci de la un eveniment ulterior (sedinta CAT, adresa primita, apel telefonic) care confirma incheierea procedurii. Leaga de un eveniment conex in thread.",
days: 15,
dayType: "calendar",
startDateLabel: "Data finalizare proceduri mediu",
requiresCustomStartDate: true,
- startDateHint: "Data finalizarii procedurii de evaluare de mediu",
+ startDateHint:
+ "Data evenimentului care confirma inchiderea procedurii de mediu (sedinta CAT, adresa primita, apel telefonic). Leaga de un eveniment conex in thread.",
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
},
{
id: "aviz-cultura-comisie",
- label: "Aviz Cultura (dupa comisie)",
+ label: "Aviz Cultura — emitere dupa comisie",
description:
- "Termen de emitere a avizului de la Comisia nationala/zonala a monumentelor istorice, de la data analizarii documentatiei in comisie.",
+ "Faza 2: Termen de 30 zile calendaristice pentru emiterea avizului, care incepe DUPA primirea convocarii sedintei sau evenimentului completari finale. Se creeaza automat si un termen de 30 zile (faza 1) pentru depunerea la comisia de specialitate.",
days: 30,
dayType: "calendar",
- startDateLabel: "Data sedinta comisie",
+ startDateLabel: "Data sedinta comisie / completari finale",
requiresCustomStartDate: true,
- startDateHint: "Data sedintei comisiei monumentelor istorice",
+ startDateHint:
+ "Data sedintei comisiei monumentelor istorice sau data primirii adresei de completari finale",
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
@@ -231,6 +298,9 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
startDateLabel: "Data depunerii documentatiei",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
@@ -245,6 +315,9 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
startDateLabel: "Data depunerii",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
@@ -259,6 +332,9 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
startDateLabel: "Data solicitarii",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
+ chainNextTypeId: "aviz-emitere-dupa-completari",
+ chainNextActionLabel:
+ "Adauga termen emitere dupa completari (15 zile cal.)",
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
diff --git a/src/modules/registratura/services/deadline-service.ts b/src/modules/registratura/services/deadline-service.ts
index 89b474e..7e6d56e 100644
--- a/src/modules/registratura/services/deadline-service.ts
+++ b/src/modules/registratura/services/deadline-service.ts
@@ -94,6 +94,9 @@ export function getDeadlineDisplayStatus(
if (deadline.resolution === "anulat") {
return { label: "Anulat", variant: "gray", daysRemaining: null };
}
+ if (deadline.resolution === "intrerupt") {
+ return { label: "Intrerupt", variant: "yellow", daysRemaining: null };
+ }
return { label: "Finalizat", variant: "gray", daysRemaining: null };
}
diff --git a/src/modules/registratura/types.ts b/src/modules/registratura/types.ts
index 823c526..823d6f1 100644
--- a/src/modules/registratura/types.ts
+++ b/src/modules/registratura/types.ts
@@ -32,6 +32,7 @@ export const DEFAULT_DOCUMENT_TYPES = [
"raport",
"cerere",
"proces-verbal",
+ "convocare-sedinta",
"notificare",
"comunicare",
"apel-telefonic",
@@ -53,6 +54,7 @@ export const DEFAULT_DOC_TYPE_LABELS: Record
= {
raport: "Raport / Studiu",
cerere: "Cerere",
"proces-verbal": "Proces verbal",
+ "convocare-sedinta": "Convocare sedinta",
notificare: "Notificare",
comunicare: "Comunicare",
"apel-telefonic": "Apel telefonic",
@@ -113,7 +115,8 @@ export type DeadlineResolution =
| "completed"
| "aprobat-tacit"
| "respins"
- | "anulat";
+ | "anulat"
+ | "intrerupt";
export type DeadlineCategory =
| "certificat"