| Server IP : 54.37.205.81 / Your IP : 216.73.216.76 Web Server : nginx/1.22.1 System : Linux vps-249481fa 6.1.0-50-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64 User : debian ( 1000) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/app.copyrightchain.it/copyrightchain_app/components/ |
Upload File : |
import React, { useState, useRef, useEffect, useMemo } from 'react';
import { Download, Printer, Shield, CheckCircle, Share2, FileText, Calendar, User, Hash, Loader2, ListChecks, History, Fingerprint, Award, AlertCircle, RefreshCcw, Clock, Stamp, Sparkles, X, Cpu, ExternalLink, Link as LinkIcon, EyeOff, Archive, Package, RefreshCw, Box, Building2 } from 'lucide-react';
import { Certificate, Language } from '../types';
import { translations } from '../translations';
import html2canvas from 'html2canvas';
import { jsPDF } from 'jspdf';
import QRCode from 'qrcode';
import { useNotification } from '../App';
import { PDFDocument, rgb } from 'pdf-lib';
import { usePersistedState } from '../hooks/usePersistedState';
const ABO_FOOTER_TEXT = 'ABO BANK Legal Office, Department of Intellectual Property and Copyright - Bank Association Offshore 1001 Third Avenue W, Suite 190, Bradenton, FL 34205 21. ABO BANK Harley Street, London, England, United Kingdom, W1G 9QD . Associazione Banche Offshore Corso Venezia 1 Milano Incorporata Codice Fiscale 92034960457';
const DEFAULT_CC_LOGO_URL = '/copyrightchain-logo.png';
interface CertificateViewProps {
certificate: Certificate;
lang: Language;
clientToken: string | null;
}
const CertificateView: React.FC<CertificateViewProps> = ({ certificate, lang, clientToken }) => {
const t = useMemo(() => translations[lang], [lang]);
const { notify } = useNotification();
const [isGeneratingPDF, setIsGeneratingPDF] = useState(false);
const [isGeneratingStamp, setIsGeneratingStamp] = useState(false);
const [qrCodeUrl, setQrCodeUrl] = useState<string>('');
const [isBundling, setIsBundling] = useState(false);
const [publicVerifyData, setPublicVerifyData] = useState<any>(null);
const certificateRef = useRef<HTMLDivElement>(null);
const stampPreviewRef = useRef<HTMLDivElement>(null);
const certAny = certificate as any;
const timestampEvidence = (certAny.timestampEvidence || {}) as any;
const isTimestampCert =
String(certificate.tier || '').toLowerCase() === 'timestamp' ||
Boolean(timestampEvidence.status || timestampEvidence.provider || timestampEvidence.transaction || timestampEvidence.issuedAt || timestampEvidence.bodyUrl);
const formatInfoCertStampDate = (value: any) => {
if (!value) return 'data marca disponibile';
const d = new Date(String(value));
if (Number.isNaN(d.getTime())) return String(value);
const pad = (n: number) => String(n).padStart(2, '0');
return `${pad(d.getUTCDate())}/${pad(d.getUTCMonth() + 1)}/${d.getUTCFullYear()} ore ${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())} UTC`;
};
const publicAny = publicVerifyData || {};
const verifyUrl =
(certAny.verifyUrl && String(certAny.verifyUrl).trim()) ||
(certificate.legalAttestation && String(certificate.legalAttestation).match(/https?:\/\/\S+/)?.[0]) ||
`https://copyrightchain.it/verifica-certificato/?id=${encodeURIComponent(certificate.id || "")}&hash=${encodeURIComponent(certificate.fileHash || certificate.hash || "")}`;
const otsProofUrl = String(certAny.otsProofUrl || '').trim();
const otsManifestUrl = String(certAny.otsManifestUrl || '').trim();
const anchoredAt = String(certAny.anchoredAt || '').trim();
const confirmedAt = String(certAny.confirmedAt || '').trim();
// Branding: persisted (non-sensitive) settings.
const [branding] = usePersistedState('cc_branding', {
companyName: 'ABO BANK LEGAL DIVISION',
logoUrl: '',
vatNumber: '',
footerText: 'Documento tecnico di certificazione digitale emesso da CopyrightChain. Il certificato documenta hash, data di deposito, verifica pubblica e dati tecnici associati.',
});
const officialLogoUrl = (String((branding as any).logoUrl || '').trim()) || DEFAULT_CC_LOGO_URL;
const rawVideoRetained = certAny.videoRetainedByPlatform ?? certAny.video_retained_by_platform ?? publicAny.video_retained_by_platform ?? false;
const videoRetainedByPlatform = rawVideoRetained === true || String(rawVideoRetained).toLowerCase() === 'true';
const videoSha256 = String(certAny.videoSha256 || certAny.video_sha256 || publicAny.video_sha256 || '').trim();
const videoFileName = String(certAny.videoFileName || certAny.video_file_name || publicAny.video_file_name || '').trim();
const videoDeclarationText = String(certAny.videoDeclarationText || certAny.video_declaration_text || publicAny.video_declaration_text || '').trim();
const videoProofPresent = Boolean(certAny.videoProof || certAny.video_proof || publicAny.video_proof || videoSha256 || videoFileName || videoDeclarationText);
const displayVideoDeclarationText = lang === 'en' && videoProofPresent
? `The depositor declares in the video that they are making this deposit on CopyrightChain, confirms that the uploaded file "${certificate.title}" is the work to be certified, associated with the SHA-256 hash ${certificate.fileHash || (certificate as any).hash || 'N/A'}, and declares that they will keep the original video file downloaded at the end of the recording.`
: videoDeclarationText;
const displayLegalAttestation = lang === 'en'
? `Certificate issued through CopyrightChain AI Gateway. Certificate ID: ${certificate.id}. Public verification: ${verifyUrl || 'N/A'}`
: String(certificate.legalAttestation || `Certificato emesso via CopyrightChain AI Gateway. ID: ${certificate.id}. Verifica: ${verifyUrl || ''}`);
const aiAssisted = Boolean(
certAny.aiAssisted ||
certAny.ai_assisted ||
publicAny.ai_assisted ||
certAny.contentType === 'ai_assisted' ||
certAny.content_type === 'ai_assisted' ||
publicAny.content_type === 'ai_assisted'
);
const aiToolUsed = String(certAny.aiToolUsed || certAny.ai_tool_used || publicAny.ai_tool_used || '').trim();
const aiPrompt = String(certAny.aiPrompt || certAny.ai_prompt || publicAny.ai_prompt || '').trim();
const humanContribution = String(certAny.humanContribution || certAny.human_contribution || publicAny.human_contribution || '').trim();
const aiProcessNotes = String(certAny.aiProcessNotes || certAny.ai_process_notes || publicAny.ai_process_notes || '').trim();
const rawAiDeclarationAccepted = certAny.aiDeclarationAccepted ?? certAny.ai_declaration_accepted ?? publicAny.ai_declaration_accepted ?? false;
const aiDeclarationAccepted = rawAiDeclarationAccepted === true || String(rawAiDeclarationAccepted).toLowerCase() === 'true';
useEffect(() => {
let cancelled = false;
const certId = String(certificate.id || '').trim();
if (!certId) return;
fetch(`https://app.copyrightchain.it/api/ai/verify/public?id=${encodeURIComponent(certId)}`)
.then((res) => res.ok ? res.json() : null)
.then((data) => {
if (!cancelled && data?.ok) setPublicVerifyData(data);
})
.catch(() => {});
return () => {
cancelled = true;
};
}, [certificate.id]);
useEffect(() => {
const generateQR = async () => {
try {
const verifyUrl =
(certificate.verifyUrl && String(certificate.verifyUrl).trim()) ||
(certificate.legalAttestation && String(certificate.legalAttestation).match(/https?:\/\/\S+/)?.[0]) ||
`https://copyrightchain.it/verifica-certificato/?id=${encodeURIComponent(certificate.id || "")}&hash=${encodeURIComponent(certificate.fileHash || certificate.hash || "")}`;
const url = await QRCode.toDataURL(verifyUrl, {
width: 256,
margin: 1,
color: { dark: '#0f172a', light: '#ffffff' },
});
setQrCodeUrl(url);
} catch (err) { console.error('QR Error:', err); }
};
generateQR();
}, [certificate.id]);
const handlePrint = () => window.print();
const handleDownloadPDF = async () => {
const element = certificateRef.current;
if (!element) return;
setIsGeneratingPDF(true);
notify(lang === 'it' ? "Generazione documento ufficiale..." : "Generating official document...", "info");
try {
const canvas = await html2canvas(element, {
scale: 2,
useCORS: true,
allowTaint: true,
backgroundColor: '#ffffff',
logging: false,
width: element.scrollWidth,
height: element.scrollHeight
});
const imgData = canvas.toDataURL('image/jpeg', 0.9);
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'mm',
format: 'a4'
});
const pdfWidth = pdf.internal.pageSize.getWidth();
const pdfHeight = pdf.internal.pageSize.getHeight();
pdf.addImage(imgData, 'JPEG', 0, 0, pdfWidth, pdfHeight);
pdf.save(`Copyright_Cert_${certificate.id}.pdf`);
notify(lang === 'it' ? "Documento scaricato con successo." : "Document downloaded successfully.", "success");
} catch (error) {
console.error('PDF Generation Error:', error);
notify(lang === 'it' ? "Errore durante il download. Riprova." : "Download failed. Please try again.", "error");
} finally {
setIsGeneratingPDF(false);
}
};
const handleDownloadStamped = async () => {
if (!certificate.fileData) {
notify(lang === 'it' ? "File originale non trovato." : "Original file not found.", "error");
return;
}
setIsGeneratingStamp(true);
notify(lang === 'it' ? "Applicazione timbro su ogni pagina..." : "Applying stamp to every page...", "info");
try {
if (!stampPreviewRef.current) return;
const stampCanvas = await html2canvas(stampPreviewRef.current, {
scale: 2,
useCORS: true,
backgroundColor: null,
logging: false
});
const stampImgData = stampCanvas.toDataURL('image/png');
if (certificate.mimeType === 'application/pdf') {
const existingPdfBytes = await fetch(certificate.fileData).then((res) => res.arrayBuffer());
const pdfDoc = await PDFDocument.load(existingPdfBytes);
const stampImage = await pdfDoc.embedPng(stampImgData);
const pages = pdfDoc.getPages();
pages.forEach((page) => {
const { width, height } = page.getSize();
const stampWidth = 140;
const stampHeight = (stampCanvas.height / stampCanvas.width) * stampWidth;
page.drawImage(stampImage, {
x: width - stampWidth - 30,
y: height - stampHeight - 30,
width: stampWidth,
height: stampHeight,
opacity: 0.9,
});
});
const pdfBytes = await pdfDoc.save();
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `STAMPED_${certificate.fileName}`;
link.click();
} else if (certificate.mimeType.startsWith('image/')) {
const img = new Image();
img.src = certificate.fileData;
await new Promise((resolve) => (img.onload = resolve));
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
if (ctx) {
ctx.drawImage(img, 0, 0);
const stamp = new Image();
stamp.src = stampImgData;
await new Promise((resolve) => (stamp.onload = resolve));
const stampWidth = canvas.width * 0.25;
const stampHeight = (stamp.height / stamp.width) * stampWidth;
ctx.globalAlpha = 0.9;
ctx.drawImage(stamp, canvas.width - stampWidth - 40, 40, stampWidth, stampHeight);
const link = document.createElement('a');
link.href = canvas.toDataURL(certificate.mimeType);
link.download = `STAMPED_${certificate.fileName}`;
link.click();
}
}
notify(lang === 'it' ? "File timbrato scaricato." : "Stamped file downloaded.", "success");
} catch (e) {
notify(lang === 'it' ? "Errore durante lo stamping." : "Error during stamping.", "error");
} finally {
setIsGeneratingStamp(false);
}
};
const handleDownloadBundle = async () => {
setIsBundling(true);
notify(lang === 'it' ? "Compilazione Fascicolo Probatorio..." : "Compiling Evidence Bundle...", "info");
// Nessun delay artificiale: se in futuro il bundle verrà generato via API,
// qui andrà una chiamata reale con progress/streaming.
const manifest = [
'COPYRIGHTCHAIN DIGITAL CERTIFICATE REGISTRY',
'OFFICIAL EVIDENCE BUNDLE',
'',
`Certificate ID: ${certificate.id}`,
`Title: ${certificate.title}`,
`Original file: ${certificate.fileName}`,
`Author / Registrant: ${certificate.author}`,
`Deposit date: ${new Date(certificate.timestamp).toISOString()}`,
`File SHA-256: ${certificate.fileHash || (certificate as any).hash || 'N/A'}`,
`Public verification: ${verifyUrl || 'N/A'}`,
'',
'BLOCKCHAIN / TIMESTAMP EVIDENCE',
`Status: ${certificate.bitcoinEvidence?.status || 'N/A'}`,
`Bitcoin TxID: ${certificate.bitcoinEvidence?.txId || 'N/A'}`,
`Block height: ${typeof certificate.bitcoinEvidence?.blockHeight === 'number' ? certificate.bitcoinEvidence.blockHeight : 'N/A'}`,
`Anchored at: ${anchoredAt || 'N/A'}`,
`Confirmed at: ${confirmedAt || 'N/A'}`,
'',
'VIDEO PROOF',
`Status: ${videoProofPresent ? 'PRESENTE / PRESENT' : 'NON ASSOCIATO / NOT ASSOCIATED'}`,
`Video SHA-256: ${videoSha256 || 'N/A'}`,
`Video file: ${videoFileName || 'N/A'}`,
`Video retained by platform: ${videoRetainedByPlatform ? 'YES' : 'NO'}`,
`Declaration: ${displayVideoDeclarationText || 'N/A'}`,
'',
`Issued by: ${branding.companyName}`,
'',
'Note: CopyrightChain stores the technical evidence and hash references. When video proof is used, the video file remains with the user unless expressly stated otherwise.'
].join('\n');
const blob = new Blob([manifest], { type: 'text/plain' });
const link = document.createElement('a');
link.href = URL.createObjectURL(blob);
link.download = `Evidence_Bundle_${certificate.id}.txt`;
link.click();
setIsBundling(false);
};
const handleProtectedDownload = async (url: string, fallbackName: string) => {
if (!url) return;
if (!clientToken) {
notify(lang === 'it' ? 'Sessione cliente non valida.' : 'Invalid client session.', 'error');
return;
}
try {
const res = await fetch(url, {
headers: {
'X-CCP-Token': clientToken
}
});
if (!res.ok) {
throw new Error(`download_failed_${res.status}`);
}
const blob = await res.blob();
let filename = fallbackName;
const cd = res.headers.get('content-disposition') || '';
const m = cd.match(/filename="?([^"]+)"?/i);
if (m && m[1]) {
filename = m[1];
}
const a = document.createElement('a');
const blobUrl = URL.createObjectURL(blob);
a.href = blobUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(blobUrl);
notify(lang === 'it' ? 'Download completato.' : 'Download completed.', 'success');
} catch (e) {
notify(lang === 'it' ? 'Download non autorizzato o non disponibile.' : 'Unauthorized or unavailable download.', 'error');
}
};
return (
<div className="space-y-8 print:p-0">
<div className="flex flex-wrap gap-2 md:gap-3 print:hidden">
<button onClick={handlePrint} className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-slate-100 hover:bg-slate-200 text-slate-700 px-4 py-2.5 rounded-xl transition text-xs md:text-sm font-bold">
<Printer size={18} /> <span className="hidden sm:inline">{t.printCert}</span>
</button>
<button onClick={handleDownloadPDF} disabled={isGeneratingPDF} className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-blue-600 hover:bg-blue-700 text-white px-5 py-2.5 rounded-xl transition text-xs md:text-sm font-bold shadow-lg shadow-blue-100">
{isGeneratingPDF ? <Loader2 size={18} className="animate-spin" /> : <Download size={18} />}
<span>{t.downloadPdf}</span>
</button>
<button onClick={handleDownloadBundle} disabled={isBundling} className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-emerald-600 text-white px-4 py-2.5 rounded-xl transition text-xs md:text-sm font-bold shadow-lg shadow-emerald-100">
{isBundling ? <Loader2 size={18} className="animate-spin" /> : <Package size={18} />} {t.evidenceBundle}
</button>
{!isTimestampCert && (
<button onClick={handleDownloadStamped} disabled={isGeneratingStamp} className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-slate-900 text-white px-4 py-2.5 rounded-xl transition text-xs md:text-sm font-bold">
{isGeneratingStamp ? <Loader2 size={18} className="animate-spin" /> : <Stamp size={18} />}
{lang === 'it' ? 'Scarica Timbrato' : 'Download Stamped'}
</button>
)}
{otsProofUrl && (
<button onClick={() => handleProtectedDownload(otsProofUrl, `proof_${certificate.id}.ots`)} className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-violet-600 text-white px-4 py-2.5 rounded-xl transition text-xs md:text-sm font-bold shadow-lg shadow-violet-100">
<Archive size={18} /> OTS Proof
</button>
)}
{otsManifestUrl && (
<button onClick={() => handleProtectedDownload(otsManifestUrl, `manifest_${certificate.id}.json`)} className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-slate-700 text-white px-4 py-2.5 rounded-xl transition text-xs md:text-sm font-bold">
<FileText size={18} /> Manifest
</button>
)}
{verifyUrl && (
<a href={verifyUrl} target="_blank" rel="noreferrer" className="flex-1 md:flex-none justify-center flex items-center gap-2 bg-white border border-slate-200 text-slate-700 px-4 py-2.5 rounded-xl transition text-xs md:text-sm font-bold">
<ExternalLink size={18} /> {lang === 'it' ? 'Verifica pubblica' : 'Public verify'}
</a>
)}
</div>
{/* Timbro visivo - FUORI SCHERMO */}
<div className="fixed -left-[2000px] top-0 pointer-events-none">
<div ref={stampPreviewRef} className="p-8 bg-white border-4 border-slate-900 rounded-[3rem] w-[500px] flex items-center gap-8 shadow-2xl">
<div className="w-24 h-24 bg-white p-2 rounded-2xl shadow-sm border border-slate-100">
{qrCodeUrl && <img src={qrCodeUrl} alt="QR" className="w-full h-full" />}
</div>
<div className="text-left border-l-4 border-slate-900 pl-8 flex-1">
<p className="text-lg font-black text-slate-900 leading-none mb-1 uppercase tracking-tighter">{branding.companyName} REGISTERED</p>
<p className="text-xs font-bold text-slate-600 mb-3 uppercase">DATA CERTA: {new Date(certificate.timestamp).toLocaleDateString()}</p>
<p className="text-[9px] font-mono font-black text-slate-400 uppercase break-all">ID: {certificate.id}</p>
</div>
</div>
</div>
<div
ref={certificateRef}
className="certificate-container bg-white border-[3px] border-slate-900 p-10 md:p-14 relative overflow-hidden shadow-2xl print:shadow-none rounded-sm min-h-[1120px]"
>
{/* Filigrana */}
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 opacity-[0.025] pointer-events-none">
<Shield size={420} className="md:w-[760px] md:h-[760px]" />
</div>
<div className="relative z-10 text-center space-y-8 md:space-y-10">
<div className="border-b-4 border-slate-900 pb-8">
<div className="flex flex-col md:flex-row items-center justify-between gap-6 text-left">
<div className="flex items-center gap-5">
<div className="bg-white border border-slate-200 rounded-2xl p-4 shadow-sm">
<img src={officialLogoUrl} crossOrigin="anonymous" alt="CopyrightChain Logo" className="h-16 md:h-24 object-contain" />
</div>
<div>
<p className="text-[10px] font-black uppercase tracking-[0.35em] text-slate-500">CopyrightChain</p>
<h1 className="serif-font text-3xl md:text-4xl font-black text-slate-950 tracking-tight uppercase leading-none">
{lang === 'it' ? 'Registro Digitale dei Certificati' : 'Digital Certificate Registry'}
</h1>
<p className="mt-2 text-[10px] md:text-xs font-black uppercase tracking-[0.22em] text-slate-500">
{isTimestampCert
? (lang === 'it' ? 'Certificato marca temporale Openapi / InfoCert' : 'Openapi / InfoCert timestamp certificate')
: (lang === 'it' ? 'Certificato di deposito digitale e prova di integrità SHA-256' : 'Digital deposit certificate and SHA-256 integrity proof')}
</p>
</div>
</div>
<div className="text-center md:text-right border border-slate-900 rounded-2xl px-6 py-4 bg-slate-50">
<p className="text-[9px] font-black uppercase tracking-[0.3em] text-slate-500">Official Record</p>
<p className="text-lg font-mono font-black text-slate-950 mt-1">{certificate.id}</p>
<p className="text-[9px] font-black uppercase tracking-widest text-slate-400 mt-1">{branding.companyName}</p>
</div>
</div>
</div>
{/* Registro tecnico */}
<div className="p-6 rounded-2xl border border-slate-200 bg-slate-50 text-left">
<div className="flex items-start gap-4">
<Box className={certificate.bitcoinEvidence?.status === 'pending' ? 'text-orange-500 flex-shrink-0 mt-1' : 'text-blue-700 flex-shrink-0 mt-1'} size={26} />
<div className="min-w-0">
<p className="text-xs font-black uppercase tracking-widest text-slate-900">
{lang === 'it' ? 'Registro tecnico di integrità e verifica' : 'Technical integrity and verification registry'}
</p>
<p className="text-[10px] font-bold uppercase text-slate-500 mt-1">
{lang === 'it' ? 'Hash SHA-256, data deposito, verifica pubblica e dati di ancoraggio quando disponibili.' : 'SHA-256 hash, deposit date, public verification and anchoring data when available.'}
</p>
<p className="mt-4 text-[10px] font-black uppercase tracking-widest text-slate-400">File SHA-256</p>
<p className="font-mono text-[10px] md:text-xs font-black text-slate-900 break-all">{certificate.fileHash || (certificate as any).hash || '—'}</p>
</div>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 md:gap-14 text-left">
<div className="space-y-1 border-l-4 border-slate-900 pl-6">
<p className="text-[11px] text-slate-400 font-black uppercase tracking-widest">{t.certTitle}</p>
<p className="text-xl md:text-2xl font-black text-slate-900 break-words">{certificate.title}</p>
</div>
<div className="space-y-1 border-l-4 border-blue-600 pl-6">
<p className="text-[11px] text-slate-400 font-black uppercase tracking-widest">{t.certId}</p>
<p className="text-xl md:text-2xl font-mono font-black text-blue-700 break-all">{certificate.id}</p>
</div>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-8 text-left">
<div className="flex items-start gap-4">
<Calendar className="text-slate-300 mt-1 flex-shrink-0" size={24} />
<div className="min-w-0">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">{t.depositDate}</p>
<p className="text-sm md:text-base font-black text-slate-800 leading-tight">
{new Date(certificate.timestamp).toLocaleDateString(lang === 'it' ? 'it-IT' : 'en-US')}
</p>
</div>
</div>
<div className="flex items-start gap-4">
<User className="text-slate-300 mt-1 flex-shrink-0" size={24} />
<div className="min-w-0">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">{t.authorRegistrant}</p>
<p className="text-sm md:text-base font-black text-slate-800 leading-tight break-words">{certificate.author}</p>
</div>
</div>
<div className="flex items-start gap-4">
<FileText className="text-slate-300 mt-1 flex-shrink-0" size={24} />
<div className="min-w-0 flex-1">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">{t.originalFile}</p>
<p className="text-sm md:text-base font-black text-slate-800 leading-tight break-all">{certificate.fileName}</p>
</div>
</div>
</div>
{isTimestampCert && (
<div className="mt-8 bg-indigo-50 border border-indigo-100 rounded-[2rem] p-6">
<div className="flex items-center gap-3 mb-5">
<div className="w-10 h-10 rounded-xl bg-indigo-600 text-white flex items-center justify-center text-xs font-black">TS</div>
<div>
<p className="text-[10px] text-indigo-500 font-black uppercase tracking-widest">Marca temporale</p>
<h3 className="text-lg font-black text-slate-900">Openapi / InfoCert</h3>
<p className="mt-1 inline-flex rounded-full bg-white border border-indigo-200 px-3 py-1 text-[10px] font-black text-indigo-700 uppercase tracking-widest">
Timbro InfoCert: {formatInfoCertStampDate(timestampEvidence.issuedAt)}
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Status</p>
<p className="font-mono text-sm font-black text-indigo-700 break-all">{String(timestampEvidence.status || 'issued')}</p>
</div>
<div>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Provider</p>
<p className="font-mono text-sm font-black text-slate-900 break-all">{String(timestampEvidence.provider || 'Openapi / InfoCert')}</p>
</div>
<div>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Ambiente</p>
<p className="font-mono text-sm font-black text-slate-900 break-all">{String(timestampEvidence.environment || '—')}</p>
</div>
<div>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Transaction</p>
<p className="font-mono text-sm font-black text-slate-900 break-all">{String(timestampEvidence.transaction || '—')}</p>
</div>
<div className="md:col-span-2">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Data emissione marca</p>
<p className="font-mono text-sm font-black text-slate-900 break-all">{formatInfoCertStampDate(timestampEvidence.issuedAt)}</p>
</div>
</div>
<div className="mt-4">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Hash SHA-256 marcato</p>
<p className="font-mono text-[10px] md:text-xs font-black text-slate-900 break-all">{String(timestampEvidence.hash || certificate.fileHash || '—')}</p>
</div>
{timestampEvidence.bodyUrl && (
<div className="mt-4">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Timestamp body / M7M</p>
<p className="font-mono text-[10px] md:text-xs font-black text-indigo-700 break-all">{String(timestampEvidence.bodyUrl)}</p>
</div>
)}
<div className="mt-4 rounded-2xl bg-white/80 border border-indigo-100 p-4">
<p className="text-xs font-bold text-slate-600 leading-relaxed">
Marca temporale InfoCert associata all’impronta SHA-256 del deposito CopyrightChain e collegata al presente certificato verificabile.
</p>
</div>
</div>
)}
{certificate.bitcoinEvidence && (
<div className="space-y-6 pt-10 border-t border-slate-100 text-left">
<p className="text-[11px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Dettagli ancoraggio blockchain' : 'Blockchain anchoring details'}
</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Status</p>
<p className="text-base font-black text-slate-900 mt-1 uppercase">
{String(certificate.bitcoinEvidence?.status || 'pending')}
</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Bitcoin TxID</p>
<p className="text-sm font-mono font-black text-slate-900 mt-1 break-all">
{String(certificate.bitcoinEvidence?.txId || '—')}
</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Block Height</p>
<p className="text-base font-black text-slate-900 mt-1">
{typeof certificate.bitcoinEvidence?.blockHeight === 'number' ? certificate.bitcoinEvidence.blockHeight : '—'}
</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Verifica pubblica' : 'Public verification'}
</p>
{verifyUrl ? (
<a href={verifyUrl} target="_blank" rel="noreferrer" className="mt-1 inline-flex items-center gap-2 text-blue-600 font-black break-all">
<ExternalLink size={16} /> {verifyUrl}
</a>
) : (
<p className="text-base font-black text-slate-900 mt-1">—</p>
)}
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Anchored At</p>
<p className="text-sm font-black text-slate-900 mt-1 break-all">
{anchoredAt ? new Date(anchoredAt).toLocaleString(lang === 'it' ? 'it-IT' : 'en-US') : '—'}
</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Confirmed At</p>
<p className="text-sm font-black text-slate-900 mt-1 break-all">
{confirmedAt ? new Date(confirmedAt).toLocaleString(lang === 'it' ? 'it-IT' : 'en-US') : '—'}
</p>
</div>
</div>
</div>
)}
{videoProofPresent && (
<div className="space-y-5 pt-10 border-t border-slate-100 text-left">
<div className="flex items-center gap-3">
<div className="bg-slate-900 text-white p-2 rounded-xl">
<Fingerprint size={20} />
</div>
<div>
<p className="text-[11px] text-slate-900 font-black uppercase tracking-widest">
{lang === 'it' ? 'Prova video associata al deposito' : 'Video proof associated with this deposit'}
</p>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Collegamento tramite hash SHA-256 del file video' : 'Linked through the SHA-256 hash of the video file'}
</p>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Video Proof</p>
<p className="text-base font-black text-emerald-700 mt-1 uppercase">{lang === 'it' ? 'Presente' : 'Present'}</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Conservazione piattaforma' : 'Platform retention'}
</p>
<p className="text-base font-black text-slate-900 mt-1 uppercase">
{videoRetainedByPlatform ? 'YES' : 'NO'}
</p>
<p className="text-[9px] font-bold text-slate-400 mt-1">
{lang === 'it' ? 'Il video resta nella disponibilità dell’utente.' : 'The video remains under the user’s control.'}
</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5 md:col-span-2">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">Video SHA-256</p>
<p className="text-[10px] md:text-xs font-mono font-black text-slate-900 mt-1 break-all">{videoSha256 || '—'}</p>
</div>
<div className="bg-slate-50 border border-slate-100 rounded-2xl p-5 md:col-span-2">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'File video dichiarato' : 'Declared video file'}
</p>
<p className="text-sm font-black text-slate-900 mt-1 break-all">{videoFileName || '—'}</p>
</div>
{videoDeclarationText && (
<div className="bg-white border border-slate-200 rounded-2xl p-5 md:col-span-2">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Dichiarazione guidata' : 'Guided declaration'}
</p>
<p className="text-xs md:text-sm font-bold text-slate-700 mt-2 leading-relaxed">{displayVideoDeclarationText}</p>
</div>
)}
</div>
</div>
)}
{aiAssisted && (
<div className="space-y-5 pt-10 border-t border-slate-100 text-left">
<div className="flex items-center gap-3">
<div className="bg-indigo-900 text-white p-2 rounded-xl">
<Sparkles size={20} />
</div>
<div>
<p className="text-[11px] text-slate-900 font-black uppercase tracking-widest">
{lang === 'it' ? 'Contenuto assistito da AI' : 'AI-assisted content'}
</p>
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Dichiarazione contributo umano associata al certificato' : 'Human contribution declaration linked to this certificate'}
</p>
</div>
</div>
<div className="bg-indigo-50/60 border border-indigo-100 rounded-2xl p-6 space-y-5">
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
<div className="bg-white border border-indigo-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Strumento AI usato' : 'AI tool used'}
</p>
<p className="text-sm md:text-base font-black text-slate-900 mt-1 break-words">{aiToolUsed || '—'}</p>
</div>
<div className="bg-white border border-indigo-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Dichiarazione contributo umano' : 'Human contribution declaration'}
</p>
<p className={`text-sm md:text-base font-black mt-1 uppercase ${aiDeclarationAccepted ? 'text-emerald-700' : 'text-slate-600'}`}>
{aiDeclarationAccepted
? (lang === 'it' ? 'Accettata' : 'Accepted')
: (lang === 'it' ? 'Non indicata' : 'Not declared')}
</p>
</div>
</div>
{aiPrompt && (
<div className="bg-white border border-indigo-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Prompt principale' : 'Main prompt'}
</p>
<p className="text-xs md:text-sm font-bold text-slate-700 mt-2 leading-relaxed break-words">{aiPrompt}</p>
</div>
)}
{humanContribution && (
<div className="bg-white border border-indigo-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Contributo umano dichiarato' : 'Declared human contribution'}
</p>
<p className="text-xs md:text-sm font-bold text-slate-700 mt-2 leading-relaxed break-words">{humanContribution}</p>
</div>
)}
{aiProcessNotes && (
<div className="bg-white border border-indigo-100 rounded-2xl p-5">
<p className="text-[10px] text-slate-400 font-black uppercase tracking-widest">
{lang === 'it' ? 'Note sul processo creativo' : 'Creative process notes'}
</p>
<p className="text-xs md:text-sm font-bold text-slate-700 mt-2 leading-relaxed break-words">{aiProcessNotes}</p>
</div>
)}
<p className="text-[9px] text-slate-500 font-bold leading-relaxed">
{lang === 'it'
? 'CopyrightChain documenta il file, la data, l’hash SHA-256 e la dichiarazione del contributo umano associata al processo creativo. Non utilizza rilevatori AI e non dichiara automaticamente la tutela dell’opera.'
: 'CopyrightChain documents the file, date, SHA-256 hash and the human contribution declaration associated with the creative process. It does not use AI detectors and does not automatically declare copyright protection.'}
</p>
</div>
</div>
)}
<div className="space-y-4 pt-10 border-t border-slate-100 text-left">
<p className="text-[11px] text-slate-400 font-black uppercase tracking-widest">{t.legalAttestation}</p>
<div className="serif-font text-sm md:text-base text-slate-800 leading-relaxed italic bg-slate-50 p-8 rounded-2xl border border-slate-100">
"{displayLegalAttestation}"
</div>
</div>
<div className="flex flex-col sm:flex-row justify-between items-center sm:items-end pt-12 border-t-2 border-slate-100 gap-10">
<div className="text-center sm:text-left space-y-4 w-full sm:w-auto">
<div className="inline-flex items-center gap-3 text-green-700 bg-green-50 px-5 py-2.5 rounded-full text-[10px] font-black uppercase tracking-widest border border-green-100">
<CheckCircle size={18} /> {t.verifiedAuth}
</div>
<p className="text-[9px] text-slate-500 max-w-2xl leading-relaxed font-bold">
{ABO_FOOTER_TEXT}
</p>
<p className="text-[8px] text-slate-400 max-w-2xl leading-relaxed font-bold uppercase tracking-widest">
{lang === 'it'
? 'Documento tecnico di deposito digitale: conserva il file originale, il video proof e il presente certificato.'
: 'Technical digital deposit document: keep the original file, the video proof and this certificate.'}
</p>
</div>
<div className="text-center bg-white p-3 border border-slate-100 rounded-3xl shadow-xl">
<div className="w-28 h-28 md:w-36 md:h-36 flex items-center justify-center">
{qrCodeUrl && <img src={qrCodeUrl} alt="QR" className="w-full h-full" />}
</div>
<p className="text-[9px] text-slate-400 font-black uppercase tracking-widest mt-3">{t.scanVerify}</p>
</div>
</div>
</div>
</div>
</div>
);
};
export default CertificateView;