| import { EndpointResult, ENDPOINT_DISPLAY_NAMES } from "@/data/sampleData"; |
| import { CheckCircle2, AlertTriangle, XCircle } from "lucide-react"; |
|
|
| interface PredictionCardProps { |
| endpointKey: string; |
| result: EndpointResult; |
| } |
|
|
| function getStatusInfo(label: string) { |
| const lower = label.toLowerCase().trim(); |
| if ( |
| lower.includes("non-inhibitor") || |
| lower.includes("non-substrate") || |
| lower.includes("non ames toxic") || |
| lower.includes("non-carcinogens") || |
| lower.includes("weak inhibitor") || |
| lower.includes("low cyp") || |
| lower.includes("ready biodegradable") || |
| lower === "true" |
| ) { |
| return { |
| icon: <CheckCircle2 className="h-4 w-4 text-emerald-400" />, |
| badgeClass: |
| "bg-emerald-500/20 text-emerald-400 border border-emerald-500/30", |
| barColor: "bg-emerald-500", |
| }; |
| } |
| if ( |
| lower.includes("inhibitor") || |
| lower.includes("substrate") || |
| lower.includes("ames toxic") || |
| lower.includes("carcinogens") || |
| lower.includes("strong inhibitor") || |
| lower.includes("high cyp") || |
| lower.includes("not ready") |
| ) { |
| return { |
| icon: <XCircle className="h-4 w-4 text-red-400" />, |
| badgeClass: "bg-red-500/20 text-red-400 border border-red-500/30", |
| barColor: "bg-red-500", |
| }; |
| } |
| return { |
| icon: <AlertTriangle className="h-4 w-4 text-amber-400" />, |
| badgeClass: "bg-amber-500/20 text-amber-400 border border-amber-500/30", |
| barColor: "bg-amber-500", |
| }; |
| } |
|
|
| export default function PredictionCard({ |
| endpointKey, |
| result, |
| }: PredictionCardProps) { |
| const displayName = ENDPOINT_DISPLAY_NAMES[endpointKey] || endpointKey; |
| const status = getStatusInfo(result.label); |
| const probPercent = (result.prob * 100).toFixed(1); |
|
|
| return ( |
| <div className="group rounded-xl border border-slate-700/50 bg-slate-800/50 p-4 transition-all hover:border-slate-600/50 hover:bg-slate-800/80 hover:shadow-lg hover:shadow-slate-900/50"> |
| <div className="flex items-start justify-between gap-2 mb-3"> |
| <div className="flex items-center gap-2 min-w-0"> |
| {status.icon} |
| <h4 className="text-sm font-semibold text-slate-200 truncate"> |
| {displayName} |
| </h4> |
| </div> |
| </div> |
| <div className="mb-3"> |
| <span |
| className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${status.badgeClass}`} |
| > |
| {result.label.trim()} |
| </span> |
| </div> |
| <div className="space-y-1.5"> |
| <div className="flex items-center justify-between text-xs"> |
| <span className="text-slate-400">Probability (Class 1)</span> |
| <span className="font-mono text-slate-300">{probPercent}%</span> |
| </div> |
| <div className="h-2 w-full overflow-hidden rounded-full bg-slate-700/50"> |
| <div |
| className={`h-full rounded-full transition-all duration-500 ${status.barColor}`} |
| style={{ width: `${result.prob * 100}%` }} |
| /> |
| </div> |
| </div> |
| </div> |
| ); |
| } |