feat(registratura): atomic numbering, reserved slots, audit trail, API endpoints + theme toggle animation
Registratura module: - Atomic sequence numbering (BTG-2026-IN-00125 format) via PostgreSQL upsert - Reserved monthly slots (2/company/month) for late registrations - Append-only audit trail with diff tracking - REST API: /api/registratura (CRUD), /api/registratura/reserved, /api/registratura/audit - Auth: NextAuth session + Bearer API key support - New "intern" direction type with UI support (form, filters, table, detail panel) - Prisma models: RegistrySequence, RegistryAudit Theme toggle: - SVG mask-based sun/moon morph with 360° spin animation - Inverted logic (sun in dark mode, moon in light mode) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
import {
|
||||
ArrowDownToLine,
|
||||
ArrowRightLeft,
|
||||
ArrowUpFromLine,
|
||||
Calendar,
|
||||
CheckCircle2,
|
||||
@@ -64,6 +65,12 @@ const DIRECTION_CONFIG = {
|
||||
class:
|
||||
"bg-orange-100 text-orange-800 dark:bg-orange-900/40 dark:text-orange-300",
|
||||
},
|
||||
intern: {
|
||||
label: "Intern",
|
||||
icon: ArrowRightLeft,
|
||||
class:
|
||||
"bg-purple-100 text-purple-800 dark:bg-purple-900/40 dark:text-purple-300",
|
||||
},
|
||||
} as const;
|
||||
|
||||
const STATUS_CONFIG = {
|
||||
@@ -76,6 +83,10 @@ const STATUS_CONFIG = {
|
||||
label: "Închis",
|
||||
class: "bg-gray-100 text-gray-600 dark:bg-gray-800 dark:text-gray-400",
|
||||
},
|
||||
reserved: {
|
||||
label: "Rezervat",
|
||||
class: "bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300",
|
||||
},
|
||||
} as const;
|
||||
|
||||
const RESOLUTION_LABELS: Record<string, string> = {
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
Globe,
|
||||
ArrowDownToLine,
|
||||
ArrowUpFromLine,
|
||||
ArrowRightLeft,
|
||||
HardDrive,
|
||||
FolderOpen,
|
||||
Link2,
|
||||
@@ -554,6 +555,19 @@ export function RegistryEntryForm({
|
||||
<ArrowUpFromLine className="h-4 w-4" />
|
||||
Ieșit
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setDirection("intern")}
|
||||
className={cn(
|
||||
"flex flex-1 items-center justify-center gap-1.5 rounded-md px-3 py-2 text-sm font-medium transition-all",
|
||||
direction === "intern"
|
||||
? "bg-purple-500 text-white shadow-sm"
|
||||
: "text-muted-foreground hover:text-foreground hover:bg-background",
|
||||
)}
|
||||
>
|
||||
<ArrowRightLeft className="h-4 w-4" />
|
||||
Intern
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -41,6 +41,7 @@ export function RegistryFilters({ filters, onUpdate }: RegistryFiltersProps) {
|
||||
<SelectItem value="all">Toate</SelectItem>
|
||||
<SelectItem value="intrat">Intrat</SelectItem>
|
||||
<SelectItem value="iesit">Ieșit</SelectItem>
|
||||
<SelectItem value="intern">Intern</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
@@ -74,6 +75,7 @@ export function RegistryFilters({ filters, onUpdate }: RegistryFiltersProps) {
|
||||
<SelectItem value="all">Toate</SelectItem>
|
||||
<SelectItem value="deschis">Deschis</SelectItem>
|
||||
<SelectItem value="inchis">Închis</SelectItem>
|
||||
<SelectItem value="reserved">Rezervat</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ const COLUMNS: ColumnDef[] = [
|
||||
id: "direction",
|
||||
label: "Dir.",
|
||||
tooltip:
|
||||
"Direcție: Intrat = primit de la terți, Ieșit = trimis către terți",
|
||||
"Direcție: Intrat = primit, Ieșit = trimis, Intern = intern",
|
||||
defaultVisible: true,
|
||||
},
|
||||
{
|
||||
@@ -141,6 +141,7 @@ const STORAGE_KEY = "registratura:visible-columns";
|
||||
const DIRECTION_LABELS: Record<string, string> = {
|
||||
intrat: "Intrat",
|
||||
iesit: "Ieșit",
|
||||
intern: "Intern",
|
||||
};
|
||||
|
||||
function getDocTypeLabel(type: string): string {
|
||||
@@ -152,6 +153,7 @@ function getDocTypeLabel(type: string): string {
|
||||
const STATUS_LABELS: Record<string, string> = {
|
||||
deschis: "Deschis",
|
||||
inchis: "Închis",
|
||||
reserved: "Rezervat",
|
||||
};
|
||||
|
||||
function loadVisibleColumns(): Set<ColumnId> {
|
||||
@@ -327,7 +329,11 @@ export function RegistryTable({
|
||||
<td className="px-3 py-2">
|
||||
<Badge
|
||||
variant={
|
||||
entry.direction === "intrat" ? "default" : "secondary"
|
||||
entry.direction === "intrat"
|
||||
? "default"
|
||||
: entry.direction === "intern"
|
||||
? "outline"
|
||||
: "secondary"
|
||||
}
|
||||
className="text-xs"
|
||||
>
|
||||
@@ -424,9 +430,16 @@ export function RegistryTable({
|
||||
<td className="px-3 py-2">
|
||||
<Badge
|
||||
variant={
|
||||
entry.status === "deschis" ? "default" : "outline"
|
||||
entry.status === "deschis"
|
||||
? "default"
|
||||
: entry.status === "reserved"
|
||||
? "secondary"
|
||||
: "outline"
|
||||
}
|
||||
className="text-xs"
|
||||
className={cn(
|
||||
"text-xs",
|
||||
entry.status === "reserved" && "border-dashed",
|
||||
)}
|
||||
>
|
||||
{STATUS_LABELS[entry.status]}
|
||||
</Badge>
|
||||
|
||||
Reference in New Issue
Block a user