import { useState, useEffect, useRef } from 'react'; import axios from 'axios'; import { Shield, Lock, CheckCircle2, Database, Languages, Fingerprint, Zap, Palette, Upload, Trash2 } from 'lucide-react'; interface EntityMeta { type: string; text: string; score: number; start: number; end: number; } interface RedactResponse { original_text: string; redacted_text: string; detected_language: string; entities: EntityMeta[]; } type Theme = 'premium' | 'light' | 'dark'; const EXAMPLES = [ { id: "PRO-01", label: "Procès Verbal", lang: "fr", text: `PROCÈS-VERBAL DE RÉUNION DE CHANTIER - RÉNOVATION COMPLEXE HÔTELIER\n\nDate : 20 Mars 2026\nLieu : 142 Avenue des Champs-Élysées, 75008 Paris.\n\nPRÉSENTS :\n- M. Alexandre de La Rochefoucauld (Directeur de projet, Groupe Immobilier "Lux-Horizon" - SIRET 321 654 987 00054).\n- Mme Valérie Marchand (Architecte, Cabinet "Marchand & Associés").\n- M. Thomas Dubois (Ingénieur sécurité, joignable au 06.45.12.89.33).\n\nORDRE DU JOUR :\nValidation des acomptes sur l'IBAN FR76 3000 1000 2000 3000 4000 500.` }, { id: "MED-02", label: "Medical Record", lang: "en", text: `CLINICAL DISCHARGE SUMMARY - PATIENT ID: #XP-99021\n\nPATIENT INFORMATION:\nName: Sarah-Jane Montgomery\nDOB: 12/05/1982\nAddress: 1244 North Oak Street, San Francisco, CA 94102\nSSN : 123-45-6789. Email: sj.montgomery@provider.net.` } ]; function App() { const [text, setText] = useState(''); const [language, setLanguage] = useState('auto'); const [theme, setTheme] = useState(() => (localStorage.getItem('pg-theme') as Theme) || 'premium'); const [result, setResult] = useState(null); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const [apiStatus, setApiStatus] = useState<'checking' | 'online' | 'offline'>('online'); const [copied, setCopied] = useState(false); const [isThemeOpen, setIsThemeOpen] = useState(false); const [isLangOpen, setIsLangOpen] = useState(false); const themeRef = useRef(null); const langRef = useRef(null); const fileInputRef = useRef(null); const API_URL = import.meta.env.VITE_API_URL || ''; useEffect(() => { localStorage.setItem('pg-theme', theme); const handleClickOutside = (e: MouseEvent) => { if (themeRef.current && !themeRef.current.contains(e.target as Node)) setIsThemeOpen(false); if (langRef.current && !langRef.current.contains(e.target as Node)) setIsLangOpen(false); }; document.addEventListener('mousedown', handleClickOutside); return () => document.removeEventListener('mousedown', handleClickOutside); }, [theme]); useEffect(() => { const checkStatus = async () => { try { await axios.get(`${API_URL}/api/status`); setApiStatus('online'); } catch (err) { setApiStatus('offline'); } }; checkStatus(); }, [API_URL]); const handleRedact = async () => { if (!text.trim()) return; setLoading(true); setError(null); try { const response = await axios.post(`${API_URL}/api/redact`, { text, language }); setResult(response.data); } catch (err: any) { console.error(err); const msg = err.response?.data?.detail || 'An unexpected error occurred.'; setError(typeof msg === 'string' ? msg : 'Analysis failed. Please try again.'); setTimeout(() => setError(null), 6000); } finally { setTimeout(() => setLoading(false), 400); } }; const themeClasses = { premium: { body: 'bg-slate-50', header: 'bg-white border-slate-200 text-slate-900', panel: 'bg-white border-slate-200', panelHeader: 'bg-slate-50 text-slate-500', input: 'bg-white text-slate-900 placeholder-slate-300', output: 'bg-slate-50 text-slate-800', tag: 'bg-blue-600 text-white shadow-sm', footer: 'bg-slate-100/50 border-slate-200', btn: 'bg-slate-900 hover:bg-black text-white', btnDisabled: 'bg-slate-200 text-slate-400 cursor-not-allowed', itemHover: 'hover:bg-slate-100 text-slate-900', dropdown: 'bg-white border-slate-200 shadow-2xl', itemCard: 'bg-white border-slate-200 text-slate-900 shadow-sm' }, light: { body: 'bg-white', header: 'bg-white border-black text-black', panel: 'bg-white border-black', panelHeader: 'bg-white border-b-black text-black', input: 'bg-white text-black placeholder-gray-300', output: 'bg-white text-black', tag: 'bg-black text-white rounded-none border border-white', footer: 'bg-white border-black', btn: 'bg-black hover:bg-zinc-800 text-white', btnDisabled: 'bg-zinc-100 text-zinc-300 cursor-not-allowed border border-zinc-200', itemHover: 'hover:bg-zinc-100 text-black', dropdown: 'bg-white border-black shadow-xl', itemCard: 'bg-white border-black text-black' }, dark: { body: 'bg-[#020617]', header: 'bg-slate-900/50 border-slate-800 text-white', panel: 'bg-slate-900/30 border-slate-800', panelHeader: 'bg-slate-900/50 text-slate-400', input: 'bg-transparent text-white placeholder-slate-700', output: 'bg-black/20 text-blue-400', tag: 'bg-blue-500 text-black font-black', footer: 'bg-black/40 border-slate-800', btn: 'bg-blue-600 hover:bg-blue-500 text-white shadow-blue-500/20', btnDisabled: 'bg-blue-900/20 text-blue-800 cursor-not-allowed border border-blue-900/30', itemHover: 'hover:bg-slate-800 text-white', dropdown: 'bg-slate-900 border-slate-800 shadow-2xl shadow-black', itemCard: 'bg-slate-900 border-slate-800 text-white shadow-lg shadow-black/20' } }[theme]; return (
{/* HEADER */}

Redac

{apiStatus}
GitHub
{isThemeOpen && (
{['premium', 'light', 'dark'].map((t) => ( ))}
)}
{isLangOpen && (
{['auto', 'en', 'fr'].map((l) => ( ))}
)}
{/* MAIN WORKSPACE */}
{/* PANEL 1: SOURCE */}
Source Document
{const f=e.target.files?.[0]; if(f){const r=new FileReader(); r.onload=(ev)=>setText(ev.target?.result as string); r.readAsText(f);}}} className="hidden" />
{loading &&
} {/* Error Alert */} {error && (

{error}

)}