159 lines
5.4 KiB
TypeScript
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'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>
|
|
);
|
|
}
|