feat(registratura): redesign CU deadline tracking — direction filtering, CJ toggle, auto-track, verification badge

- CU has NO tacit approval on any entry
- Direction-dependent categories: iesiri (CU, Avize, Completari, Urbanism, Autorizare), intrari (Contestatie)
- Rename: Analiza → Urbanism (PUD/PUZ/PUG), Autorizare (AC) → Autorizare (AD/AC)
- Auto-track deadlines: cu-verificare (10zl) created automatically with CU emitere
- CJ toggle: auto-creates arhitect-sef solicita aviz (3zc) + primar emite aviz (5zc)
- Verification badge: after 10 days shows "Nu mai pot returna documentatia"
- Prelungire helper: CU issue date + 6/12/24 month calculator
- cu-prelungire-emitere changed to 30zc (practica administrativa)
- New DeadlineTypeDef fields: autoTrack, directionFilter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
AI Assistant
2026-03-10 18:58:50 +02:00
parent f5ffce2e23
commit b2519a3b9c
5 changed files with 537 additions and 147 deletions
@@ -12,36 +12,39 @@ 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 { Info, Building2, Calendar } from "lucide-react";
import {
DEADLINE_CATALOG,
CATEGORY_LABELS,
getCategoriesForDirection,
getSelectableDeadlines,
} from "../services/deadline-catalog";
import { computeDueDate } from "../services/working-days";
import type { DeadlineCategory, DeadlineTypeDef } from "../types";
import type {
DeadlineCategory,
DeadlineTypeDef,
RegistryDirection,
} from "../types";
interface DeadlineAddDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
entryDate: string;
onAdd: (typeId: string, startDate: string) => void;
direction: RegistryDirection;
/** Callback: typeId, startDate, options (CJ toggle etc.) */
onAdd: (
typeId: string,
startDate: string,
options?: { isCJ?: boolean },
) => void;
}
type Step = "category" | "type" | "date";
const CATEGORIES: DeadlineCategory[] = [
"certificat",
"avize",
"completari",
"analiza",
"autorizare",
"publicitate",
"contestatie",
];
export function DeadlineAddDialog({
open,
onOpenChange,
entryDate,
direction,
onAdd,
}: DeadlineAddDialogProps) {
const [step, setStep] = useState<Step>("category");
@@ -51,10 +54,20 @@ export function DeadlineAddDialog({
null,
);
const [startDate, setStartDate] = useState(entryDate);
const [isCJ, setIsCJ] = useState(false);
// ── Prelungire helper state ──
const [cuIssueDate, setCuIssueDate] = useState("");
const [cuDurationMonths, setCuDurationMonths] = useState<number | null>(null);
const categories = useMemo(
() => getCategoriesForDirection(direction),
[direction],
);
const typesForCategory = useMemo(() => {
if (!selectedCategory) return [];
return DEADLINE_CATALOG.filter((d) => d.category === selectedCategory);
return getSelectableDeadlines(selectedCategory);
}, [selectedCategory]);
const dueDatePreview = useMemo(() => {
@@ -74,11 +87,22 @@ export function DeadlineAddDialog({
});
}, [selectedType, startDate]);
// Compute CU expiry when user uses the prelungire helper
const computedExpiryDate = useMemo(() => {
if (!cuIssueDate || !cuDurationMonths) return null;
const issue = new Date(cuIssueDate);
issue.setMonth(issue.getMonth() + cuDurationMonths);
return issue;
}, [cuIssueDate, cuDurationMonths]);
const handleClose = () => {
setStep("category");
setSelectedCategory(null);
setSelectedType(null);
setStartDate(entryDate);
setIsCJ(false);
setCuIssueDate("");
setCuDurationMonths(null);
onOpenChange(false);
};
@@ -99,18 +123,41 @@ export function DeadlineAddDialog({
if (step === "type") {
setStep("category");
setSelectedCategory(null);
setIsCJ(false);
} else if (step === "date") {
setStep("type");
setSelectedType(null);
setCuIssueDate("");
setCuDurationMonths(null);
}
};
const handleConfirm = () => {
if (!selectedType || !startDate) return;
onAdd(selectedType.id, startDate);
const isCUType =
selectedType.id === "cu-emitere-l50" ||
selectedType.id === "cu-emitere-l350";
onAdd(selectedType.id, startDate, {
isCJ: isCUType ? isCJ : undefined,
});
handleClose();
};
// Apply prelungire helper: set start date from computed expiry
const handleApplyExpiryHelper = () => {
if (computedExpiryDate) {
const y = computedExpiryDate.getFullYear();
const m = String(computedExpiryDate.getMonth() + 1).padStart(2, "0");
const d = String(computedExpiryDate.getDate()).padStart(2, "0");
setStartDate(`${y}-${m}-${d}`);
}
};
const isPrelungireType = selectedType?.id === "cu-prelungire-emitere";
const isCUEmitere =
selectedType?.id === "cu-emitere-l50" ||
selectedType?.id === "cu-emitere-l350";
return (
<Dialog
open={open}
@@ -121,17 +168,20 @@ export function DeadlineAddDialog({
<DialogContent className="sm:max-w-md">
<DialogHeader>
<DialogTitle>
{step === "category" && "Adaugă termen legal — Categorie"}
{step === "category" && "Adauga termen legal — Categorie"}
{step === "type" &&
`Adaugă termen legal — ${selectedCategory ? CATEGORY_LABELS[selectedCategory] : ""}`}
`Adauga termen legal — ${selectedCategory ? CATEGORY_LABELS[selectedCategory] : ""}`}
{step === "date" &&
`Adaugă termen legal — ${selectedType?.label ?? ""}`}
`Adauga termen legal — ${selectedType?.label ?? ""}`}
</DialogTitle>
</DialogHeader>
{/* ── Step 1: Category selection ── */}
{step === "category" && (
<div className="grid gap-2 py-2">
{CATEGORIES.map((cat) => (
{categories.map((cat) => {
const count = getSelectableDeadlines(cat).length;
return (
<button
key={cat}
type="button"
@@ -142,15 +192,50 @@ export function DeadlineAddDialog({
{CATEGORY_LABELS[cat]}
</span>
<Badge variant="outline" className="text-xs">
{DEADLINE_CATALOG.filter((d) => d.category === cat).length}
{count}
</Badge>
</button>
))}
);
})}
{/* Direction info */}
<div className="flex items-start gap-2 mt-2 rounded-lg bg-muted/50 p-2.5">
<Info className="h-3.5 w-3.5 mt-0.5 text-muted-foreground shrink-0" />
<p className="text-[11px] text-muted-foreground">
{direction === "iesit"
? "Categoriile afisate sunt pentru demersuri depuse de noi (iesiri) — termene pe care le urmarim la institutii."
: "Categoriile afisate sunt pentru acte administrative primite (intrari) — termene de contestare/raspuns."}
</p>
</div>
</div>
)}
{/* ── Step 2: Type selection ── */}
{step === "type" && (
<div className="grid gap-2 py-2 max-h-[400px] overflow-y-auto">
<div className="space-y-2 py-2">
{/* CJ toggle for CU category */}
{selectedCategory === "certificat" && (
<label className="flex items-center gap-2 rounded-lg border border-dashed p-2.5 cursor-pointer hover:bg-accent/50 transition-colors">
<input
type="checkbox"
checked={isCJ}
onChange={(e) => setIsCJ(e.target.checked)}
className="h-4 w-4 rounded border-gray-300"
/>
<Building2 className="h-4 w-4 text-muted-foreground" />
<div>
<span className="text-sm font-medium">
Solicitat la Consiliul Judetean
</span>
<p className="text-[10px] text-muted-foreground">
Activeaza sub-termene automate: arhitect-sef solicita aviz
primar (3z) + primar emite aviz (5z)
</p>
</div>
</label>
)}
<div className="grid gap-2 max-h-[400px] overflow-y-auto">
{typesForCategory.map((typ) => (
<button
key={typ.id}
@@ -158,7 +243,7 @@ export function DeadlineAddDialog({
className="rounded-lg border p-3 text-left transition-colors hover:bg-accent"
onClick={() => handleTypeSelect(typ)}
>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-wrap">
<span className="font-medium text-sm">{typ.label}</span>
<Badge variant="outline" className="text-[10px]">
{typ.days}{" "}
@@ -177,7 +262,7 @@ export function DeadlineAddDialog({
variant="outline"
className="text-[10px] text-orange-600"
>
înapoi
inapoi
</Badge>
)}
</div>
@@ -192,10 +277,99 @@ export function DeadlineAddDialog({
</button>
))}
</div>
{/* Info about auto-tracked deadlines for CU */}
{selectedCategory === "certificat" && (
<div className="flex items-start gap-2 rounded-lg bg-blue-50 dark:bg-blue-950/20 border border-blue-200 dark:border-blue-800 p-2.5">
<Info className="h-3.5 w-3.5 mt-0.5 text-blue-600 shrink-0" />
<div className="text-[11px] text-blue-800 dark:text-blue-300">
<p className="font-medium">Termene automate (in fundal):</p>
<p className="mt-0.5">
Verificare cerere CU (10 zile lucr.) se creeaza automat.
Dupa expirare, institutia nu mai poate returna documentatia.
</p>
{isCJ && (
<p className="mt-0.5">
Aviz primar CJ (3z + 5z) se creeaza automat la
bifarea optiunii CJ.
</p>
)}
</div>
</div>
)}
</div>
)}
{/* ── Step 3: Date confirmation + preview ── */}
{step === "date" && selectedType && (
<div className="space-y-4 py-2">
{/* Prelungire helper: compute expiry from CU issue date */}
{isPrelungireType && (
<div className="rounded-lg border border-dashed p-3 space-y-2">
<div className="flex items-center gap-1.5">
<Calendar className="h-3.5 w-3.5 text-muted-foreground" />
<span className="text-xs font-medium">
Calculator data expirare CU
</span>
</div>
<p className="text-[10px] text-muted-foreground">
Introdu data emiterii CU si selecteaza durata de valabilitate
pentru a calcula automat data expirarii.
</p>
<div className="flex gap-2 items-end">
<div className="flex-1">
<Label className="text-[10px]">Data emitere CU</Label>
<Input
type="date"
value={cuIssueDate}
onChange={(e) => setCuIssueDate(e.target.value)}
className="mt-0.5 h-8 text-xs"
/>
</div>
<div className="flex gap-1">
{[6, 12, 24].map((months) => (
<Button
key={months}
type="button"
variant={
cuDurationMonths === months ? "default" : "outline"
}
size="sm"
className="h-8 text-xs px-2"
onClick={() => setCuDurationMonths(months)}
>
{months} luni
</Button>
))}
</div>
</div>
{computedExpiryDate && (
<div className="flex items-center justify-between rounded bg-muted/50 px-2 py-1.5">
<span className="text-xs text-muted-foreground">
Data expirare CU:{" "}
<strong>
{computedExpiryDate.toLocaleDateString("ro-RO", {
day: "2-digit",
month: "2-digit",
year: "numeric",
})}
</strong>
</span>
<Button
type="button"
variant="outline"
size="sm"
className="h-6 text-[10px] px-2"
onClick={handleApplyExpiryHelper}
>
Aplica ca data start
</Button>
</div>
)}
</div>
)}
{/* Start date input */}
<div>
<Label>{selectedType.startDateLabel}</Label>
{selectedType.startDateHint && (
@@ -211,21 +385,22 @@ export function DeadlineAddDialog({
/>
</div>
{/* Due date preview */}
{dueDatePreview && (
<div className="rounded-lg border bg-muted/30 p-3">
<p className="text-xs text-muted-foreground">
{selectedType.isBackwardDeadline
? "Termen limită depunere"
: "Termen limită calculat"}
? "Termen limita depunere"
: "Termen limita calculat"}
</p>
<p className="text-lg font-bold">{dueDatePreview}</p>
<p className="text-xs text-muted-foreground mt-1">
{selectedType.days}{" "}
{selectedType.dayType === "working"
? "zile lucrătoare"
? "zile lucratoare"
: "zile calendaristice"}
{selectedType.isBackwardDeadline
? " ÎNAINTE"
? " INAINTE"
: " de la data start"}
</p>
{selectedType.legalReference && (
@@ -235,23 +410,38 @@ export function DeadlineAddDialog({
)}
</div>
)}
{/* CJ info reminder */}
{isCUEmitere && isCJ && (
<div className="flex items-start gap-2 rounded-lg bg-amber-50 dark:bg-amber-950/20 border border-amber-200 dark:border-amber-800 p-2.5">
<Building2 className="h-3.5 w-3.5 mt-0.5 text-amber-600 shrink-0" />
<p className="text-[11px] text-amber-800 dark:text-amber-300">
Solicitat la CJ se vor crea automat sub-termenele de aviz
primar (3z solicitat + 5z emis).
</p>
</div>
)}
</div>
)}
<DialogFooter className="gap-2 sm:gap-0">
{step !== "category" && (
<Button type="button" variant="outline" onClick={handleBack}>
Înapoi
Inapoi
</Button>
)}
{step === "category" && (
<Button type="button" variant="outline" onClick={handleClose}>
Anulează
Anuleaza
</Button>
)}
{step === "date" && (
<Button type="button" onClick={handleConfirm} disabled={!startDate}>
Adaugă termen
<Button
type="button"
onClick={handleConfirm}
disabled={!startDate}
>
Adauga termen
</Button>
)}
</DialogFooter>
@@ -1,7 +1,7 @@
"use client";
import { useState } from "react";
import { Clock, CheckCircle2, X, History } from "lucide-react";
import { Clock, CheckCircle2, X, History, ShieldCheck, Building2 } from "lucide-react";
import { Badge } from "@/shared/components/ui/badge";
import { Button } from "@/shared/components/ui/button";
import type { TrackedDeadline } from "../types";
@@ -42,6 +42,19 @@ export function DeadlineCard({
const [showAudit, setShowAudit] = useState(false);
const auditLog = deadline.auditLog ?? [];
const isAutoTrack = def?.autoTrack === true;
const isVerificationDeadline = deadline.typeId === "cu-verificare";
const isCJDeadline =
deadline.typeId === "cu-cj-solicitare-aviz" ||
deadline.typeId === "cu-cj-aviz-primar";
// For verification deadlines, check if the 10-day period has passed
const verificationExpired =
isVerificationDeadline &&
deadline.resolution === "pending" &&
status.daysRemaining !== null &&
status.daysRemaining < 0;
return (
<div
className={cn(
@@ -50,12 +63,25 @@ export function DeadlineCard({
)}
>
<div className="flex items-center gap-3">
{isAutoTrack ? (
isCJDeadline ? (
<Building2 className="h-4 w-4 shrink-0 text-amber-500" />
) : (
<ShieldCheck className="h-4 w-4 shrink-0 text-blue-500" />
)
) : (
<Clock className="h-4 w-4 shrink-0 text-muted-foreground" />
)}
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-wrap">
<span className="text-sm font-medium truncate">
{def?.label ?? deadline.typeId}
</span>
{isAutoTrack && (
<Badge variant="outline" className="text-[10px] text-purple-600 border-purple-300">
auto
</Badge>
)}
<Badge
className={cn(
"text-[10px] border-0",
@@ -67,21 +93,30 @@ export function DeadlineCard({
<span className="ml-1">
(
{status.daysRemaining < 0
? `${Math.abs(status.daysRemaining)}z depășit`
? `${Math.abs(status.daysRemaining)}z depasit`
: `${status.daysRemaining}z`}
)
</span>
)}
</Badge>
</div>
{/* Verification badge: institution lost right to return docs */}
{verificationExpired && (
<div className="flex items-center gap-1 mt-1">
<Badge className="text-[10px] border-0 bg-emerald-100 text-emerald-800 dark:bg-emerald-900 dark:text-emerald-200">
<ShieldCheck className="h-3 w-3 mr-0.5" />
Nu mai pot returna documentatia
</Badge>
</div>
)}
<div className="text-xs text-muted-foreground mt-0.5">
{def?.isBackwardDeadline ? "Termen limită" : "Start"}:{" "}
{def?.isBackwardDeadline ? "Termen limita" : "Start"}:{" "}
{formatDate(deadline.startDate)}
{" "}
{def?.isBackwardDeadline ? "Depunere până la" : "Termen"}:{" "}
{" \u2192 "}
{def?.isBackwardDeadline ? "Depunere pana la" : "Termen"}:{" "}
{formatDate(deadline.dueDate)}
{def?.dayType === "working" && (
<span className="ml-1">(zile lucrătoare)</span>
<span className="ml-1">(zile lucratoare)</span>
)}
</div>
</div>
@@ -238,10 +238,52 @@ export function RegistryEntryForm({
const handleAddDeadline = (
typeId: string,
startDate: string,
chainParentId?: string,
options?: { isCJ?: boolean; chainParentId?: string },
) => {
const tracked = createTrackedDeadline(typeId, startDate, chainParentId);
if (tracked) setTrackedDeadlines((prev) => [...prev, tracked]);
const tracked = createTrackedDeadline(
typeId,
startDate,
options?.chainParentId,
);
if (tracked) {
const newDeadlines = [tracked];
// Auto-create verification deadline for CU emitere types
const isCUEmitere =
typeId === "cu-emitere-l50" || typeId === "cu-emitere-l350";
if (isCUEmitere) {
const verification = createTrackedDeadline(
"cu-verificare",
startDate,
);
if (verification) newDeadlines.push(verification);
}
// Auto-create CJ sub-deadlines if CJ toggle is on
if (isCUEmitere && options?.isCJ) {
const cjRequest = createTrackedDeadline(
"cu-cj-solicitare-aviz",
startDate,
);
if (cjRequest) {
newDeadlines.push(cjRequest);
// Chain: primar responds 5 days from when arhitect-sef requests (3 days from start)
const requestDue = new Date(startDate);
requestDue.setDate(requestDue.getDate() + 3);
const y = requestDue.getFullYear();
const m = String(requestDue.getMonth() + 1).padStart(2, "0");
const d = String(requestDue.getDate()).padStart(2, "0");
const cjResponse = createTrackedDeadline(
"cu-cj-aviz-primar",
`${y}-${m}-${d}`,
cjRequest.id,
);
if (cjResponse) newDeadlines.push(cjResponse);
}
}
setTrackedDeadlines((prev) => [...prev, ...newDeadlines]);
}
};
const handleResolveDeadline = (
@@ -1394,6 +1436,7 @@ export function RegistryEntryForm({
open={deadlineAddOpen}
onOpenChange={setDeadlineAddOpen}
entryDate={date}
direction={direction}
onAdd={handleAddDeadline}
/>
@@ -1,14 +1,21 @@
import type { DeadlineTypeDef, DeadlineCategory } from "../types";
import type {
DeadlineTypeDef,
DeadlineCategory,
RegistryDirection,
} from "../types";
export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
// ═══════════════════════════════════════════════════════════════
// CERTIFICAT DE URBANISM
// ═══════════════════════════════════════════════════════════════
// ── Auto-tracked (system creates automatically, not user-selectable) ──
{
id: "cu-verificare",
label: "Verificare cerere CU",
description:
"Structurile de specialitate verifica documentatia depusa. Daca este incompleta sau necorespunzatoare, se restituie in acest termen.",
"Verificare operativa a documentatiei depuse. Dupa acest termen institutia nu mai are dreptul legal sa solicite clarificari sau sa returneze documentatia.",
days: 10,
dayType: "working",
startDateLabel: "Data depunerii cererii",
@@ -16,38 +23,14 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "certificat",
legalReference: "Legea 50/1991, art. 6^1 alin. (1)",
},
{
id: "cu-emitere-l50",
label: "Emitere CU (constructii)",
description:
"Termen de emitere a Certificatului de Urbanism pentru documentatii de constructii. Se aplica avizarea tacita la depasire.",
days: 15,
dayType: "working",
startDateLabel: "Data depunerii cererii",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
category: "certificat",
legalReference: "Legea 50/1991, art. 6^1 alin. (1)",
},
{
id: "cu-emitere-l350",
label: "Emitere CU (urbanism)",
description:
"Termen de emitere a Certificatului de Urbanism pentru documentatii de urbanism (PUG/PUZ/PUD).",
days: 30,
dayType: "calendar",
startDateLabel: "Data depunerii cererii",
requiresCustomStartDate: false,
tacitApprovalApplicable: true,
category: "certificat",
legalReference: "Legea 350/2001, art. 29 alin. (2)",
autoTrack: true,
directionFilter: ["iesit"],
},
{
id: "cu-suport-tehnic",
label: "Suport tehnic interinstitutional",
description:
"Termen in care autoritatile locale acorda suport tehnic de specialitate institutiilor din sistemul de aparare/ordine publica (SNAOPSN) — stabilirea cerintelor urbanistice.",
"Termen in care autoritatile locale acorda suport tehnic de specialitate institutiilor din SNAOPSN — stabilirea cerintelor urbanistice.",
days: 10,
dayType: "working",
startDateLabel: "Data solicitarii",
@@ -56,35 +39,91 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "certificat",
legalReference: "Legea 50/1991, art. 8 alin. (2)",
autoTrack: true,
directionFilter: ["iesit"],
},
// ── CJ sub-deadlines (auto-created when CJ toggle is on) ──
{
id: "cu-cj-solicitare-aviz",
label: "Arhitect-sef solicita aviz primar",
description:
"La depunerea cererii CU la Consiliul Judetean, arhitectul-sef solicita avizul structurii de specialitate a primariei in 3 zile calendaristice.",
days: 3,
dayType: "calendar",
startDateLabel: "Data depunerii cererii CU la CJ",
requiresCustomStartDate: false,
tacitApprovalApplicable: false,
chainNextTypeId: "cu-cj-aviz-primar",
chainNextActionLabel: "Adauga termen emitere aviz primar (5 zile)",
category: "certificat",
legalReference: "Legea 50/1991, art. 4 alin. (1^1)",
autoTrack: true,
directionFilter: ["iesit"],
},
{
id: "cu-prelungire-depunere",
label: "Termen depunere prelungire CU",
id: "cu-cj-aviz-primar",
label: "Primar emite aviz",
description:
"Cererea de prelungire trebuie depusa cu minim 15 zile calendaristice INAINTE de expirarea CU. Se calculeaza inapoi de la data expirarii.",
days: 15,
"Primarul emite avizul structurii de specialitate in 5 zile calendaristice de la solicitarea arhitectului-sef.",
days: 5,
dayType: "calendar",
startDateLabel: "Data expirare CU",
startDateLabel: "Data solicitarii avizului",
requiresCustomStartDate: true,
startDateHint: "Data de expirare a Certificatului de Urbanism",
startDateHint: "Data la care arhitectul-sef a solicitat avizul",
tacitApprovalApplicable: false,
category: "certificat",
isBackwardDeadline: true,
legalReference: "Norme metodologice Legea 50/1991",
legalReference: "Legea 50/1991, art. 4 alin. (1^1)",
autoTrack: true,
directionFilter: ["iesit"],
},
// ── User-selectable CU deadlines ──
{
id: "cu-emitere-l50",
label: "Emitere CU (constructii — L50)",
description:
"Termen de emitere a Certificatului de Urbanism pentru documentatii de constructii. NU se aplica avizarea tacita.",
days: 15,
dayType: "working",
startDateLabel: "Data inregistrarii cererii",
requiresCustomStartDate: false,
tacitApprovalApplicable: false,
category: "certificat",
legalReference: "Legea 50/1991, art. 6^1 alin. (1)",
directionFilter: ["iesit"],
},
{
id: "cu-emitere-l350",
label: "Emitere CU (urbanism — L350)",
description:
"Termen de emitere a Certificatului de Urbanism pentru documentatii de urbanism (PUG/PUZ/PUD). NU se aplica avizarea tacita.",
days: 30,
dayType: "calendar",
startDateLabel: "Data inregistrarii cererii",
requiresCustomStartDate: false,
tacitApprovalApplicable: false,
category: "certificat",
legalReference: "Legea 350/2001, art. 29 alin. (2)",
directionFilter: ["iesit"],
},
{
id: "cu-prelungire-emitere",
label: "Emitere prelungire CU",
description:
"Termen de emitere a prelungirii CU de la depunerea cererii de prelungire.",
days: 15,
"Termen de emitere a prelungirii CU de la depunerea cererii de prelungire. Termen din practica administrativa (nu e explicit in lege).",
days: 30,
dayType: "calendar",
startDateLabel: "Data depunerii cererii de prelungire",
requiresCustomStartDate: true,
startDateHint: "Data la care s-a depus cererea de prelungire a CU",
tacitApprovalApplicable: true,
startDateHint:
"Data la care s-a depus cererea de prelungire a CU",
tacitApprovalApplicable: false,
category: "certificat",
legalReference: "Legea 50/1991, art. 6^1",
legalReference: "Practica administrativa",
directionFilter: ["iesit"],
},
// ═══════════════════════════════════════════════════════════════
@@ -102,6 +141,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (1)",
directionFilter: ["iesit"],
},
{
id: "aviz-urbanism-30",
@@ -115,12 +155,13 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
},
{
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 (care au propriii timpi de evaluare).",
"Actul administrativ de mediu se emite in maximum 15 zile de la data incheierii procedurilor specifice de mediu.",
days: 15,
dayType: "calendar",
startDateLabel: "Data finalizare proceduri mediu",
@@ -129,6 +170,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
},
{
id: "aviz-cultura-comisie",
@@ -143,6 +185,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
},
{
id: "aviz-cultura-mc",
@@ -153,10 +196,12 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
dayType: "working",
startDateLabel: "Data primirii documentatiei complete",
requiresCustomStartDate: true,
startDateHint: "Data la care Min. Culturii a primit documentatia completa",
startDateHint:
"Data la care Min. Culturii a primit documentatia completa",
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3^1)",
directionFilter: ["iesit"],
},
{
id: "aviz-aeronautica",
@@ -170,6 +215,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
},
{
id: "aviz-isu",
@@ -183,6 +229,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
},
{
id: "aviz-transport-eu",
@@ -196,6 +243,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 7 alin. (3)",
directionFilter: ["iesit"],
},
{
id: "aviz-comisie-agenda",
@@ -209,6 +257,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "avize",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
},
{
id: "aviz-comisie-emitere",
@@ -219,10 +268,12 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
dayType: "calendar",
startDateLabel: "Data analizarii in comisie",
requiresCustomStartDate: true,
startDateHint: "Data la care documentatia a fost analizata in comisia de specialitate",
startDateHint:
"Data la care documentatia a fost analizata in comisia de specialitate",
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
},
{
id: "aviz-oportunitate-comisie",
@@ -236,6 +287,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "avize",
legalReference: "Legea 350/2001, art. 32 alin. (1^1)",
directionFilter: ["iesit"],
},
{
id: "aviz-oportunitate-emitere",
@@ -248,9 +300,9 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
requiresCustomStartDate: true,
startDateHint: "Data sedintei comisiei tehnice in care s-a analizat",
tacitApprovalApplicable: false,
chainNextTypeId: undefined,
category: "avize",
legalReference: "Legea 350/2001, art. 32 alin. (1^1)",
directionFilter: ["iesit"],
},
{
id: "aviz-reconfirmare",
@@ -265,6 +317,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
},
{
id: "aviz-primar",
@@ -279,6 +332,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "avize",
legalReference: "Legea 50/1991, art. 4 alin. (1^1)",
directionFilter: ["iesit"],
},
{
id: "aviz-monument-fara-ac",
@@ -289,10 +343,12 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
dayType: "calendar",
startDateLabel: "Data notificarii",
requiresCustomStartDate: true,
startDateHint: "Data la care s-a notificat serviciul deconcentrat de cultura",
startDateHint:
"Data la care s-a notificat serviciul deconcentrat de cultura",
tacitApprovalApplicable: true,
category: "avize",
legalReference: "Legea 50/1991, art. 11 alin. (1)",
directionFilter: ["iesit"],
},
// ═══════════════════════════════════════════════════════════════
@@ -310,6 +366,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "completari",
legalReference: "Norme metodologice Legea 50/1991",
directionFilter: ["iesit"],
},
{
id: "completare-beneficiar-60",
@@ -325,6 +382,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
chainNextActionLabel: "Adauga termen emitere dupa completari (15 zile)",
category: "completari",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
},
{
id: "completare-emitere-15",
@@ -339,6 +397,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: true,
category: "completari",
legalReference: "Legea 350/2001, art. 44 alin. (4)",
directionFilter: ["iesit"],
},
{
id: "completare-ac-beneficiar",
@@ -353,10 +412,11 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "completari",
legalReference: "Legea 50/1991, art. 7 alin. (1^1)",
directionFilter: ["iesit"],
},
// ═══════════════════════════════════════════════════════════════
// ANALIZA
// URBANISM (PUD/PUZ/PUG) — renamed from "Analiza"
// ═══════════════════════════════════════════════════════════════
{
id: "ctatu-analiza",
@@ -368,8 +428,9 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
startDateLabel: "Data depunerii",
requiresCustomStartDate: false,
tacitApprovalApplicable: false,
category: "analiza",
category: "urbanism",
legalReference: "Legea 350/2001",
directionFilter: ["iesit"],
},
{
id: "consiliu-promovare",
@@ -380,8 +441,9 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
startDateLabel: "Data depunerii",
requiresCustomStartDate: false,
tacitApprovalApplicable: false,
category: "analiza",
category: "urbanism",
legalReference: "Legea 350/2001",
directionFilter: ["iesit"],
},
{
id: "consiliu-vot",
@@ -394,12 +456,13 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
requiresCustomStartDate: true,
startDateHint: "Data finalizarii dezbaterii publice",
tacitApprovalApplicable: false,
category: "analiza",
category: "urbanism",
legalReference: "Legea 350/2001",
directionFilter: ["iesit"],
},
// ═══════════════════════════════════════════════════════════════
// AUTORIZARE (AC)
// AUTORIZARE (AD/AC)
// ═══════════════════════════════════════════════════════════════
{
id: "ac-verificare",
@@ -413,6 +476,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "autorizare",
legalReference: "Legea 50/1991, art. 7 alin. (1)",
directionFilter: ["iesit"],
},
{
id: "ac-emitere",
@@ -426,6 +490,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "autorizare",
legalReference: "Legea 50/1991, art. 7 alin. (1)",
directionFilter: ["iesit"],
},
{
id: "ac-emitere-urgenta",
@@ -439,6 +504,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "autorizare",
legalReference: "Legea 50/1991, art. 7 alin. (1^2)",
directionFilter: ["iesit"],
},
{
id: "ac-emitere-agricol",
@@ -452,6 +518,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "autorizare",
legalReference: "Legea 50/1991, art. 7 alin. (1^3)",
directionFilter: ["iesit"],
},
{
id: "ac-prelungire",
@@ -467,6 +534,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
category: "autorizare",
isBackwardDeadline: true,
legalReference: "Legea 50/1991, art. 7 alin. (8)",
directionFilter: ["iesit"],
},
// ═══════════════════════════════════════════════════════════════
@@ -512,12 +580,14 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
dayType: "calendar",
startDateLabel: "Data ultimei publicitati",
requiresCustomStartDate: true,
startDateHint: "Data la care actul a fost adus la cunostinta publicului (ultima operatiune de publicitate: notare in CF, ziar, panou etc.)",
startDateHint:
"Data la care actul a fost adus la cunostinta publicului (ultima operatiune de publicitate: notare in CF, ziar, panou etc.)",
tacitApprovalApplicable: false,
chainNextTypeId: "contestare-ac",
chainNextActionLabel: "Adauga termen contestare in instanta (60 zile)",
category: "contestatie",
legalReference: "Legea 554/2004, art. 7",
directionFilter: ["intrat"],
},
{
id: "contestare-ac",
@@ -528,10 +598,12 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
dayType: "calendar",
startDateLabel: "Data raspuns plangere / expirare termen",
requiresCustomStartDate: true,
startDateHint: "Data primirii raspunsului la plangerea prealabila (sau data la care a expirat termenul de raspuns)",
startDateHint:
"Data primirii raspunsului la plangerea prealabila (sau data la care a expirat termenul de raspuns)",
tacitApprovalApplicable: false,
category: "contestatie",
legalReference: "Legea 50/1991, art. 12",
directionFilter: ["intrat"],
},
{
id: "contestare-urbanism",
@@ -546,6 +618,7 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
tacitApprovalApplicable: false,
category: "contestatie",
legalReference: "Legea 350/2001, art. 64 alin. (3)",
directionFilter: ["intrat"],
},
{
id: "contestare-contraventie",
@@ -556,10 +629,12 @@ export const DEADLINE_CATALOG: DeadlineTypeDef[] = [
dayType: "calendar",
startDateLabel: "Data comunicarii PV",
requiresCustomStartDate: true,
startDateHint: "Data inmanarii sau comunicarii procesului-verbal de contraventie",
startDateHint:
"Data inmanarii sau comunicarii procesului-verbal de contraventie",
tacitApprovalApplicable: false,
category: "contestatie",
legalReference: "OG 2/2001, art. 31 alin. (1)",
directionFilter: ["intrat"],
},
];
@@ -567,12 +642,55 @@ export const CATEGORY_LABELS: Record<DeadlineCategory, string> = {
certificat: "Certificat de Urbanism",
avize: "Avize",
completari: "Completari",
analiza: "Analiza",
autorizare: "Autorizare (AC)",
urbanism: "Urbanism (PUD/PUZ/PUG)",
autorizare: "Autorizare (AD/AC)",
publicitate: "Publicitate / Comunicare",
contestatie: "Contestatie",
};
/** Which categories are shown for each direction */
export const DIRECTION_CATEGORIES: Record<
RegistryDirection,
DeadlineCategory[]
> = {
iesit: ["certificat", "avize", "completari", "urbanism", "autorizare"],
intrat: ["contestatie"],
};
/** Categories always visible regardless of direction */
export const SHARED_CATEGORIES: DeadlineCategory[] = ["publicitate"];
/**
* Get the ordered list of categories for a given direction.
*/
export function getCategoriesForDirection(
direction: RegistryDirection,
): DeadlineCategory[] {
return [...DIRECTION_CATEGORIES[direction], ...SHARED_CATEGORIES];
}
/**
* Get user-selectable deadlines for a category (excludes autoTrack deadlines).
*/
export function getSelectableDeadlines(
category: DeadlineCategory,
): DeadlineTypeDef[] {
return DEADLINE_CATALOG.filter(
(d) => d.category === category && !d.autoTrack,
);
}
/**
* Get auto-track deadlines that should be created automatically.
*/
export function getAutoTrackDeadlines(
category: DeadlineCategory,
): DeadlineTypeDef[] {
return DEADLINE_CATALOG.filter(
(d) => d.category === category && d.autoTrack === true,
);
}
export function getDeadlineType(typeId: string): DeadlineTypeDef | undefined {
return DEADLINE_CATALOG.find((d) => d.id === typeId);
}
+5 -1
View File
@@ -119,7 +119,7 @@ export type DeadlineCategory =
| "certificat"
| "avize"
| "completari"
| "analiza"
| "urbanism"
| "autorizare"
| "publicitate"
| "contestatie";
@@ -140,6 +140,10 @@ export interface DeadlineTypeDef {
legalReference?: string;
category: DeadlineCategory;
isBackwardDeadline?: boolean;
/** If true, this deadline is auto-created by the system (not user-selectable) */
autoTrack?: boolean;
/** Which directions this category/type applies to (undefined = both) */
directionFilter?: RegistryDirection[];
}
/** Audit log entry for deadline changes */