Spaces:
Running
Running
| import React, { useEffect, useState } from "react"; | |
| interface TrustSummary { | |
| platform_score: number; | |
| overall_score: number; | |
| level: string; | |
| components: Record<string, number>; | |
| recommendations: string[]; | |
| } | |
| const LEVEL_LABELS: Record<string, string> = { | |
| excellent: "Doskonaly", | |
| good: "Dobry", | |
| fair: "Umiarkowany", | |
| needs_attention: "Wymaga uwagi", | |
| }; | |
| const COMPONENT_LABELS: Record<string, string> = { | |
| link_precision: "Precyzja linkow", | |
| snapshot_richness: "Bogactwo snapshotow", | |
| eurlex: "EUR-Lex", | |
| msp_grounding: "Grounding MSP", | |
| monitoring: "Monitoring prawa", | |
| }; | |
| export const TrustCenterPanel: React.FC = () => { | |
| const [summary, setSummary] = useState<TrustSummary | null>(null); | |
| const [error, setError] = useState<string | null>(null); | |
| const [loading, setLoading] = useState(true); | |
| useEffect(() => { | |
| fetch("/api/trust/summary") | |
| .then((r) => { | |
| if (!r.ok) throw new Error("Nie udalo sie pobrac podsumowania zaufania"); | |
| return r.json(); | |
| }) | |
| .then(setSummary) | |
| .catch((e) => setError(e.message)) | |
| .finally(() => setLoading(false)); | |
| }, []); | |
| if (loading) { | |
| return ( | |
| <div className="rounded-lg border border-slate-200 bg-white p-6 shadow-sm"> | |
| <p className="text-sm text-slate-500">Ladowanie centrum zaufania...</p> | |
| </div> | |
| ); | |
| } | |
| if (error || !summary) { | |
| return ( | |
| <div className="rounded-lg border border-red-200 bg-red-50 p-6 text-red-700"> | |
| {error || "Brak danych"} | |
| </div> | |
| ); | |
| } | |
| const score = summary.overall_score ?? summary.platform_score; | |
| const levelKey = summary.level || "fair"; | |
| return ( | |
| <div className="rounded-lg border border-slate-200 bg-white p-6 shadow-sm space-y-6"> | |
| <div className="flex flex-wrap items-center justify-between gap-4"> | |
| <div> | |
| <h2 className="text-lg font-semibold text-slate-900">Centrum zaufania</h2> | |
| <p className="text-sm text-slate-500">Ocena jakosci zrodel i regulaminow platformy</p> | |
| </div> | |
| <div className="text-right"> | |
| <div className="text-3xl font-bold text-slate-900">{score}</div> | |
| <div className="text-xs uppercase tracking-wide text-slate-500">/ 100</div> | |
| <div className="mt-1 inline-block rounded-full bg-slate-100 px-3 py-1 text-xs font-medium text-slate-700"> | |
| {LEVEL_LABELS[levelKey] || levelKey} | |
| </div> | |
| </div> | |
| </div> | |
| <div className="space-y-3"> | |
| <h3 className="text-sm font-medium text-slate-700">Skladowe</h3> | |
| {Object.entries(summary.components || {}).map(([key, value]) => { | |
| const pct = Math.min(100, Math.max(0, (value / 40) * 100)); | |
| return ( | |
| <div key={key}> | |
| <div className="mb-1 flex justify-between text-xs text-slate-600"> | |
| <span>{COMPONENT_LABELS[key] || key}</span> | |
| <span>{value.toFixed(1)} pkt</span> | |
| </div> | |
| <div className="h-2 w-full overflow-hidden rounded-full bg-slate-100"> | |
| <div | |
| className="h-full rounded-full bg-emerald-500 transition-all" | |
| style={{ width: `${pct}%` }} | |
| /> | |
| </div> | |
| </div> | |
| ); | |
| })} | |
| </div> | |
| <div> | |
| <h3 className="mb-2 text-sm font-medium text-slate-700">Rekomendacje</h3> | |
| <ul className="list-disc space-y-1 pl-5 text-sm text-slate-600"> | |
| {(summary.recommendations || []).map((rec, i) => ( | |
| <li key={i}>{rec}</li> | |
| ))} | |
| </ul> | |
| </div> | |
| </div> | |
| ); | |
| }; | |
| export default TrustCenterPanel; | |