Files
Anonyme/app/page.tsx
2025-07-29 10:41:21 +02:00

175 lines
6.2 KiB
TypeScript

"use client";
import { useState } from "react";
import { FileUploadComponent } from "./components/FileUploadComponent";
import { EntityMappingTable } from "./components/EntityMappingTable";
import { ProgressBar } from "./components/ProgressBar";
import { useFileHandler } from "./components/FileHandler";
import { useAnonymization } from "./components/AnonymizationLogic";
import { useDownloadActions } from "./components/DownloadActions";
interface EntityMapping {
originalValue: string;
anonymizedValue: string;
entityType: string;
startIndex: number;
endIndex: number;
}
export default function Home() {
const [sourceText, setSourceText] = useState("");
const [outputText, setOutputText] = useState("");
const [uploadedFile, setUploadedFile] = useState<File | null>(null);
const [fileContent, setFileContent] = useState("");
const [error, setError] = useState<string | null>(null);
const [isLoadingFile, setIsLoadingFile] = useState(false);
const [entityMappings, setEntityMappings] = useState<EntityMapping[]>([]);
const [isExampleLoaded, setIsExampleLoaded] = useState(false); // NOUVEAU
const progressSteps = ["Téléversement", "Prévisualisation", "Anonymisation"];
const getCurrentStep = () => {
if (outputText) return 3;
if (uploadedFile || (sourceText && sourceText.trim())) return 2;
return 1;
};
// Fonction pour recommencer (retourner à l'état initial)
const handleRestart = () => {
setSourceText("");
setOutputText("");
setUploadedFile(null);
setFileContent("");
setError(null);
setIsLoadingFile(false);
setEntityMappings([]);
setIsExampleLoaded(false); // NOUVEAU
};
// Hooks personnalisés pour la logique métier
const { handleFileChange } = useFileHandler({
setUploadedFile,
setSourceText,
setFileContent,
setError,
setIsLoadingFile, // Passer le setter
});
const { anonymizeData, isProcessing } = useAnonymization({
sourceText,
fileContent,
uploadedFile,
setOutputText,
setError,
setEntityMappings,
});
const { copyToClipboard, downloadText } = useDownloadActions({ outputText });
return (
<div className="min-h-screen w-full overflow-hidden">
{/* Header */}
<div className="text-[#092727] border-opacity-20">
<div className="max-w-6xl mx-auto px-2 sm:px-4 py-6 sm:py-8">
<h1 className="text-xl sm:text-2xl md:text-3xl lg:text-4xl font-bold text-center mb-2 leading-tight">
OUTIL D&apos;ANONYMISATION DE DONNÉES
</h1>
<p className=" text-center text-sm sm:text-base lg:text-lg px-2">
Protégez vos informations sensibles en quelques clics
</p>
</div>
</div>
{/* Main Content */}
<div className="max-w-6xl mx-auto px-2 sm:px-4 py-4 sm:py-8 space-y-4">
{/* Progress Bar */}
<ProgressBar currentStep={getCurrentStep()} steps={progressSteps} />
{/* Upload Section */}
<div className="bg-white rounded-2xl border border-gray-50 overflow-hidden">
<div className="p-1 sm:p-3">
<FileUploadComponent
uploadedFile={uploadedFile}
handleFileChange={handleFileChange}
sourceText={sourceText}
setSourceText={setSourceText}
setUploadedFile={setUploadedFile}
setFileContent={setFileContent}
onAnonymize={anonymizeData}
isProcessing={isProcessing}
canAnonymize={
uploadedFile !== null ||
Boolean(sourceText && sourceText.trim())
}
isLoadingFile={isLoadingFile}
onRestart={handleRestart}
outputText={outputText}
copyToClipboard={copyToClipboard}
downloadText={downloadText}
isExampleLoaded={isExampleLoaded} // NOUVEAU
setIsExampleLoaded={setIsExampleLoaded} // NOUVEAU
/>
</div>
</div>
{/* Entity Mapping Table - Seulement si outputText existe */}
{outputText && (
<div className="bg-white rounded-2xl border border-gray-100 overflow-hidden">
<div className="p-1 sm:p-3">
<EntityMappingTable mappings={entityMappings} />
</div>
</div>
)}
{/* Error Message - Version améliorée */}
{error && (
<div className="bg-red-50 border border-red-200 rounded-xl p-3 sm:p-4 mx-2 sm:mx-0">
<div className="flex items-start space-x-3">
<svg
className="w-5 h-5 text-red-500 flex-shrink-0 mt-0.5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth={2}
d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<div className="flex-1">
<h3 className="text-red-800 text-sm font-semibold mb-2">
{error.includes("scanné")
? "📄 PDF Scanné Détecté"
: error.includes("HTTP")
? "🚨 Erreur de Traitement"
: "⚠️ Erreur"}
</h3>
<div className="text-red-700 text-xs sm:text-sm leading-relaxed">
{error.split("\n").map((line, index) => (
<div key={index} className={index > 0 ? "mt-2" : ""}>
{line.startsWith("💡") ? (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-3 mt-3">
<div className="text-blue-800 font-medium text-sm">
{line}
</div>
</div>
) : line.startsWith("-") ? (
<div className="ml-4 text-blue-700">{line}</div>
) : (
line
)}
</div>
))}
</div>
</div>
</div>
</div>
)}
</div>
</div>
);
}