espace-paie-odentas/app/test-signature-verification/page.tsx
odentas d5a110484b feat: Système de vérification de signature électronique avec QR code
- Page publique /verify/[id] affichant Odentas Seal, TSA, certificat
- API /api/signatures/create-verification pour créer preuves
- Générateur PDF de preuve avec QR code (jsPDF)
- Hook useSignatureProof() pour intégration facile
- Table Supabase signature_verifications avec RLS public
- Page de test /test-signature-verification
- Documentation complète du système

Les signataires peuvent scanner le QR code ou visiter l'URL pour vérifier l'authenticité et l'intégrité de leur document signé.
2025-10-29 09:22:01 +01:00

129 lines
4.6 KiB
TypeScript

"use client";
import { useState } from "react";
import { useSignatureProof } from "@/hooks/useSignatureProof";
import { Download, Loader2 } from "lucide-react";
/**
* Page de test du système de vérification de signature
* Route: /test-signature-verification
*/
export default function TestSignatureVerificationPage() {
const { createSignatureProof, isCreating, error } = useSignatureProof();
const [result, setResult] = useState<{
verification_url: string;
qr_code_data_url: string;
proof_pdf_blob: Blob;
} | null>(null);
const handleTest = async () => {
const proof = await createSignatureProof({
document_name: "Contrat CDDU Test - Jean Dupont",
pdf_url: "https://example.com/signed.pdf",
signer_name: "Jean Dupont",
signer_email: "jean.dupont@example.com",
signature_hash: "dafe9a5e258d144190bcf82327ed9dcc80adf96bceceb3f35963d9c362ee594e",
organization_id: "550e8400-e29b-41d4-a716-446655440000", // UUID test
});
if (proof) {
setResult(proof);
}
};
const downloadProof = () => {
if (!result) return;
const url = URL.createObjectURL(result.proof_pdf_blob);
const a = document.createElement("a");
a.href = url;
a.download = "preuve-signature-test.pdf";
a.click();
URL.revokeObjectURL(url);
};
return (
<div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 py-12 px-4">
<div className="max-w-2xl mx-auto">
<div className="bg-white rounded-2xl shadow-xl p-8">
<h1 className="text-3xl font-bold text-slate-900 mb-6">
Test Système de Vérification
</h1>
<button
onClick={handleTest}
disabled={isCreating}
className="w-full px-6 py-3 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
{isCreating ? (
<>
<Loader2 className="w-5 h-5 animate-spin" />
Création en cours...
</>
) : (
"Créer une Preuve de Test"
)}
</button>
{error && (
<div className="mt-4 p-4 bg-red-50 border border-red-200 rounded-lg">
<p className="text-red-900 font-semibold">Erreur</p>
<p className="text-red-700 text-sm">{error}</p>
</div>
)}
{result && (
<div className="mt-6 space-y-4">
<div className="p-4 bg-green-50 border border-green-200 rounded-lg">
<p className="text-green-900 font-semibold mb-2"> Preuve créée !</p>
<div className="space-y-3">
<div>
<p className="text-sm text-green-700 mb-1">URL de vérification :</p>
<a
href={result.verification_url}
target="_blank"
rel="noopener noreferrer"
className="text-sm text-indigo-600 hover:underline break-all"
>
{result.verification_url}
</a>
</div>
<div>
<p className="text-sm text-green-700 mb-2">QR Code :</p>
<img
src={result.qr_code_data_url}
alt="QR Code"
className="w-48 h-48 border-2 border-green-300 rounded-lg"
/>
</div>
<button
onClick={downloadProof}
className="flex items-center gap-2 px-4 py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition-colors"
>
<Download className="w-5 h-5" />
Télécharger le PDF de Preuve
</button>
</div>
</div>
</div>
)}
<div className="mt-8 p-4 bg-slate-50 rounded-lg">
<p className="text-sm text-slate-600">
<strong>Ce test va créer :</strong>
</p>
<ul className="text-sm text-slate-600 mt-2 space-y-1 list-disc list-inside">
<li>Une entrée dans la table <code>signature_verifications</code></li>
<li>Une URL de vérification publique</li>
<li>Un QR code pointant vers cette URL</li>
<li>Un PDF de preuve avec le QR code intégré</li>
</ul>
</div>
</div>
</div>
</div>
);
}