Spaces:
Sleeping
Sleeping
| {% extends "base.html" %} | |
| {% block title %}{{ candidate.name }}{% endblock %} | |
| {% block content %} | |
| <div class="mb-6"> | |
| <a href="/dashboard" class="text-indigo-600 hover:text-indigo-800 text-sm font-medium">β Back to Dashboard</a> | |
| </div> | |
| <div class="grid grid-cols-1 lg:grid-cols-3 gap-6"> | |
| <!-- LEFT: Profile --> | |
| <div class="space-y-5"> | |
| <div class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6 text-center"> | |
| <div class="w-20 h-20 gradient-bg rounded-2xl flex items-center justify-center text-white text-3xl font-bold mx-auto mb-4"> | |
| {{ candidate.name[0].upper() if candidate.name else '?' }} | |
| </div> | |
| <h2 class="text-xl font-bold text-gray-900">{{ candidate.name }}</h2> | |
| <p class="text-gray-500 text-sm mt-1">{{ candidate.email or 'No email' }}</p> | |
| <p class="text-gray-400 text-sm">{{ candidate.phone or 'No phone' }}</p> | |
| <div class="mt-4"> | |
| <span class="status-badge status-{{ candidate.status }} text-sm px-3 py-1">{{ candidate.status }}</span> | |
| </div> | |
| </div> | |
| <!-- Score Card --> | |
| <div class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6"> | |
| <h3 class="font-semibold text-gray-700 mb-3 text-sm">Match Score</h3> | |
| <div class="text-center mb-3"> | |
| <span class="text-5xl font-extrabold {% if candidate.score >= 70 %}text-green-500{% elif candidate.score >= 50 %}text-yellow-500{% else %}text-red-500{% endif %}"> | |
| {{ candidate.score }} | |
| </span> | |
| <span class="text-2xl text-gray-400 font-light">/100</span> | |
| </div> | |
| <div class="progress-bar"> | |
| <div class="progress-fill {% if candidate.score >= 70 %}bg-green-500{% elif candidate.score >= 50 %}bg-yellow-400{% else %}bg-red-400{% endif %}" | |
| style="width:{{ candidate.score }}%"></div> | |
| </div> | |
| {% if candidate.job_title %} | |
| <p class="text-xs text-gray-400 mt-3 text-center">For: {{ candidate.job_title }}</p> | |
| {% endif %} | |
| </div> | |
| <!-- Interview Info --> | |
| {% if candidate.interview_scheduled %} | |
| <div class="bg-blue-50 border border-blue-100 rounded-2xl p-5"> | |
| <h3 class="font-semibold text-blue-800 text-sm mb-2">π Interview Scheduled</h3> | |
| <p class="text-blue-700 font-medium text-sm">{{ candidate.interview_scheduled }}</p> | |
| </div> | |
| {% endif %} | |
| </div> | |
| <!-- RIGHT: Analysis --> | |
| <div class="lg:col-span-2 space-y-5"> | |
| <!-- AI Reasoning --> | |
| {% if candidate.reasoning %} | |
| <div class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6"> | |
| <h3 class="font-semibold text-gray-800 mb-3 flex items-center gap-2"> | |
| π€ AI Assessment | |
| </h3> | |
| <p class="text-gray-600 text-sm leading-relaxed bg-indigo-50 rounded-xl p-4 border-l-4 border-indigo-400 italic"> | |
| "{{ candidate.reasoning }}" | |
| </p> | |
| </div> | |
| {% endif %} | |
| <!-- Skills --> | |
| <div class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6"> | |
| <h3 class="font-semibold text-gray-800 mb-4">π§© Skill Gap Analysis</h3> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div> | |
| <h4 class="text-xs font-semibold text-green-700 uppercase mb-2">β Matching Skills</h4> | |
| <div class="flex flex-wrap gap-2"> | |
| {% if skills_matched %} | |
| {% for skill in skills_matched %} | |
| <span class="px-3 py-1 bg-green-100 text-green-700 rounded-full text-xs font-medium border border-green-200">{{ skill }}</span> | |
| {% endfor %} | |
| {% else %} | |
| <p class="text-gray-400 text-xs">None detected</p> | |
| {% endif %} | |
| </div> | |
| </div> | |
| <div> | |
| <h4 class="text-xs font-semibold text-red-600 uppercase mb-2">β οΈ Missing Skills</h4> | |
| <div class="flex flex-wrap gap-2"> | |
| {% if skills_missing %} | |
| {% for skill in skills_missing %} | |
| <span class="px-3 py-1 bg-red-50 text-red-600 rounded-full text-xs font-medium border border-red-200">{{ skill }}</span> | |
| {% endfor %} | |
| {% else %} | |
| <p class="text-gray-400 text-xs">No gaps found π</p> | |
| {% endif %} | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Reschedule --> | |
| {% if candidate.status in ['shortlisted', 'scheduled'] and candidate.email %} | |
| <div class="bg-white rounded-2xl shadow-sm border border-gray-100 p-6"> | |
| <h3 class="font-semibold text-gray-800 mb-4">π¬ Schedule / Reschedule Interview</h3> | |
| <div class="grid grid-cols-2 gap-4"> | |
| <div> | |
| <label class="text-xs font-medium text-gray-600 mb-1 block">Date & Time</label> | |
| <input id="rs-datetime" type="datetime-local" class="w-full border border-gray-200 rounded-xl px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:outline-none"/> | |
| </div> | |
| <div> | |
| <label class="text-xs font-medium text-gray-600 mb-1 block">Meeting Link</label> | |
| <input id="rs-link" type="url" placeholder="https://meet.google.com/..." class="w-full border border-gray-200 rounded-xl px-3 py-2 text-sm focus:ring-2 focus:ring-indigo-400 focus:outline-none"/> | |
| </div> | |
| </div> | |
| <button onclick="reschedule({{ candidate.id }})" | |
| class="mt-4 gradient-bg text-white font-semibold px-6 py-2.5 rounded-xl hover:opacity-90 transition text-sm"> | |
| π§ Send Interview Email | |
| </button> | |
| <div id="rs-msg" class="mt-2 text-sm hidden"></div> | |
| </div> | |
| {% endif %} | |
| </div> | |
| </div> | |
| {% endblock %} | |
| {% block scripts %} | |
| <script> | |
| async function reschedule(id) { | |
| const dt = document.getElementById('rs-datetime').value; | |
| const link = document.getElementById('rs-link').value; | |
| const msg = document.getElementById('rs-msg'); | |
| const res = await fetch(`/api/reschedule/${id}`, { | |
| method: 'POST', | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ datetime: dt, link }) | |
| }); | |
| const data = await res.json(); | |
| msg.classList.remove('hidden'); | |
| if (data.success) { | |
| msg.className = 'mt-2 text-sm text-green-600'; | |
| msg.textContent = 'β Interview email sent successfully!'; | |
| } else { | |
| msg.className = 'mt-2 text-sm text-red-500'; | |
| msg.textContent = 'β Failed: ' + (data.error || 'Unknown error'); | |
| } | |
| } | |
| </script> | |
| {% endblock %} | |