"use client"; import { useState, useCallback } from "react"; import Image from "next/image"; import { Button } from "@/components/ui/button"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Badge } from "@/components/ui/badge"; import { Upload, FileText, ShieldCheck, Download, Trash2, AlertCircle, X, Zap, Lock, Shield, Clock, Eye, TestTube, } from "lucide-react"; import PresidioModal from "./components/PresidioModal"; export type PageObject = { pageNumber: number; htmlContent: string; }; interface ProcessedFile { id: string; name: string; status: "processing" | "completed" | "error"; timestamp: Date; originalSize?: string; processedSize?: string; piiCount?: number; errorMessage?: string; processedBlob?: Blob; anonymizedText?: string; } export default function Home() { const [file, setFile] = useState(null); const [isProcessing, setIsProcessing] = useState(false); const [progress, setProgress] = useState(0); const [isDragOver, setIsDragOver] = useState(false); const [history, setHistory] = useState([]); const [error, setError] = useState(null); const [showPresidioModal, setShowPresidioModal] = useState(false); const [anonymizedResult, setAnonymizedResult] = useState<{ text: string; piiCount: number; } | null>(null); const handleFileChange = (e: React.ChangeEvent) => { if (e.target.files?.length) { setFile(e.target.files[0]); setError(null); } }; const handleDrop = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragOver(false); if (e.dataTransfer.files?.length) { setFile(e.dataTransfer.files[0]); setError(null); } }, []); const handleDragOver = useCallback((e: React.DragEvent) => { e.preventDefault(); setIsDragOver(true); }, []); const handleDragLeave = useCallback(() => { setIsDragOver(false); }, []); const formatFileSize = (bytes: number): string => { if (bytes === 0) return "0 Bytes"; const k = 1024; const sizes = ["Bytes", "KB", "MB", "GB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i]; }; const clearFile = () => { setFile(null); setError(null); }; const clearHistory = () => setHistory([]); const removeFromHistory = (id: string) => setHistory((prev) => prev.filter((item) => item.id !== id)); const handleDownloadTxt = (id: string) => { const fileToDownload = history.find((item) => item.id === id); if (!fileToDownload?.processedBlob) return; const url = URL.createObjectURL(fileToDownload.processedBlob); const a = document.createElement("a"); a.href = url; a.download = `anonymized_${fileToDownload.name .split(".") .slice(0, -1) .join(".")}.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); }; const handlePreview = (id: string) => { const fileToPreview = history.find((item) => item.id === id); if (fileToPreview?.anonymizedText && fileToPreview.piiCount !== undefined) { setAnonymizedResult({ text: fileToPreview.anonymizedText, piiCount: fileToPreview.piiCount, }); setShowPresidioModal(true); } }; const getStatusInfo = (item: ProcessedFile) => { switch (item.status) { case "completed": return { icon: , color: "bg-[#061717]", }; case "error": return { icon: , color: "bg-[#F7AB6E]", }; default: return { icon: (
), color: "bg-[#061717]", }; } }; const loadTestDocument = () => { try { // Créer un document de test avec des données PII fictives const testContent = `Rapport pour la société belge "Solution Globale SPRL" (BCE : BE 0987.654.321). Contact principal : M. Luc Dubois, né le 15/03/1975. Son numéro de registre national est le 75.03.15-123.45. Adresse : Avenue des Arts 56, 1000 Bruxelles. Téléphone : +32 470 12 34 56. Email : luc.dubois@solutionglobale.be. Le paiement de la facture a été effectué par carte VISA 4979 1234 5678 9012. Le remboursement sera versé sur le compte IBAN BE12 3456 7890 1234, code SWIFT : GEBABEBB.`; const testBlob = new Blob([testContent], { type: "text/plain" }); const testFile = new File([testBlob], "document-test.txt", { type: "text/plain", }); setFile(testFile); setError(null); } catch { setError("Erreur lors du chargement du document de test"); } }; const processFile = async () => { if (!file) return; setIsProcessing(true); setProgress(0); setError(null); const fileId = `${Date.now()}-${file.name}`; setHistory((prev) => [ { id: fileId, name: file.name, status: "processing", timestamp: new Date(), originalSize: formatFileSize(file.size), }, ...prev, ]); setFile(null); try { const formData = new FormData(); formData.append("file", file); setProgress(25); const response = await fetch("/api/process-document", { method: "POST", body: formData, }); setProgress(75); const result = await response.json(); if (!response.ok) { throw new Error( result.error || "Une erreur est survenue lors du traitement." ); } const { anonymizedText, piiCount } = result; const processedBlob = new Blob([anonymizedText], { type: "text/plain;charset=utf-8", }); setHistory((prev) => prev.map((item) => item.id === fileId ? { ...item, status: "completed", processedSize: formatFileSize(processedBlob.size), piiCount, processedBlob, anonymizedText, } : item ) ); setProgress(100); } catch (err) { const errorMessage = err instanceof Error ? err.message : "Une erreur inconnue est survenue."; setError(errorMessage); setHistory((prev) => prev.map((item) => item.id === fileId ? { ...item, status: "error", errorMessage } : item ) ); } finally { setIsProcessing(false); setTimeout(() => setProgress(0), 1000); } }; return (

LeCercle.IA

Anonymisation • RGPD • Sécurisé

{file ? ( ) : ( )}
{file ? (

{file.name}

{formatFileSize(file.size)}

) : (

Glissez votre document

Ou cliquez ici

)}
{/* Bouton pour charger un document de test */}
{isProcessing && (
Traitement... {Math.round(progress)}%
)} {error && (

{error}

)}
{file && !isProcessing && ( )}
{[ { icon: Shield, title: "RGPD", subtitle: "Conforme" }, { icon: Clock, title: "Rapide", subtitle: "Local" }, { icon: Lock, title: "Sécurisé", subtitle: "Sans Serveur" }, ].map((item, index) => (

{item.title}

{item.subtitle}

))}
{showPresidioModal && ( setShowPresidioModal(false)} /> )}
); }