Files
Anonyme/app/page.tsx
2025-07-26 21:39:49 +02:00

159 lines
5.4 KiB
TypeScript

"use client";
import { useState } from "react";
import { FileUploadComponent } from "./components/FileUploadComponent";
import { ResultPreviewComponent } from "./components/ResultPreviewComponent";
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";
import { highlightEntities } from "./utils/highlightEntities";
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 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([]);
};
// 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 bg-white w-full">
{/* Header */}
<div className="bg-[#092727] border-b border-white 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-white text-center mb-2 leading-tight">
OUTIL D&apos;ANONYMISATION DE DONNÉES
</h1>
<p className="text-white text-opacity-80 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-4xl 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-100 overflow-hidden">
<div className="p-3 sm:p-6">
<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}
/>
</div>
</div>
{/* Result Preview */}
{outputText && (
<div className="bg-white rounded-2xl border border-gray-100 overflow-hidden">
<div className="p-3 sm:p-6">
<ResultPreviewComponent
outputText={outputText}
copyToClipboard={copyToClipboard}
downloadText={downloadText}
highlightEntities={highlightEntities}
/>
</div>
</div>
)}
{/* Entity Mapping Table */}
{outputText && (
<div className="bg-white rounded-2xl border border-gray-100 overflow-hidden">
<div className="p-3 sm:p-6">
<EntityMappingTable mappings={entityMappings} />
</div>
</div>
)}
{/* Error Message */}
{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-center space-x-2">
<svg
className="w-4 h-4 sm:w-5 sm:h-5 text-red-500 flex-shrink-0"
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>
<p className="text-red-700 text-xs sm:text-sm font-medium break-words">{error}</p>
</div>
</div>
)}
</div>
</div>
);
}