kaauh_ats/templates/recruitment/candidate_detail.html
2025-10-07 18:33:49 +03:00

384 lines
18 KiB
HTML

{% extends "base.html" %}
{% load static humanize i18n %}
{% block title %}{{ candidate.name }} - {{ block.super }}{% endblock %}
{% block customCSS %}
<style>
/* ================================================= */
/* THEME VARIABLES AND GLOBAL STYLES (FROM JOB DETAIL) */
/* ================================================= */
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--kaauh-border: #eaeff3;
--kaauh-primary-text: #343a40;
}
/* Primary Color Overrides */
.text-primary { color: var(--kaauh-teal) !important; }
.text-info { color: #17a2b8 !important; }
.text-success { color: #28a745 !important; }
.text-secondary { color: #6c757d !important; }
/* Main Action Button Style */
.btn-main-action {
background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
color: white;
font-weight: 600;
padding: 0.6rem 1.2rem;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
gap: 0.5rem;
}
.btn-main-action:hover {
background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark);
transform: translateY(-1px);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
/* Outlined Button Styles */
.btn-outline-primary {
color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
}
.btn-outline-primary:hover {
background-color: var(--kaauh-teal);
color: white;
}
.btn-outline-secondary {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal);
}
.btn-outline-secondary:hover {
background-color: var(--kaauh-teal-dark);
color: white;
border-color: var(--kaauh-teal-dark);
}
.btn-outline-info {
color: #17a2b8;
border-color: #17a2b8;
}
.btn-outline-info:hover {
background-color: #17a2b8;
color: white;
}
/* Card enhancements */
.card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
background-color: white;
}
/* Candidate Header Card (The teal header) */
.candidate-header-card {
background: linear-gradient(135deg, var(--kaauh-teal), #004d57);
color: white;
border-radius: 0.75rem 0.75rem 0 0;
padding: 1.5rem;
box-shadow: 0 4px 10px rgba(0,0,0,0.15);
}
.candidate-header-card h1 {
font-weight: 700;
margin: 0;
font-size: 1.8rem;
}
.candidate-header-card .badge {
font-size: 0.9rem;
padding: 0.4em 0.8em;
border-radius: 0.4rem;
font-weight: 700;
}
/* Left Column Tabs (Main Content Tabs) */
.main-tabs {
border-bottom: 1px solid var(--kaauh-border);
background-color: #f8f9fa;
padding: 0 1.25rem;
}
.main-tabs .nav-link {
border: none;
border-bottom: 3px solid transparent;
color: var(--kaauh-primary-text);
font-weight: 500;
padding: 0.75rem 1rem;
margin-right: 0.5rem;
transition: all 0.2s;
}
.main-tabs .nav-link:hover {
color: var(--kaauh-teal);
}
.main-tabs .nav-link.active {
color: var(--kaauh-teal-dark);
background-color: white;
border-bottom: 3px solid var(--kaauh-teal);
font-weight: 600;
}
/* Right Column Tabs (Parsed Data/Activity) */
.right-column-card .nav-tabs {
padding: 0;
margin-bottom: 0;
border-bottom: none;
background-color: transparent;
}
.right-column-card .nav-link {
padding: 0.9rem 1rem;
font-size: 0.95rem;
font-weight: 600;
color: var(--kaauh-primary-text);
border-right: 1px solid var(--kaauh-border);
border-bottom: 1px solid var(--kaauh-border);
background-color: #f8f9fa;
}
.right-column-card .nav-item:last-child .nav-link {
border-right: none;
}
.right-column-card .nav-link.active {
background-color: white;
color: var(--kaauh-teal-dark);
border-bottom: 3px solid var(--kaauh-teal);
border-right-color: transparent;
margin-bottom: -1px;
}
.right-column-card .tab-content {
padding: 1.5rem 1.25rem;
background-color: white;
}
/* ==================================== */
/* NEW: PARSED DATA GRID OPTIMIZATION */
/* ==================================== */
.parsed-data-item {
/* Ensure the border/bg container takes full width of the grid column */
width: 100%;
}
.parsed-data-item .data-value {
/* Allow data values to wrap without breaking the layout */
word-wrap: break-word;
word-break: break-word;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<div class="row g-4">
{# LEFT COLUMN: MAIN CANDIDATE DETAILS AND TABS #}
<div class="col-lg-8">
<div class="card shadow-sm no-hover">
{# HEADER SECTION (The original Candidate Header Card content, redesigned) #}
<div class="candidate-header-card">
<div class="d-flex justify-content-between align-items-start flex-wrap">
<div>
<h1 class="h3 mb-2">{{ candidate.name }}</h1>
<div class="d-flex align-items-center gap-2 mb-2">
<span class="badge {% if candidate.applied %}bg-success{% else %}bg-warning{% endif %}">
{{ candidate.applied|yesno:"Applied,Pending" }}
</span>
<span id="stageDisplay" class="badge"
data-class="{'bg-primary': $stage == 'Applied', 'bg-info': $stage == 'Exam', 'bg-warning': $stage == 'Interview', 'bg-success': $stage == 'Offer'}"
data-signals-stage="'{{ candidate.stage }}'">
{% trans "Stage:" %}
<span data-text="$stage"></span>
</span>
</div>
<small class="text-white opacity-75">
{% trans "Applied for:" %} <strong>{{ candidate.job.title }}</strong>
</small>
</div>
{# Action buttons moved to the right column, keeping only the most visible here for quick access if preferred #}
{% if user.is_staff %}
<button type="button" class="btn btn-outline-light btn-sm mt-1" data-bs-toggle="modal" data-bs-target="#stageUpdateModal">
<i class="fas fa-exchange-alt"></i> {% trans "Change Stage" %}
</button>
{% endif %}
</div>
</div>
{# LEFT TABS NAVIGATION #}
<ul class="nav nav-tabs main-tabs" id="candidateTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="contact-tab" data-bs-toggle="tab" data-bs-target="#contact-pane" type="button" role="tab" aria-controls="contact-pane" aria-selected="true">
<i class="fas fa-id-card me-1"></i> {% trans "Contact & Job" %}
</button>
</li>
{% if candidate.resume %}
<li class="nav-item" role="presentation">
<button class="nav-link" id="resume-tab" data-bs-toggle="tab" data-bs-target="#resume-pane" type="button" role="tab" aria-controls="resume-pane" aria-selected="false">
<i class="fas fa-file-pdf me-1"></i> {% trans "Resume" %}
</button>
</li>
{% endif %}
{% if candidate.parsed_summary %}
<li class="nav-item" role="presentation">
<button class="nav-link" id="summary-tab" data-bs-toggle="tab" data-bs-target="#summary-pane" type="button" role="tab" aria-controls="summary-pane" aria-selected="false">
<i class="fas fa-chart-bar me-1"></i> {% trans "Summary" %}
</button>
</li>
{% endif %}
</ul>
<div class="card-body">
<div class="tab-content" id="candidateTabsContent">
{# TAB 1 CONTENT: CONTACT & DATES (Original Contact Card) #}
<div class="tab-pane fade show active" id="contact-pane" role="tabpanel" aria-labelledby="contact-tab">
<h5 class="text-primary mb-4">{% trans "Core Details" %}</h5>
<div class="row g-4">
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-envelope fa-2x text-muted me-3"></i>
<div>
<small class="text-muted d-block">{% trans "Email" %}</small>
<strong>{{ candidate.email }}</strong>
</div>
</div>
</div>
<div class="col-md-6">
<div class="d-flex align-items-center">
<i class="fas fa-briefcase fa-2x text-muted me-3"></i>
<div>
<small class="text-muted d-block">{% trans "Position Applied" %}</small>
<strong>{{ candidate.job.title }}</strong>
</div>
</div>
</div>
<div class="col-12">
<div class="d-flex align-items-center">
<i class="fas fa-calendar-check fa-2x text-muted me-3"></i>
<div>
<small class="text-muted d-block">{% trans "Applied Date" %}</small>
<div class="d-flex align-items-center gap-2">
<strong>{{ candidate.created_at|date:"M d, Y H:i" }}</strong>
<span class="badge bg-light text-dark">
<i class="far fa-clock me-1"></i>
{{ candidate.created_at|naturaltime }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
{# TAB 2 CONTENT: RESUME (Original Resume Card) #}
{% if candidate.resume %}
<div class="tab-pane fade" id="resume-pane" role="tabpanel" aria-labelledby="resume-tab">
<h5 class="text-primary mb-4">{% trans "Resume Document" %}</h5>
<div class="d-flex align-items-center justify-content-between p-3 border rounded">
<div>
<p class="mb-1"><strong>{{ candidate.resume.name }}</strong></p>
<small class="text-muted">{{ candidate.resume.name|truncatechars:30 }}</small>
</div>
<a href="{{ candidate.resume.url }}" download class="btn btn-main-action">
<i class="fas fa-download me-1"></i>
{% trans "Download Resume" %}
</a>
</div>
</div>
{% endif %}
{# TAB 3 CONTENT: PARSED SUMMARY (Original Parsed Summary Card) #}
{% if candidate.parsed_summary %}
<div class="tab-pane fade" id="summary-pane" role="tabpanel" aria-labelledby="summary-tab">
<h5 class="text-primary mb-4">{% trans "AI Generated Summary" %}</h5>
<div class="border-start border-primary ps-3 pt-1 pb-1">
<p class="mb-0 text-secondary">{{ candidate.parsed_summary|linebreaks }}</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{# RIGHT COLUMN: ACTIONS AND PARSED DATA TABS #}
<div class="col-lg-4">
{# ACTIONS CARD (The new consolidated action card) #}
{% if user.is_staff %}
<div class="card shadow-sm mb-4 p-3">
<h5 class="text-muted mb-3"><i class="fas fa-cog me-2"></i>{% trans "Management Actions" %}</h5>
<div class="d-grid gap-2">
{# MODAL TRIGGER #}
{% comment %} <button type="button" class="btn btn-main-action" data-bs-toggle="modal" data-bs-target="#stageUpdateModal">
<i class="fas fa-exchange-alt"></i> {% trans "Update Stage" %}
</button> {% endcomment %}
<a href="{% url 'candidate_update' candidate.slug %}" class="btn btn-outline-primary">
<i class="fas fa-edit"></i> {% trans "Edit Details" %}
</a>
<a href="{% url 'candidate_delete' candidate.slug %}" class="btn btn-outline-danger" onclick="return confirm('{% trans "Are you sure you want to delete this candidate?" %}')">
<i class="fas fa-trash-alt"></i> {% trans "Delete Candidate" %}
</a>
<a href="{% url 'candidate_list' %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left"></i> {% trans "Back to List" %}
</a>
</div>
</div>
{% endif %}
{# PARSED DATA TABS (Original Parsed Data Card, now tabbed) #}
{% if parsed %}
<div class="card right-column-card shadow-sm">
<ul class="nav nav-tabs" id="parsedDataTabs" role="tablist">
<li class="nav-item flex-fill" role="presentation">
<button class="nav-link active" id="data-tab" data-bs-toggle="tab" data-bs-target="#data-pane" type="button" role="tab" aria-controls="data-pane" aria-selected="true">
<i class="fas fa-database me-1"></i> {% trans "Parsed Data" %}
</button>
</li>
<li class="nav-item flex-fill" role="presentation">
<button class="nav-link" id="activity-tab" data-bs-toggle="tab" data-bs-target="#activity-pane" type="button" role="tab" aria-controls="activity-pane" aria-selected="false">
<i class="fas fa-history me-1"></i> {% trans "Activity" %}
</button>
</li>
</ul>
<div class="tab-content" id="parsedDataTabsContent">
{# TAB 1: PARSED DATA - UPDATED TO 2-COLUMN GRID #}
<div class="tab-pane fade show active" id="data-pane" role="tabpanel" aria-labelledby="data-tab">
<h6 class="text-muted small text-uppercase mb-3">{% trans "Structured Resume Data" %}</h6>
<div class="row g-3">
{% for key, value in parsed.items %}
<div class="col-md-6 parsed-data-item">
<div class="p-3 border rounded h-100 bg-light">
<h6 class="text-muted small text-uppercase mb-1">
<i class="fas fa-tag me-1 text-primary"></i> {{ key|title }}
</h6>
<p class="mb-0 text-dark small data-value">
{{ value|default:"N/A"|linebreaksbr }}
</p>
</div>
</div>
{% endfor %}
</div>
</div>
{# TAB 2: ACTIVITY (Placeholder) #}
<div class="tab-pane fade" id="activity-pane" role="tabpanel" aria-labelledby="activity-tab">
<p class="text-muted">
{% trans "Activity feed (e.g., stage changes, notes, interview history) will appear here." %}
</p>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
{% if user.is_staff %}
{% include "recruitment/partials/stage_update_modal.html" with candidate=candidate form=stage_form %}
{% endif %}
{% endblock %}