Coderound / proj /frontend /src /components /CandidateDetail.jsx
cloud450's picture
Upload 42 files
ab13a8a verified
'use client';
import React, { useState } from 'react';
import { motion } from 'framer-motion';
import { X, ShieldCheck, Zap, Briefcase, Cpu, TrendingUp, Info, Search } from 'lucide-react';
export default function CandidateDetail({ evaluation, onClose }) {
const [activeTab, setActiveTab] = useState('Synthesis');
const agents = [
{ name: 'Synthesis', icon: ShieldCheck },
{ name: 'Signal Extraction', icon: Zap },
{ name: 'Explanation', icon: Info },
{ name: 'Founder Eval', icon: TrendingUp },
{ name: 'HR Agent', icon: Search },
{ name: 'Tech Agent', icon: Cpu },
{ name: 'Business Agent', icon: Briefcase },
];
const getAgentContent = (name) => {
if (name === 'Synthesis') return evaluation.synthesis;
const agent = evaluation.agent_outputs.find(a => a.agent_name === name);
return agent ? agent.content : 'No output available for this agent.';
};
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
className="fixed inset-0 z-[100] bg-black/40 backdrop-blur-sm flex justify-end"
onClick={onClose}
>
<motion.div
initial={{ x: '100%' }}
animate={{ x: 0 }}
exit={{ x: '100%' }}
transition={{ type: 'spring', damping: 30, stiffness: 300 }}
className="w-full max-w-2xl bg-white dark:bg-slate-950 h-full shadow-2xl flex flex-col"
onClick={e => e.stopPropagation()}
>
{/* Header */}
<div className="p-8 border-b border-slate-100 dark:border-slate-800 flex justify-between items-start">
<div>
<span className="text-xs font-bold text-indigo-600 uppercase tracking-widest mb-1 block">Full Report</span>
<h2 className="text-3xl font-bold text-slate-900 dark:text-white">{evaluation.name}</h2>
<div className="flex items-center gap-4 mt-2">
<div className="flex items-center gap-1.5">
<div className="w-2 h-2 rounded-full bg-emerald-500"></div>
<span className="text-sm font-medium text-slate-500">{evaluation.decision}</span>
</div>
<div className="text-sm text-slate-400">Score: {Math.round(evaluation.final_score)}/100</div>
</div>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-slate-100 dark:hover:bg-slate-800 rounded-full transition-colors"
>
<X className="w-6 h-6 text-slate-400" />
</button>
</div>
{/* Content Area */}
<div className="flex flex-1 overflow-hidden">
{/* Sidebar Tabs */}
<div className="w-16 md:w-48 border-r border-slate-100 dark:border-slate-900 bg-slate-50/50 dark:bg-slate-900/20 py-6">
{agents.map((agent) => {
const Icon = agent.icon;
const isActive = activeTab === agent.name;
return (
<button
key={agent.name}
onClick={() => setActiveTab(agent.name)}
className={`w-full flex items-center gap-3 px-4 py-3 text-sm font-medium transition-all ${
isActive
? 'text-indigo-600 bg-white dark:bg-slate-900 shadow-sm border-r-2 border-indigo-600'
: 'text-slate-400 hover:text-slate-600 dark:hover:text-slate-300'
}`}
>
<Icon className="w-5 h-5 flex-shrink-0" />
<span className="hidden md:block truncate">{agent.name}</span>
</button>
);
})}
</div>
{/* Main Content */}
<div className="flex-1 overflow-y-auto p-8">
<AnimatePresence mode="wait">
<motion.div
key={activeTab}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
className="prose dark:prose-invert max-w-none"
>
<div className="mb-6 flex items-center justify-between">
<h3 className="text-xl font-bold m-0">{activeTab} Output</h3>
</div>
{activeTab === 'Synthesis' ? (
<div className="space-y-6">
<div className="p-5 bg-indigo-50 dark:bg-indigo-900/20 rounded-2xl border border-indigo-100 dark:border-indigo-800">
<h4 className="text-indigo-900 dark:text-indigo-300 font-bold mb-2">Final Summary</h4>
<p className="text-sm leading-relaxed text-indigo-800 dark:text-indigo-400">{evaluation.synthesis}</p>
</div>
<div className="grid grid-cols-2 gap-4">
<div className="p-4 bg-emerald-50 dark:bg-emerald-900/10 rounded-xl border border-emerald-100 dark:border-emerald-800/50">
<h4 className="text-emerald-700 dark:text-emerald-400 font-bold text-sm mb-3">Key Strengths</h4>
<ul className="space-y-2">
{evaluation.strengths.map((s, i) => (
<li key={i} className="text-xs flex items-start gap-2 text-emerald-800/70 dark:text-emerald-500/70">
<span className="block w-1 h-1 rounded-full bg-emerald-400 mt-1.5 flex-shrink-0"></span>
{s}
</li>
))}
</ul>
</div>
<div className="p-4 bg-rose-50 dark:bg-rose-900/10 rounded-xl border border-rose-100 dark:border-rose-800/50">
<h4 className="text-rose-700 dark:text-rose-400 font-bold text-sm mb-3">Potential Risks</h4>
<ul className="space-y-2">
{evaluation.risks.map((r, i) => (
<li key={i} className="text-xs flex items-start gap-2 text-rose-800/70 dark:text-rose-500/70">
<span className="block w-1 h-1 rounded-full bg-rose-400 mt-1.5 flex-shrink-0"></span>
{r}
</li>
))}
</ul>
</div>
</div>
<div className="grid grid-cols-5 gap-2">
{Object.entries(evaluation.scores).map(([key, val]) => (
<div key={key} className="p-3 bg-slate-50 dark:bg-slate-900 rounded-lg text-center">
<div className="text-[10px] uppercase text-slate-400 font-bold mb-1">{key}</div>
<div className="text-sm font-bold text-slate-700 dark:text-slate-300">{val}</div>
</div>
))}
</div>
</div>
) : (
<div className="bg-slate-50 dark:bg-slate-900/50 p-6 rounded-2xl whitespace-pre-wrap text-sm leading-relaxed text-slate-600 dark:text-slate-400 border border-slate-100 dark:border-slate-800">
{getAgentContent(activeTab)}
</div>
)}
</motion.div>
</AnimatePresence>
</div>
</div>
</motion.div>
</motion.div>
);
}