import React, { useEffect, useState } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import api from '../api/axios'; import { toast } from 'sonner'; import { ArrowLeft, Save, FileText, CheckCircle2, Search, Eye, Plus, Trash2, Layers, Sparkles, Settings, ListChecks, Link as LinkIcon, Edit3, X, Palette, Monitor, Smartphone, Bot, Layout, Sliders, Type, ExternalLink, Calendar } from 'lucide-react'; export default function AdminDossierConfig() { const { id } = useParams(); const navigate = useNavigate(); const [dossier, setDossier] = useState(null); const [extractedTexts, setExtractedTexts] = useState([]); const [fieldsList, setFieldsList] = useState([]); const [loading, setLoading] = useState(true); const [searchTerm, setSearchTerm] = useState(''); // UX State: right panel tabs ('ia', 'manual', 'mapped') const [activeTab, setActiveTab] = useState('ia'); // Designer State const [uiConfig, setUiConfig] = useState({ theme: 'modern', background: 'mesh', aiPosition: 'right', aiGreeting: 'Bonjour ! Comment puis-je vous aider a remplir votre dossier ?', aiName: 'Assistant Dossier', aiAvatar: '', showBotIcon: true, fontFamily: 'font-sans', primaryColor: '#6366f1', borderRadius: '12', inputSpacing: 'compact', labelStyle: 'uppercase', glassIntensity: 'medium', isAiEnabled: false, showStepper: false, showProgress: true, allowSaveDraft: true, themePreset: 'royal' }); // Expanded states for accordion-style UX const [expandedExtraction, setExpandedExtraction] = useState(null); const [expandedMappedField, setExpandedMappedField] = useState(null); // Form states const [draftField, setDraftField] = useState(null); const [editDraft, setEditDraft] = useState(null); const [newManualField, setNewManualField] = useState({ label: '', name: `var_m${Date.now().toString().slice(-4)}`, type: 'text', group: 'General', suffix: '', options: '', width: '100', // Default full width style: 'modern', fontSize: 'md', fontWeight: 'bold', borderRadius: 'default', animation: 'none', helpText: '', tooltip: '', validation: { required: true, pattern: '', min: '', max: '' }, conditions: [], // { fieldId: '', operator: 'eq', value: '' } transform: 'none', transformConfig: {} }); const [analyzing, setAnalyzing] = useState(false); useEffect(() => { const fetchData = async () => { try { const dossRes = await api.get('/dossiers'); const found = dossRes.data.find(d => d.id === Number(id)); if (!found) return navigate('/admin/dashboard/dossiers'); setDossier(found); const textRes = await api.get(`/dossiers/${id}/extract-text`); setExtractedTexts(textRes.data); if (found.uiConfig) { setUiConfig(prev => ({ ...prev, ...found.uiConfig })); } if (found.fieldsConfig && Array.isArray(found.fieldsConfig)) { setFieldsList(found.fieldsConfig.map(f => ({ name: f.name, label: f.label, pdfFieldName: f.pdfFieldName || '', type: f.type || 'text', group: f.group || 'General', suffix: f.suffix || '', options: f.options || '', width: f.width || '100', style: f.style || 'modern', fontSize: f.fontSize || 'md', fontWeight: f.fontWeight || 'bold', borderRadius: f.borderRadius || 'default', animation: f.animation || 'none', helpText: f.helpText || '', tooltip: f.tooltip || '', validation: f.validation || { required: true, pattern: '', min: '', max: '' }, conditions: f.conditions || [], transform: f.transform || 'none', transformConfig: f.transformConfig || {} }))); } else { setFieldsList([]); } } catch (error) { console.error(error); toast.error('Erreur lors du chargement.'); } finally { setLoading(false); } }; fetchData(); }, [id, navigate]); // --- IA EXTRACTION HANDLERS --- const handleOpenExtraction = async (text) => { if (expandedExtraction === text) { setExpandedExtraction(null); setDraftField(null); return; } setExpandedExtraction(text); if (uiConfig.isAiEnabled) { setAnalyzing(true); setDraftField({ pdfFieldName: text, label: 'IA Analyse...', name: '', type: 'text', group: 'General' }); try { const { data } = await api.post('/dossiers/ai-analyze', { text }); setDraftField({ ...data, pdfFieldName: text }); } catch { toast.error("Echec de l'IA, passage en mode manuel."); setDraftField({ pdfFieldName: text, label: text.substring(0, 30), name: `var_${Date.now().toString().slice(-4)}`, type: 'text', group: 'General', suffix: '', options: '' }); } finally { setAnalyzing(false); } } else { setDraftField({ pdfFieldName: text, label: text.substring(0, 30), name: `var_${Date.now().toString().slice(-4)}`, type: 'text', group: 'General', suffix: '', options: '', width: '100', style: 'modern', fontSize: 'md', fontWeight: 'bold', borderRadius: 'default', animation: 'none', helpText: '', tooltip: '', validation: { required: true, pattern: '', min: '', max: '' }, conditions: [], transform: 'none', transformConfig: {} }); } }; const handleAddExtraction = () => { if (!draftField.name.trim() || !draftField.label.trim()) { return toast.error("Le label et l'ID sont requis"); } setFieldsList([...fieldsList, draftField]); toast.success("Variable associee !"); setExpandedExtraction(null); setDraftField(null); // Optional: Auto switch to mapped tab after a few to see progress? }; // --- MANUAL FIELD HANDLERS --- const handleAddManualField = () => { if (!newManualField.label.trim()) return toast.error("Le label est requis"); setFieldsList([...fieldsList, { ...newManualField, pdfFieldName: '' }]); setNewManualField({ label: '', name: `var_m${Date.now().toString().slice(-4)}`, type: 'text', group: 'General', suffix: '', options: '', width: '100', style: 'modern', fontSize: 'md', fontWeight: 'bold', borderRadius: 'default', animation: 'none', helpText: '', tooltip: '', validation: { required: true, pattern: '', min: '', max: '' }, conditions: [], transform: 'none', transformConfig: {} }); toast.success("Champ manuel ajoute !"); }; // --- MAPPED FIELDS HANDLERS --- const handleEditMapped = (index, field) => { if (expandedMappedField === index) { setExpandedMappedField(null); setEditDraft(null); } else { setExpandedMappedField(index); setEditDraft({ ...field }); } }; const handleSaveMapped = (index) => { if (!editDraft.label.trim() || !editDraft.name.trim()) return toast.error("Erreur de saisie"); const updated = [...fieldsList]; updated[index] = { ...editDraft }; setFieldsList(updated); setExpandedMappedField(null); setEditDraft(null); toast.success("Mise a jour effectuee"); }; const handleRemoveMapped = (index) => { const list = [...fieldsList]; list.splice(index, 1); setFieldsList(list); if (expandedMappedField === index) { setExpandedMappedField(null); } }; const handleBurstSplit = () => { const field = draftField || editDraft; if (!field || !field.transformConfig?.separator) return; // Original raw text from PDF const rawText = field.pdfFieldName || ""; const parts = rawText.split(field.transformConfig.separator); const newFields = parts .map(p => p.trim()) .filter(p => p.length > 0) .map((part, i) => ({ ...field, // Keep all metadata label: part || `Partie ${i + 1}`, name: `${field.name}_${i + 1}`, // Unique ID transform: 'split', transformConfig: { ...field.transformConfig, index: i // Each child keeps the SAME separator but points to ITS own index } })); if (newFields.length === 0) { toast.error("Impossible de découper : aucun résultat avec ce séparateur."); return; } setFieldsList([...fieldsList, ...newFields]); if (draftField) { setDraftField(null); setExpandedExtraction(null); } else { setEditDraft(null); setExpandedMappedField(null); } toast.success(`${newFields.length} variables intelligentes générées à partir du split !`); }; const handleSaveAll = async () => { const configArray = fieldsList.map(config => ({ ...config, required: true, placeholder: `Saisir ${config.label}...` })); try { await api.put(`/dossiers/${id}/fields`, { fieldsConfig: configArray, uiConfig }); toast.success('Gabarit et design sauvegardes !'); navigate('/admin/dashboard/dossiers'); } catch (error) { console.error(error); toast.error('Echec de la sauvegarde.'); } }; if (loading) return (
); if (!dossier) return null; return (
{/* HEADER MINIMALISTE */}

Atelier de Configuration

Editeur

{dossier.name}

{/* Refined Layout (User Request): - Left Sidebar: PDF Source (Narrow & Fixed) - Main Container: Page Preview (Top) + Config Tools (Bottom) */}
{/* 1. PDF SOURCE SECTION (Full Width Top) */}
PDF Source Gabarit de reference
Lecture Active