From 3abf0d189c9383a79d731456ec1ace8b13fc45e4 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Sat, 28 Feb 2026 16:33:36 +0200 Subject: [PATCH] feat: Registratura thread explorer, AC validity tracker, interactive I/O toggle + Password Vault rework Registratura improvements: - Thread Explorer: new 'Fire conversatie' tab with timeline view, search, stats, gap tracking (la noi/la institutie), export to text report - Interactive I/O toggle: replaced direction dropdown with visual blue/orange button group (Intrat/Iesit with icons) - Doc type UX: alphabetical sort + immediate selection after adding custom type - AC Validity Tracker: full Autorizatie de Construire lifecycle workflow (12mo validity, execution phases, extension request, required docs checklist, monthly reminders, abandonment/expiry tracking) Password Vault rework (renamed to 'Parole Uzuale' v0.3.0): - New categories: WiFi, Portale Primarii, Avize Online, PIN Semnatura, Software, Hardware (replaced server/database/api) - Category icons (lucide-react) throughout list and form - WiFi QR code dialog with connection string copy - Context-aware form (PIN vs password label, hide email for WiFi/PIN, hide URL for WiFi, hide generator for PIN) - Dynamic stat cards showing top 3 categories by count - Removed encryption banner - Updated i18n, flags, config --- CLAUDE.md | 48 +- ROADMAP.md | 32 +- SESSION-GUIDE.md | 38 +- src/config/flags.ts | 2 +- src/core/i18n/locales/ro.ts | 2 +- .../components/password-vault-module.tsx | 1757 ++++++++++------- src/modules/password-vault/config.ts | 4 +- src/modules/password-vault/types.ts | 9 +- .../components/ac-validity-tracker.tsx | 741 +++++++ .../components/registratura-module.tsx | 9 + .../components/registry-entry-form.tsx | 82 +- .../components/thread-explorer.tsx | 611 ++++++ src/modules/registratura/types.ts | 70 + 13 files changed, 2575 insertions(+), 830 deletions(-) create mode 100644 src/modules/registratura/components/ac-validity-tracker.tsx create mode 100644 src/modules/registratura/components/thread-explorer.tsx diff --git a/CLAUDE.md b/CLAUDE.md index c1189c7..7bb16b1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -96,22 +96,22 @@ legacy/ # Original HTML tools for reference ## Implemented Modules (14/14 — zero placeholders) -| # | Module | Route | Version | Key Features | -| --- | ---------------------- | --------------------- | ------- | --------------------------------------------------------------------------------------------------- | -| 1 | **Dashboard** | `/` | 0.1.0 | KPI cards (6), activity feed (last 20), module grid, external tools | -| 2 | **Email Signature** | `/email-signature` | 0.1.0 | Multi-company branding, address toggle (BTG/US/SDT), live preview, zoom/copy/download | -| 3 | **Word XML Generator** | `/word-xml` | 0.1.0 | Category-based XML gen, simple/advanced mode, ZIP export | +| # | Module | Route | Version | Key Features | +| --- | ---------------------- | --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | **Dashboard** | `/` | 0.1.0 | KPI cards (6), activity feed (last 20), module grid, external tools | +| 2 | **Email Signature** | `/email-signature` | 0.1.0 | Multi-company branding, address toggle (BTG/US/SDT), live preview, zoom/copy/download | +| 3 | **Word XML Generator** | `/word-xml` | 0.1.0 | Category-based XML gen, simple/advanced mode, ZIP export | | 4 | **Registratura** | `/registratura` | 0.2.0 | CRUD registry, dynamic doc types, bidirectional Address Book, threads, backdating, **legal deadline tracking**, recipient registration, document expiry | -| 5 | **Tag Manager** | `/tag-manager` | 0.2.0 | CRUD tags, category/scope/color, US/SDT seeds, mandatory categories, **ManicTime bidirectional sync** | -| 6 | **IT Inventory** | `/it-inventory` | 0.2.0 | Dynamic equipment types, rented status (purple pulse), **42U rack visualization**, type/status/company filters | -| 7 | **Address Book** | `/address-book` | 0.1.0 | CRUD contacts, card grid, vCard export, Registratura reverse lookup, **dynamic types (creatable)** | -| 8 | **Password Vault** | `/password-vault` | 0.2.0 | CRUD credentials, email field, clickable URLs, strength meter, company scope, **AES-256-GCM encryption** | -| 9 | **Mini Utilities** | `/mini-utilities` | 0.1.0 | Text case, char counter, percentage, area converter, U→R, artifact cleaner, MDLPA, PDF reducer, OCR | -| 10 | **Prompt Generator** | `/prompt-generator` | 0.2.0 | Template-driven prompt builder, **18 templates** (14 text + 4 image), search bar, target type filter | -| 11 | **Digital Signatures** | `/digital-signatures` | 0.1.0 | CRUD assets, drag-and-drop file upload, tag chips | -| 12 | **Word Templates** | `/word-templates` | 0.1.0 | Template library, 8 categories, version tracking, .docx placeholder auto-detection | -| 13 | **AI Chat** | `/ai-chat` | 0.2.0 | Multi-provider (OpenAI/Claude/Ollama/demo), **project linking via Tag Manager**, provider status badge | -| 14 | **Hot Desk** | `/hot-desk` | 0.1.0 | 4 desks, week-ahead calendar, room layout (window+door), reserve/cancel | +| 5 | **Tag Manager** | `/tag-manager` | 0.2.0 | CRUD tags, category/scope/color, US/SDT seeds, mandatory categories, **ManicTime bidirectional sync** | +| 6 | **IT Inventory** | `/it-inventory` | 0.2.0 | Dynamic equipment types, rented status (purple pulse), **42U rack visualization**, type/status/company filters | +| 7 | **Address Book** | `/address-book` | 0.1.0 | CRUD contacts, card grid, vCard export, Registratura reverse lookup, **dynamic types (creatable)** | +| 8 | **Password Vault** | `/password-vault` | 0.2.0 | CRUD credentials, email field, clickable URLs, strength meter, company scope, **AES-256-GCM encryption** | +| 9 | **Mini Utilities** | `/mini-utilities` | 0.1.0 | Text case, char counter, percentage, area converter, U→R, artifact cleaner, MDLPA, PDF reducer, OCR | +| 10 | **Prompt Generator** | `/prompt-generator` | 0.2.0 | Template-driven prompt builder, **18 templates** (14 text + 4 image), search bar, target type filter | +| 11 | **Digital Signatures** | `/digital-signatures` | 0.1.0 | CRUD assets, drag-and-drop file upload, tag chips | +| 12 | **Word Templates** | `/word-templates` | 0.1.0 | Template library, 8 categories, version tracking, .docx placeholder auto-detection | +| 13 | **AI Chat** | `/ai-chat` | 0.2.0 | Multi-provider (OpenAI/Claude/Ollama/demo), **project linking via Tag Manager**, provider status badge | +| 14 | **Hot Desk** | `/hot-desk` | 0.1.0 | 4 desks, week-ahead calendar, room layout (window+door), reserve/cancel | ### Registratura — Legal Deadline Tracking (Termene Legale) @@ -245,15 +245,15 @@ src/modules// ## Current Integrations -| Feature | Status | Notes | -| ------------------- | ---------------------- | --------------------------------------------------------------- | -| **Authentik SSO** | ✅ Active | NextAuth v4 + OIDC, group→role/company mapping | -| **PostgreSQL** | ✅ Active | Prisma ORM, `KeyValueStore` model, `/api/storage` route | -| **MinIO** | Client configured | 10.10.10.166:9002, bucket `tools`, adapter pending | -| **AI Chat API** | ✅ Multi-provider | `/api/ai-chat` — OpenAI/Claude/Ollama/demo; needs API key env | -| **Vault Encryption**| ✅ Active | AES-256-GCM server-side, `/api/vault`, ENCRYPTION_SECRET env | -| **ManicTime Sync** | ✅ Implemented | `/api/manictime` — bidirectional Tags.txt sync, needs SMB mount | -| **N8N automations** | Webhook URL configured | For notifications, backups, workflows | +| Feature | Status | Notes | +| -------------------- | ---------------------- | --------------------------------------------------------------- | +| **Authentik SSO** | ✅ Active | NextAuth v4 + OIDC, group→role/company mapping | +| **PostgreSQL** | ✅ Active | Prisma ORM, `KeyValueStore` model, `/api/storage` route | +| **MinIO** | Client configured | 10.10.10.166:9002, bucket `tools`, adapter pending | +| **AI Chat API** | ✅ Multi-provider | `/api/ai-chat` — OpenAI/Claude/Ollama/demo; needs API key env | +| **Vault Encryption** | ✅ Active | AES-256-GCM server-side, `/api/vault`, ENCRYPTION_SECRET env | +| **ManicTime Sync** | ✅ Implemented | `/api/manictime` — bidirectional Tags.txt sync, needs SMB mount | +| **N8N automations** | Webhook URL configured | For notifications, backups, workflows | --- diff --git a/ROADMAP.md b/ROADMAP.md index 8b98ed6..a7066a5 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -30,22 +30,22 @@ ## Current Module Status (after Phase 3 completion) -| # | Module | Version | Status | Remaining Gaps | Future Enhancements | -| --- | ------------------ | ------- | -------- | ----------------------------------------------------- | ------------------------------------------- | -| 1 | Registratura | 0.2.0 | COMPLETE | — | Workflow automation, email integration, OCR | -| 2 | Email Signature | 0.1.0 | COMPLETE | US/SDT addresses may need update | AD sync, branding packs, promo banners | -| 3 | Word XML | 0.1.0 | COMPLETE | — | Schema validator, visual mapper | -| 4 | Digital Signatures | 0.1.0 | COMPLETE | — | Permission layers, document insertion | -| 5 | Password Vault | 0.2.0 | COMPLETE | — | Hardware key, rotation reminders, Passbolt | -| 6 | IT Inventory | 0.2.0 | COMPLETE | — | Network scan import | -| 7 | Address Book | 0.1.0 | COMPLETE | — | Email sync, deduplication | -| 8 | Prompt Generator | 0.2.0 | COMPLETE | — | Prompt scoring, more image templates | -| 9 | Word Templates | 0.1.0 | COMPLETE | No clause library; no Word generation | Diff compare, document generator | -| 10 | Tag Manager | 0.2.0 | COMPLETE | ManicTime needs SMB mount on Docker host | Smart suggestions | -| 11 | Mini Utilities | 0.1.0 | COMPLETE | — | More converters, DWG→DXF | -| 12 | Dashboard | 0.1.0 | COMPLETE | — | Custom dashboards per role | -| 13 | AI Chat | 0.2.0 | COMPLETE | Needs API key env vars for real AI | Streaming, model selector, conversation templates | -| 14 | Hot Desk | 0.1.0 | COMPLETE | — | — | +| # | Module | Version | Status | Remaining Gaps | Future Enhancements | +| --- | ------------------ | ------- | -------- | ---------------------------------------- | ------------------------------------------------- | +| 1 | Registratura | 0.2.0 | COMPLETE | — | Workflow automation, email integration, OCR | +| 2 | Email Signature | 0.1.0 | COMPLETE | US/SDT addresses may need update | AD sync, branding packs, promo banners | +| 3 | Word XML | 0.1.0 | COMPLETE | — | Schema validator, visual mapper | +| 4 | Digital Signatures | 0.1.0 | COMPLETE | — | Permission layers, document insertion | +| 5 | Password Vault | 0.2.0 | COMPLETE | — | Hardware key, rotation reminders, Passbolt | +| 6 | IT Inventory | 0.2.0 | COMPLETE | — | Network scan import | +| 7 | Address Book | 0.1.0 | COMPLETE | — | Email sync, deduplication | +| 8 | Prompt Generator | 0.2.0 | COMPLETE | — | Prompt scoring, more image templates | +| 9 | Word Templates | 0.1.0 | COMPLETE | No clause library; no Word generation | Diff compare, document generator | +| 10 | Tag Manager | 0.2.0 | COMPLETE | ManicTime needs SMB mount on Docker host | Smart suggestions | +| 11 | Mini Utilities | 0.1.0 | COMPLETE | — | More converters, DWG→DXF | +| 12 | Dashboard | 0.1.0 | COMPLETE | — | Custom dashboards per role | +| 13 | AI Chat | 0.2.0 | COMPLETE | Needs API key env vars for real AI | Streaming, model selector, conversation templates | +| 14 | Hot Desk | 0.1.0 | COMPLETE | — | — | **Phases 1–3 COMPLETE (all 42 tasks).** Next: Phase 4 (Quality & Testing). diff --git a/SESSION-GUIDE.md b/SESSION-GUIDE.md index 8323829..ea58495 100644 --- a/SESSION-GUIDE.md +++ b/SESSION-GUIDE.md @@ -6,24 +6,25 @@ ## Repository URLs -| Access | Git Clone URL | Web UI | -|---|---|---| -| **Internal (office)** | `http://10.10.10.166:3002/gitadmin/ArchiTools.git` | http://10.10.10.166:3002/gitadmin/ArchiTools | -| **External (internet)** | `https://git.beletage.ro/gitadmin/ArchiTools.git` | https://git.beletage.ro/gitadmin/ArchiTools | +| Access | Git Clone URL | Web UI | +| ----------------------- | -------------------------------------------------- | -------------------------------------------- | +| **Internal (office)** | `http://10.10.10.166:3002/gitadmin/ArchiTools.git` | http://10.10.10.166:3002/gitadmin/ArchiTools | +| **External (internet)** | `https://git.beletage.ro/gitadmin/ArchiTools.git` | https://git.beletage.ro/gitadmin/ArchiTools | ### Raw File URLs (for AI tools that can fetch URLs) Replace `{GITEA}` with whichever base works for you: + - Internal: `http://10.10.10.166:3002` - External: `https://git.beletage.ro` -| File | URL | -|---|---| -| CLAUDE.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/CLAUDE.md` | -| ROADMAP.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/ROADMAP.md` | -| SESSION-LOG.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/SESSION-LOG.md` | +| File | URL | +| ---------------- | -------------------------------------------------------------- | +| CLAUDE.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/CLAUDE.md` | +| ROADMAP.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/ROADMAP.md` | +| SESSION-LOG.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/SESSION-LOG.md` | | SESSION-GUIDE.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/SESSION-GUIDE.md` | -| QA-CHECKLIST.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/QA-CHECKLIST.md` | +| QA-CHECKLIST.md | `{GITEA}/gitadmin/ArchiTools/raw/branch/main/QA-CHECKLIST.md` | **Production app:** http://10.10.10.166:3000 @@ -187,25 +188,32 @@ Run `npx next build`, push to main, update ROADMAP.md + SESSION-LOG.md, notify m ## Tool-Specific Notes ### Claude Code (CLI) + Works natively. Clone/pull, read files, edit, build, push — all built in. ### ChatGPT Codex + Give it the repo URL. It can clone via git, read files, and push. Use the external URL: `https://git.beletage.ro/gitadmin/ArchiTools.git` ### VS Code + Copilot / Cursor / Windsurf + Clone the repo locally first, then open in the IDE. The AI agent reads files from disk. + ```bash git clone https://git.beletage.ro/gitadmin/ArchiTools.git cd ArchiTools && npm install && code . ``` ### Google Antigravity + Give it the repo URL. It can clone and work autonomously. Use: `https://git.beletage.ro/gitadmin/ArchiTools.git` ### Phone (ChatGPT app, Claude app) + Can't run code directly, but can read files via raw URLs and give guidance: + ``` Read these URLs and help me plan the next task: https://git.beletage.ro/gitadmin/ArchiTools/raw/branch/main/CLAUDE.md @@ -218,6 +226,7 @@ https://git.beletage.ro/gitadmin/ArchiTools/raw/branch/main/SESSION-LOG.md ## Git Workflow ### First time (any device) + ```bash git clone https://git.beletage.ro/gitadmin/ArchiTools.git cd ArchiTools @@ -226,12 +235,14 @@ npm run dev ``` ### Session start (pull latest) + ```bash git pull origin main npm install ``` ### Session end (push) + ```bash npx next build git add @@ -246,26 +257,33 @@ git push origin main ## Files to Update After Every Session ### 1. `ROADMAP.md` — Mark done tasks + ```markdown ### 1.01 ✅ (2026-02-18) `[LIGHT]` Verify Email Signature Logo Files ``` ### 2. `SESSION-LOG.md` — Add entry at the TOP + ```markdown ## Session — 2026-02-18 (Sonnet 4.6) ### Completed + - 1.01: Verified logo files - 1.02: Added address toggle ### In Progress + - 1.03: Prompt templates — 4 of 10 done ### Blockers + - Need logo files from user ### Notes + - Build passes, commit abc1234 + --- ``` diff --git a/src/config/flags.ts b/src/config/flags.ts index 357cf18..4ae16fd 100644 --- a/src/config/flags.ts +++ b/src/config/flags.ts @@ -45,7 +45,7 @@ export const DEFAULT_FLAGS: FeatureFlag[] = [ { key: "module.password-vault", enabled: true, - label: "Seif Parole", + label: "Parole Uzuale", description: "Depozit intern de credențiale", category: "module", overridable: true, diff --git a/src/core/i18n/locales/ro.ts b/src/core/i18n/locales/ro.ts index 3fbbe0d..08e7e40 100644 --- a/src/core/i18n/locales/ro.ts +++ b/src/core/i18n/locales/ro.ts @@ -79,7 +79,7 @@ export const ro: Labels = { description: "Bibliotecă semnături digitale și ștampile scanate", }, "password-vault": { - title: "Seif Parole", + title: "Parole Uzuale", description: "Depozit intern de credențiale partajate", }, "it-inventory": { diff --git a/src/modules/password-vault/components/password-vault-module.tsx b/src/modules/password-vault/components/password-vault-module.tsx index fba5b2c..b901c4d 100644 --- a/src/modules/password-vault/components/password-vault-module.tsx +++ b/src/modules/password-vault/components/password-vault-module.tsx @@ -1,757 +1,1000 @@ -"use client"; - -import { useState } from "react"; -import { - Plus, - Pencil, - Trash2, - Search, - Eye, - EyeOff, - Copy, - ExternalLink, - KeyRound, - X, -} from "lucide-react"; -import { Button } from "@/shared/components/ui/button"; -import { Input } from "@/shared/components/ui/input"; -import { Label } from "@/shared/components/ui/label"; -import { Textarea } from "@/shared/components/ui/textarea"; -import { Badge } from "@/shared/components/ui/badge"; -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "@/shared/components/ui/card"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/shared/components/ui/select"; -import { - Dialog, - DialogContent, - DialogHeader, - DialogTitle, - DialogFooter, -} from "@/shared/components/ui/dialog"; -import { Switch } from "@/shared/components/ui/switch"; -import type { CompanyId } from "@/core/auth/types"; -import type { VaultEntry, VaultEntryCategory, CustomField } from "../types"; -import { useVault } from "../hooks/use-vault"; - -const CATEGORY_LABELS: Record = { - web: "Web", - email: "Email", - server: "Server", - database: "Bază de date", - api: "API", - other: "Altele", -}; - -const COMPANY_LABELS: Record = { - beletage: "Beletage", - "urban-switch": "Urban Switch", - "studii-de-teren": "Studii de Teren", - group: "Grup", -}; - -/** Calculate password strength: 0-3 (weak, medium, strong, very strong) */ -function getPasswordStrength(pwd: string): { - level: 0 | 1 | 2 | 3; - label: string; - color: string; -} { - if (!pwd) return { level: 0, label: "Nicio parolă", color: "bg-gray-300" }; - const len = pwd.length; - const hasUpper = /[A-Z]/.test(pwd); - const hasLower = /[a-z]/.test(pwd); - const hasDigit = /\d/.test(pwd); - const hasSymbol = /[!@#$%^&*()\-_=+\[\]{}|;:,.<>?]/.test(pwd); - const varietyScore = - (hasUpper ? 1 : 0) + - (hasLower ? 1 : 0) + - (hasDigit ? 1 : 0) + - (hasSymbol ? 1 : 0); - const score = len + varietyScore * 2; - if (score < 8) return { level: 0, label: "Slabă", color: "bg-red-500" }; - if (score < 16) return { level: 1, label: "Medie", color: "bg-yellow-500" }; - if (score < 24) - return { level: 2, label: "Puternică", color: "bg-green-500" }; - return { level: 3, label: "Foarte puternică", color: "bg-emerald-600" }; -} - -type ViewMode = "list" | "add" | "edit"; - -/** Generate a random password */ -function generatePassword( - length: number, - options: { - upper: boolean; - lower: boolean; - digits: boolean; - symbols: boolean; - }, -): string { - let chars = ""; - if (options.upper) chars += "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - if (options.lower) chars += "abcdefghijklmnopqrstuvwxyz"; - if (options.digits) chars += "0123456789"; - if (options.symbols) chars += "!@#$%^&*()-_=+[]{}|;:,.<>?"; - if (!chars) - chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - let result = ""; - for (let i = 0; i < length; i++) { - result += chars.charAt(Math.floor(Math.random() * chars.length)); - } - return result; -} - -export function PasswordVaultModule() { - const { - entries, - allEntries, - loading, - filters, - updateFilter, - addEntry, - updateEntry, - removeEntry, - } = useVault(); - const [viewMode, setViewMode] = useState("list"); - const [editingEntry, setEditingEntry] = useState(null); - const [visiblePasswords, setVisiblePasswords] = useState>( - new Set(), - ); - const [copiedId, setCopiedId] = useState(null); - const [deletingId, setDeletingId] = useState(null); - - const togglePassword = (id: string) => { - setVisiblePasswords((prev) => { - const next = new Set(prev); - if (next.has(id)) next.delete(id); - else next.add(id); - return next; - }); - }; - - const handleCopy = async (text: string, id: string) => { - try { - await navigator.clipboard.writeText(text); - setCopiedId(id); - setTimeout(() => setCopiedId(null), 2000); - } catch { - /* silent */ - } - }; - - const handleSubmit = async ( - data: Omit, - ) => { - if (viewMode === "edit" && editingEntry) { - await updateEntry(editingEntry.id, data); - } else { - await addEntry(data); - } - setViewMode("list"); - setEditingEntry(null); - }; - - const handleDeleteConfirm = async () => { - if (deletingId) { - await removeEntry(deletingId); - setDeletingId(null); - } - }; - - return ( -
-
- Parolele sunt criptate (AES-256-GCM) pe server înainte de stocare. - Datele sunt protejate la rest în baza de date. -
- - {/* Stats */} -
- - -

Total

-

{allEntries.length}

-
-
- - -

Web

-

- {allEntries.filter((e) => e.category === "web").length} -

-
-
- - -

Server

-

- {allEntries.filter((e) => e.category === "server").length} -

-
-
- - -

API

-

- {allEntries.filter((e) => e.category === "api").length} -

-
-
-
- - {viewMode === "list" && ( - <> -
-
- - updateFilter("search", e.target.value)} - className="pl-9" - /> -
- - -
- - {loading ? ( -

- Se încarcă... -

- ) : entries.length === 0 ? ( -

- Nicio intrare găsită. -

- ) : ( -
- {entries.map((entry) => ( - - -
-
-

{entry.label}

- - {CATEGORY_LABELS[entry.category]} - -
-

- {entry.username} - {entry.email && ( - - ({entry.email}) - - )} -

-
- - {visiblePasswords.has(entry.id) - ? entry.password - : "••••••••••"} - - - - {copiedId === entry.id && ( - - Copiat! - - )} -
- {entry.url && ( - e.stopPropagation()} - > - {entry.url} - - )} - {entry.customFields && entry.customFields.length > 0 && ( -
- {entry.customFields.map((cf, i) => ( - - {cf.key}: {cf.value} - - ))} -
- )} -
-
- - -
-
-
- ))} -
- )} - - )} - - {(viewMode === "add" || viewMode === "edit") && ( - - - - {viewMode === "edit" ? "Editare" : "Intrare nouă"} - - - - { - setViewMode("list"); - setEditingEntry(null); - }} - /> - - - )} - - {/* Delete confirmation */} - { - if (!open) setDeletingId(null); - }} - > - - - Confirmare ștergere - -

- Ești sigur că vrei să ștergi această intrare? Acțiunea este - ireversibilă. -

- - - - -
-
-
- ); -} - -function VaultForm({ - initial, - onSubmit, - onCancel, -}: { - initial?: VaultEntry; - onSubmit: (data: Omit) => void; - onCancel: () => void; -}) { - const [label, setLabel] = useState(initial?.label ?? ""); - const [username, setUsername] = useState(initial?.username ?? ""); - const [email, setEmail] = useState(initial?.email ?? ""); - const [password, setPassword] = useState(initial?.password ?? ""); - const [url, setUrl] = useState(initial?.url ?? ""); - const [category, setCategory] = useState( - initial?.category ?? "web", - ); - const [company, setCompany] = useState( - initial?.company ?? "beletage", - ); - const [notes, setNotes] = useState(initial?.notes ?? ""); - const [customFields, setCustomFields] = useState( - initial?.customFields ?? [], - ); - - // Password generator state - const [genLength, setGenLength] = useState(16); - const [genUpper, setGenUpper] = useState(true); - const [genLower, setGenLower] = useState(true); - const [genDigits, setGenDigits] = useState(true); - const [genSymbols, setGenSymbols] = useState(true); - - const strength = getPasswordStrength(password); - - const handleGenerate = () => { - setPassword( - generatePassword(genLength, { - upper: genUpper, - lower: genLower, - digits: genDigits, - symbols: genSymbols, - }), - ); - }; - - const addCustomField = () => { - setCustomFields([...customFields, { key: "", value: "" }]); - }; - - const updateCustomField = ( - index: number, - field: keyof CustomField, - value: string, - ) => { - setCustomFields( - customFields.map((cf, i) => - i === index ? { ...cf, [field]: value } : cf, - ), - ); - }; - - const removeCustomField = (index: number) => { - setCustomFields(customFields.filter((_, i) => i !== index)); - }; - - return ( -
{ - e.preventDefault(); - onSubmit({ - label, - username, - email, - password, - url, - category, - company, - notes, - customFields: customFields.filter((cf) => cf.key.trim()), - tags: initial?.tags ?? [], - visibility: initial?.visibility ?? "admin", - }); - }} - className="space-y-4" - > -
-
- - setLabel(e.target.value)} - className="mt-1" - required - /> -
-
- - -
-
-
-
- - -
-
- - setUsername(e.target.value)} - className="mt-1" - /> -
-
-
- - setEmail(e.target.value)} - className="mt-1" - placeholder="utilizator@exemplu.ro" - /> -
-
- -
- setPassword(e.target.value)} - className="flex-1 font-mono text-sm" - /> - -
- {password && ( -
-
- Forță: - - {strength.label} - -
-
-
-
-
- )} -
- - {/* Password generator options */} -
-

- Generator parolă -

-
-
- - setGenLength(parseInt(e.target.value, 10) || 8)} - className="w-16 text-sm" - min={4} - max={64} - /> -
-
- - -
-
- - -
-
- - -
-
- - -
- -
-
- -
- - setUrl(e.target.value)} - className="mt-1" - placeholder="https://..." - /> -
- - {/* Custom fields */} -
-
- - -
- {customFields.length > 0 && ( -
- {customFields.map((cf, i) => ( -
- updateCustomField(i, "key", e.target.value)} - className="w-[140px] text-sm" - /> - - updateCustomField(i, "value", e.target.value) - } - className="flex-1 text-sm" - /> - -
- ))} -
- )} -
- -
- -