Spaces:
Running
Running
| import React, { useState, useEffect } from 'react'; | |
| import { ShieldCheck, ShieldAlert, FileText, Download, Eye, Link as LinkIcon } from 'lucide-react'; | |
| interface TrustCertificateProps { | |
| projectId: string; | |
| credibilityFlags?: any; | |
| regulationGrounding?: string; | |
| preciseRegulationUrl?: string; | |
| regulationLinkQuality?: string; | |
| snapshotData?: any; | |
| onExportCertificate?: () => void; | |
| onExportJSON?: () => void; | |
| } | |
| interface CredibilityHealth { | |
| overall_credibility: string; | |
| components: any; | |
| } | |
| export const TrustCertificatePanel: React.FC<TrustCertificateProps> = ({ | |
| projectId, | |
| credibilityFlags, | |
| regulationGrounding, | |
| preciseRegulationUrl, | |
| regulationLinkQuality = 'medium', | |
| snapshotData, | |
| onExportCertificate, | |
| onExportJSON | |
| }) => { | |
| const [health, setHealth] = useState<CredibilityHealth | null>(null); | |
| const [showCert, setShowCert] = useState(false); | |
| const [showModal, setShowModal] = useState(false); | |
| useEffect(() => { | |
| fetch('/api/admin/credibility-health') | |
| .then(r => r.json()) | |
| .then(setHealth) | |
| .catch(() => {}); | |
| }, []); | |
| const trustLevel = credibilityFlags?.overall_trust_level || | |
| (credibilityFlags?.msp_using_real_data ? 'high' : 'medium'); | |
| const badgeColor = trustLevel === 'high' ? '#10b981' : trustLevel === 'medium' ? '#f59e0b' : '#ef4444'; | |
| const qualityColor = regulationLinkQuality === 'high' ? '#10b981' : regulationLinkQuality === 'medium' ? '#f59e0b' : '#64748b'; | |
| const openFullCertificate = () => setShowModal(true); | |
| return ( | |
| <> | |
| <div style={{ | |
| border: `2px solid ${badgeColor}`, | |
| borderRadius: 10, | |
| padding: 14, | |
| marginBottom: 16, | |
| background: '#f8fafc', | |
| boxShadow: '0 1px 3px rgba(0,0,0,0.08)' | |
| }}> | |
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: 8 }}> | |
| <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}> | |
| <span style={{ | |
| background: badgeColor, | |
| color: 'white', | |
| padding: '3px 12px', | |
| borderRadius: 999, | |
| fontSize: 11, | |
| fontWeight: 700, | |
| display: 'inline-flex', | |
| alignItems: 'center', | |
| gap: 4 | |
| }}> | |
| <ShieldCheck size={14} /> {trustLevel.toUpperCase()} TRUST | |
| </span> | |
| <span style={{ | |
| background: qualityColor, | |
| color: 'white', | |
| padding: '2px 8px', | |
| borderRadius: 6, | |
| fontSize: 10, | |
| fontWeight: 600 | |
| }}> | |
| REG LINK: {regulationLinkQuality.toUpperCase()} | |
| </span> | |
| <span style={{ fontWeight: 600, fontSize: 14, color: '#1e2937' }}> | |
| Regulation Grounding Certificate | |
| </span> | |
| </div> | |
| <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}> | |
| <button | |
| onClick={() => setShowCert(!showCert)} | |
| style={{ | |
| background: '#334155', | |
| color: 'white', | |
| border: 'none', | |
| padding: '5px 11px', | |
| borderRadius: 6, | |
| fontSize: 12, | |
| cursor: 'pointer', | |
| display: 'flex', | |
| alignItems: 'center', | |
| gap: 4 | |
| }} | |
| > | |
| <Eye size={14} /> {showCert ? 'Ukryj' : 'Pokaż'} Szczegóły | |
| </button> | |
| <button | |
| onClick={openFullCertificate} | |
| style={{ | |
| background: '#1e40af', | |
| color: 'white', | |
| border: 'none', | |
| padding: '5px 11px', | |
| borderRadius: 6, | |
| fontSize: 12, | |
| cursor: 'pointer', | |
| display: 'flex', | |
| alignItems: 'center', | |
| gap: 4 | |
| }} | |
| > | |
| <FileText size={14} /> Pełne Świadectwo | |
| </button> | |
| {onExportCertificate && ( | |
| <button | |
| onClick={onExportCertificate} | |
| style={{ | |
| background: '#059669', | |
| color: 'white', | |
| border: 'none', | |
| padding: '5px 11px', | |
| borderRadius: 6, | |
| fontSize: 12, | |
| cursor: 'pointer', | |
| display: 'flex', | |
| alignItems: 'center', | |
| gap: 4 | |
| }} | |
| > | |
| <Download size={14} /> PDF | |
| </button> | |
| )} | |
| {onExportJSON && ( | |
| <button | |
| onClick={onExportJSON} | |
| style={{ | |
| background: '#7c3aed', | |
| color: 'white', | |
| border: 'none', | |
| padding: '5px 11px', | |
| borderRadius: 6, | |
| fontSize: 12, | |
| cursor: 'pointer', | |
| display: 'flex', | |
| alignItems: 'center', | |
| gap: 4 | |
| }} | |
| > | |
| JSON | |
| </button> | |
| )} | |
| </div> | |
| </div> | |
| {preciseRegulationUrl && ( | |
| <div style={{ marginTop: 8, fontSize: 12, display: 'flex', alignItems: 'center', gap: 6 }}> | |
| <LinkIcon size={13} style={{ color: '#64748b' }} /> | |
| <a href={preciseRegulationUrl} target="_blank" rel="noreferrer" | |
| style={{ color: '#1e40af', textDecoration: 'underline', fontSize: 12 }}> | |
| Oficjalny dokument regulaminu (najwyższa precyzja) | |
| </a> | |
| </div> | |
| )} | |
| {showCert && ( | |
| <div style={{ marginTop: 12, padding: 12, background: 'white', borderRadius: 6, fontSize: 12.5, border: '1px solid #e2e8f0' }}> | |
| <div style={{ marginBottom: 6, fontWeight: 600, color: '#334155' }}>Regulation Grounding Certificate v1</div> | |
| {snapshotData && ( | |
| <div style={{ fontSize: 11.5, lineHeight: 1.45, color: '#334155' }}> | |
| <strong>Program:</strong> {snapshotData.program}<br /> | |
| <strong>Version Hash:</strong> <code style={{ fontSize: 10 }}>{snapshotData.version_hash}</code><br /> | |
| <strong>Snapshot ID:</strong> {snapshotData.id}<br /> | |
| <strong>Effective:</strong> {snapshotData.effective_date || 'N/A'} | <strong>Institution:</strong> {snapshotData.source_institution || 'N/A'} | |
| </div> | |
| )} | |
| {regulationGrounding && ( | |
| <pre style={{ | |
| marginTop: 8, | |
| fontSize: 10, | |
| background: '#f1f5f9', | |
| padding: 8, | |
| borderRadius: 4, | |
| maxHeight: 140, | |
| overflow: 'auto', | |
| whiteSpace: 'pre-wrap' | |
| }}> | |
| {regulationGrounding.slice(0, 650)} | |
| </pre> | |
| )} | |
| {credibilityFlags && ( | |
| <div style={{ marginTop: 8, fontSize: 11, color: '#475569' }}> | |
| <strong>Trust Flags:</strong> MSP Real={!!credibilityFlags.msp_using_real_data} | GUS Enriched={!!credibilityFlags.gus_enriched} | Level: {credibilityFlags.overall_trust_level} | |
| </div> | |
| )} | |
| {health && ( | |
| <div style={{ marginTop: 8, padding: 6, background: '#ecfdf5', borderRadius: 4, fontSize: 11 }}> | |
| <strong>System Health:</strong> {health.overall_credibility} | |
| {health.components?.acquisition_regulation_link_quality && ( | |
| <> | Link Quality: {health.components.acquisition_regulation_link_quality.high_quality_links_pct}% high</> | |
| )} | |
| </div> | |
| )} | |
| <div style={{ marginTop: 8, fontSize: 10.5, color: '#64748b' }}> | |
| Pełna audytowalność: hash wersji + snapshot + EUR-Lex + GUS. Dokument nadaje się do załączenia instytucji finansującej. | |
| </div> | |
| </div> | |
| )} | |
| </div> | |
| {/* Full Certificate Modal */} | |
| {showModal && ( | |
| <div style={{ | |
| position: 'fixed', top: 0, left: 0, right: 0, bottom: 0, | |
| background: 'rgba(15,23,42,0.65)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1000 | |
| }} onClick={() => setShowModal(false)}> | |
| <div style={{ | |
| background: 'white', width: '92%', maxWidth: 720, maxHeight: '88vh', overflow: 'auto', | |
| borderRadius: 12, padding: 24, boxShadow: '0 20px 25px -5px rgb(0 0 0 / 0.1)' | |
| }} onClick={e => e.stopPropagation()}> | |
| <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}> | |
| <h3 style={{ margin: 0, fontSize: 18 }}>Pełne Świadectwo Zgodności — Regulation Grounding Certificate</h3> | |
| <button onClick={() => setShowModal(false)} style={{ fontSize: 20, border: 'none', background: 'none', cursor: 'pointer' }}>×</button> | |
| </div> | |
| <div style={{ fontSize: 13, lineHeight: 1.55, color: '#334155' }}> | |
| <p><strong>Projekt ID:</strong> {projectId}</p> | |
| {preciseRegulationUrl && <p><strong>Najbardziej precyzyjny dokument:</strong> <a href={preciseRegulationUrl} target="_blank">{preciseRegulationUrl}</a></p>} | |
| {regulationGrounding && <pre style={{ background: '#f8fafc', padding: 12, fontSize: 11, whiteSpace: 'pre-wrap' }}>{regulationGrounding}</pre>} | |
| {snapshotData && <pre style={{ background: '#f1f5f9', padding: 10, fontSize: 11 }}>{JSON.stringify(snapshotData, null, 2)}</pre>} | |
| </div> | |
| <div style={{ marginTop: 20, display: 'flex', gap: 8 }}> | |
| {onExportCertificate && <button onClick={onExportCertificate} style={{ background: '#059669', color: 'white', padding: '8px 16px', borderRadius: 6, border: 'none' }}>Pobierz PDF Świadectwo</button>} | |
| {onExportJSON && <button onClick={onExportJSON} style={{ background: '#7c3aed', color: 'white', padding: '8px 16px', borderRadius: 6, border: 'none' }}>Pobierz JSON</button>} | |
| <button onClick={() => setShowModal(false)} style={{ padding: '8px 16px', borderRadius: 6, border: '1px solid #cbd5e1' }}>Zamknij</button> | |
| </div> | |
| </div> | |
| </div> | |
| )} | |
| </> | |
| ); | |
| }; | |
| export default TrustCertificatePanel; |