"use client"; import { useRef, useState } from "react"; import { Plus, Pencil, Trash2, Search, FileText, ExternalLink, Copy, FolderOpen, Wand2, Loader2, } 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 type { CompanyId } from "@/core/auth/types"; import type { WordTemplate, TemplateCategory } from "../types"; import { useTemplates } from "../hooks/use-templates"; import { parsePlaceholdersFromBuffer, parsePlaceholdersFromUrl, } from "../services/placeholder-parser"; const CATEGORY_LABELS: Record = { contract: "Contract", memoriu: "Memoriu tehnic", oferta: "Ofertă", raport: "Raport", cerere: "Cerere", aviz: "Aviz", scrisoare: "Scrisoare", altele: "Altele", }; type ViewMode = "list" | "add" | "edit"; export function WordTemplatesModule() { const { templates, allTemplates, loading, filters, updateFilter, addTemplate, updateTemplate, cloneTemplate, removeTemplate, } = useTemplates(); const [viewMode, setViewMode] = useState("list"); const [editingTemplate, setEditingTemplate] = useState( null, ); const [deletingId, setDeletingId] = useState(null); const handleSubmit = async ( data: Omit, ) => { if (viewMode === "edit" && editingTemplate) { await updateTemplate(editingTemplate.id, data); } else { await addTemplate(data); } setViewMode("list"); setEditingTemplate(null); }; const handleDeleteConfirm = async () => { if (deletingId) { await removeTemplate(deletingId); setDeletingId(null); } }; return (
{/* Stats */}

Total șabloane

{allTemplates.length}

Beletage

{allTemplates.filter((t) => t.company === "beletage").length}

Urban Switch

{allTemplates.filter((t) => t.company === "urban-switch").length}

Studii de Teren

{ allTemplates.filter((t) => t.company === "studii-de-teren") .length }

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

Se încarcă...

) : templates.length === 0 ? (

Niciun șablon găsit. Adaugă primul șablon Word.

) : (
{templates.map((tpl) => (

{tpl.name}

{tpl.description && (

{tpl.description}

)}
{CATEGORY_LABELS[tpl.category]} v{tpl.version} {tpl.clonedFrom && ( Clonă )}
{/* Placeholders display */} {(tpl.placeholders ?? []).length > 0 && (
{(tpl.placeholders ?? []).map((p) => ( {`{{${p}}}`} ))}
)} {tpl.fileUrl && ( Deschide fișier )}
))}
)} )} {(viewMode === "add" || viewMode === "edit") && ( {viewMode === "edit" ? "Editare șablon" : "Șablon nou"} { setViewMode("list"); setEditingTemplate(null); }} /> )} {/* Delete confirmation */} { if (!open) setDeletingId(null); }} > Confirmare ștergere

Ești sigur că vrei să ștergi acest șablon? Acțiunea este ireversibilă.

); } function TemplateForm({ initial, onSubmit, onCancel, }: { initial?: WordTemplate; onSubmit: ( data: Omit, ) => void; onCancel: () => void; }) { const [name, setName] = useState(initial?.name ?? ""); const [description, setDescription] = useState(initial?.description ?? ""); const [category, setCategory] = useState( initial?.category ?? "contract", ); const [fileUrl, setFileUrl] = useState(initial?.fileUrl ?? ""); const [company, setCompany] = useState( initial?.company ?? "beletage", ); const [version, setVersion] = useState(initial?.version ?? "1.0.0"); const [placeholdersText, setPlaceholdersText] = useState( (initial?.placeholders ?? []).join(", "), ); const [parsing, setParsing] = useState(false); const [parseError, setParseError] = useState(null); const fileInputRef = useRef(null); const applyPlaceholders = (found: string[]) => { if (found.length === 0) { setParseError( "Nu s-au găsit placeholder-e de forma {{VARIABILA}} în fișier.", ); return; } setPlaceholdersText(found.join(", ")); setParseError(null); }; const handleFileDetect = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; setParsing(true); setParseError(null); try { const buffer = await file.arrayBuffer(); const found = await parsePlaceholdersFromBuffer(buffer); applyPlaceholders(found); } catch (err) { setParseError( `Eroare la parsare: ${err instanceof Error ? err.message : String(err)}`, ); } finally { setParsing(false); if (fileInputRef.current) fileInputRef.current.value = ""; } }; const handleUrlDetect = async () => { if (!fileUrl) return; setParsing(true); setParseError(null); try { const found = await parsePlaceholdersFromUrl(fileUrl); applyPlaceholders(found); } catch (err) { setParseError( `Nu s-a putut accesa URL-ul (CORS sau rețea): ${err instanceof Error ? err.message : String(err)}`, ); } finally { setParsing(false); } }; return (
{ e.preventDefault(); const placeholders = placeholdersText .split(",") .map((p) => p.trim()) .filter((p) => p.length > 0); onSubmit({ name, description, category, fileUrl, company, version, placeholders, clonedFrom: initial?.clonedFrom, tags: initial?.tags ?? [], visibility: initial?.visibility ?? "all", }); }} className="space-y-4" >
setName(e.target.value)} className="mt-1" required />