PharmAI / frontend /src /components /PredictionCard.tsx
Hattie's picture
Initial PharmAI deployment
9316888
Raw
History Blame Contribute Delete
3.04 kB
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>
);
}