kaauh_ats/templates/recruitment/agency_assignment_detail.html
2025-10-30 18:00:51 +03:00

519 lines
22 KiB
HTML

{% extends 'base.html' %}
{% load static i18n %}
{% block title %}{{ assignment.agency.name }} - {{ assignment.job.title }} - ATS{% endblock %}
{% block customCSS %}
<style>
/* KAAT-S UI Variables */
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--kaauh-border: #eaeff3;
--kaauh-primary-text: #343a40;
--kaauh-success: #28a745;
--kaauh-info: #17a2b8;
--kaauh-danger: #dc3545;
--kaauh-warning: #ffc107;
}
.kaauh-card {
border: 1px solid var(--kaauh-border);
border-radius: 0.75rem;
box-shadow: 0 4px 12px rgba(0,0,0,0.06);
background-color: white;
}
.btn-main-action {
background-color: var(--kaauh-teal);
border-color: var(--kaauh-teal);
color: white;
font-weight: 600;
transition: all 0.2s ease;
}
.btn-main-action:hover {
background-color: var(--kaauh-teal-dark);
border-color: var(--kaauh-teal-dark);
box-shadow: 0 4px 8px rgba(0,0,0,0.15);
}
.status-badge {
font-size: 0.75rem;
padding: 0.3em 0.7em;
border-radius: 0.35rem;
font-weight: 700;
}
.status-ACTIVE { background-color: var(--kaauh-success); color: white; }
.status-EXPIRED { background-color: var(--kaauh-danger); color: white; }
.status-COMPLETED { background-color: var(--kaauh-info); color: white; }
.status-CANCELLED { background-color: var(--kaauh-warning); color: #856404; }
.progress-ring {
width: 120px;
height: 120px;
position: relative;
}
.progress-ring-circle {
transition: stroke-dashoffset 0.35s;
transform: rotate(-90deg);
transform-origin: 50% 50%;
}
.progress-ring-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 1.5rem;
font-weight: 700;
color: var(--kaauh-teal-dark);
}
.message-item {
border-left: 4px solid var(--kaauh-teal);
background-color: #f8f9fa;
padding: 1rem;
margin-bottom: 1rem;
border-radius: 0 0.5rem 0.5rem 0;
}
.message-item.unread {
border-left-color: var(--kaauh-info);
background-color: #e7f3ff;
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- Header -->
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h3 mb-1" style="color: var(--kaauh-teal-dark); font-weight: 700;">
<i class="fas fa-tasks me-2"></i>
{{ assignment.agency.name }} - {{ assignment.job.title }}
</h1>
<p class="text-muted mb-0">
{% trans "Assignment Details and Management" %}
</p>
</div>
<div>
<a href="{% url 'agency_assignment_list' %}" class="btn btn-outline-secondary me-2">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Assignments" %}
</a>
<a href="{% url 'agency_assignment_update' assignment.slug %}" class="btn btn-main-action">
<i class="fas fa-edit me-1"></i> {% trans "Edit Assignment" %}
</a>
</div>
</div>
<div class="row">
<!-- Assignment Overview -->
<div class="col-lg-8">
<!-- Assignment Details Card -->
<div class="kaauh-card p-4 mb-4">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-info-circle me-2"></i>
{% trans "Assignment Details" %}
</h5>
<div class="row">
<div class="col-md-6">
<div class="mb-3">
<label class="text-muted small">{% trans "Agency" %}</label>
<div class="fw-bold">{{ assignment.agency.name }}</div>
<div class="text-muted small">{{ assignment.agency.contact_person }}</div>
</div>
<div class="mb-3">
<label class="text-muted small">{% trans "Job" %}</label>
<div class="fw-bold">{{ assignment.job.title }}</div>
<div class="text-muted small">{{ assignment.job.department }}</div>
</div>
</div>
<div class="col-md-6">
<div class="mb-3">
<label class="text-muted small">{% trans "Status" %}</label>
<div>
<span class="status-badge status-{{ assignment.status }}">
{{ assignment.get_status_display }}
</span>
</div>
</div>
<div class="mb-3">
<label class="text-muted small">{% trans "Deadline" %}</label>
<div class="{% if assignment.is_expired %}text-danger{% else %}text-muted{% endif %}">
<i class="fas fa-calendar-alt me-1"></i>
{{ assignment.deadline_date|date:"Y-m-d H:i" }}
</div>
{% if assignment.is_expired %}
<small class="text-danger">
<i class="fas fa-exclamation-triangle me-1"></i>{% trans "Expired" %}
</small>
{% endif %}
</div>
</div>
</div>
{% if assignment.admin_notes %}
<div class="mt-3 pt-3 border-top">
<label class="text-muted small">{% trans "Admin Notes" %}</label>
<div class="text-muted">{{ assignment.admin_notes }}</div>
</div>
{% endif %}
</div>
<div class="kaauh-card shadow-sm mb-4">
<div class="card-body my-2">
<h5 class="card-title mb-3 mx-2">
<i class="fas fa-key me-2 text-warning"></i>
{% trans "Access Credentials" %}
</h5>
<div class="mb-3 mx-2">
<label class="form-label text-muted small">{% trans "Login URL" %}</label>
<div class="input-group">
<input type="text" readonly value="{{ request.scheme }}://{{ request.get_host }}{% url 'agency_portal_login' %}"
class="form-control font-monospace" id="loginUrl">
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('loginUrl')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="mb-3 mx-2">
<label class="form-label text-muted small">{% trans "Access Token" %}</label>
<div class="input-group">
<input type="text" readonly value="{{ access_link.unique_token }}"
class="form-control font-monospace" id="accessToken">
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('accessToken')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="mb-3 mx-2">
<label class="form-label text-muted small">{% trans "Password" %}</label>
<div class="input-group">
<input type="text" readonly value="{{ access_link.access_password }}"
class="form-control font-monospace" id="accessPassword">
<button class="btn btn-outline-secondary" type="button" onclick="copyToClipboard('accessPassword')">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
<div class="alert alert-info mx-2">
<i class="fas fa-info-circle me-2"></i>
{% trans "Share these credentials securely with the agency. They can use this information to log in and submit candidates." %}
</div>
<a href="{% url 'agency_access_link_detail' access_link.slug %}"
class="btn btn-outline-info btn-sm mx-2">
<i class="fas fa-eye me-1"></i> {% trans "View Access Links Details" %}
</a>
</div>
</div>
<!-- Candidates Card -->
<div class="kaauh-card p-4">
<div class="d-flex justify-content-between align-items-center mb-4">
<h5 class="mb-0" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-users me-2"></i>
{% trans "Submitted Candidates" %} ({{ total_candidates }})
</h5>
{% if access_link %}
<a href="{% url 'agency_portal_login' %}" target="_blank" class="btn btn-outline-info btn-sm">
<i class="fas fa-external-link-alt me-1"></i> {% trans "Preview Portal" %}
</a>
{% endif %}
</div>
{% if candidates %}
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Contact" %}</th>
<th>{% trans "Stage" %}</th>
<th>{% trans "Submitted" %}</th>
<th>{% trans "Actions" %}</th>
</tr>
</thead>
<tbody>
{% for candidate in candidates %}
<tr>
<td>
<div class="fw-bold">{{ candidate.name }}</div>
</td>
<td>
<div class="small">
<div><i class="fas fa-envelope me-1"></i> {{ candidate.email }}</div>
<div><i class="fas fa-phone me-1"></i> {{ candidate.phone }}</div>
</div>
</td>
<td>
<span class="badge bg-info">{{ candidate.get_stage_display }}</span>
</td>
<td>
<div class="small text-muted">
{{ candidate.created_at|date:"Y-m-d H:i" }}
</div>
</td>
<td>
<a href="{% url 'candidate_detail' candidate.slug %}"
class="btn btn-sm btn-outline-primary" title="{% trans 'View Details' %}">
<i class="fas fa-eye"></i>
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% else %}
<div class="text-center py-4">
<i class="fas fa-users fa-2x text-muted mb-3"></i>
<h6 class="text-muted">{% trans "No candidates submitted yet" %}</h6>
<p class="text-muted small">
{% trans "Candidates will appear here once the agency submits them through their portal." %}
</p>
</div>
{% endif %}
</div>
</div>
<!-- Sidebar -->
<div class="col-lg-4">
<!-- Progress Card -->
<div class="kaauh-card p-4 mb-4">
<h5 class="mb-4 text-center" style="color: var(--kaauh-teal-dark);">
{% trans "Submission Progress" %}
</h5>
<div class="text-center mb-3">
<div class="progress-ring">
<svg width="120" height="120">
<circle class="progress-ring-circle"
stroke="#e9ecef"
stroke-width="8"
fill="transparent"
r="52"
cx="60"
cy="60"/>
<circle class="progress-ring-circle"
stroke="var(--kaauh-teal)"
stroke-width="8"
fill="transparent"
r="52"
cx="60"
cy="60"
style="stroke-dasharray: 326.73; stroke-dashoffset: {{ stroke_dashoffset }};"/>
</svg>
<div class="progress-ring-text">
{% widthratio total_candidates assignment.max_candidates 100 as progress %}
{{ progress|floatformat:0 }}%
</div>
</div>
</div>
<div class="text-center">
<div class="h4 mb-1">{{ total_candidates }}</div>
<div class="text-muted">/ {{ assignment.max_candidates }} {% trans "candidates" %}</div>
</div>
<div class="progress mt-3" style="height: 8px;">
{% widthratio total_candidates assignment.max_candidates 100 as progress %}
<div class="progress-bar" style="width: {{ progress }}%"></div>
</div>
</div>
<!-- Actions Card -->
<div class="kaauh-card p-4">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-cog me-2"></i>
{% trans "Actions" %}
</h5>
<div class="d-grid gap-2">
<a href=""
class="btn btn-outline-primary">
<i class="fas fa-envelope me-1"></i> {% trans "Send Message" %}
</a>
{% if assignment.is_active and not assignment.is_expired %}
<button type="button" class="btn btn-outline-warning"
data-bs-toggle="modal" data-bs-target="#extendDeadlineModal">
<i class="fas fa-clock me-1"></i> {% trans "Extend Deadline" %}
</button>
{% endif %}
<a href="{% url 'agency_assignment_update' assignment.slug %}"
class="btn btn-outline-secondary">
<i class="fas fa-edit me-1"></i> {% trans "Edit Assignment" %}
</a>
</div>
</div>
</div>
</div>
<!-- Messages Section -->
{% if messages_ %}
<div class="kaauh-card p-4 mt-4">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-comments me-2"></i>
{% trans "Recent Messages" %}
</h5>
<div class="row">
{% for message in messages_|slice:":6" %}
<div class="col-lg-6 mb-3">
<div class="message-item {% if not message.is_read %}unread{% endif %}">
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="fw-bold">{{ message.subject }}</div>
<small class="text-muted">{{ message.created_at|date:"Y-m-d H:i" }}</small>
</div>
<div class="small text-muted mb-2">
{% trans "From" %}: {{ message.sender.get_full_name }}
</div>
<div class="small">{{ message.message|truncatewords:30 }}</div>
{% if not message.is_read %}
<span class="badge bg-info mt-2">{% trans "New" %}</span>
{% endif %}
</div>
</div>
{% endfor %}
</div>
{% if messages_.count > 6 %}
<div class="text-center mt-3">
<a href="#" class="btn btn-outline-primary btn-sm">
{% trans "View All Messages" %}
</a>
</div>
{% endif %}
</div>
{% endif %}
</div>
<!-- Extend Deadline Modal -->
<div class="modal fade" id="extendDeadlineModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">
<i class="fas fa-clock me-2"></i>
{% trans "Extend Assignment Deadline" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form method="post" action="{% url 'agency_assignment_extend_deadline' assignment.slug %}">
{% csrf_token %}
<div class="modal-body">
<div class="mb-3">
<label for="new_deadline" class="form-label">
{% trans "New Deadline" %} <span class="text-danger">*</span>
</label>
<input type="datetime-local" class="form-control" id="new_deadline"
name="new_deadline" required>
<small class="form-text text-muted">
{% trans "Current deadline:" %} {{ assignment.deadline_date|date:"Y-m-d H:i" }}
</small>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
{% trans "Cancel" %}
</button>
<button type="submit" class="btn btn-main-action">
<i class="fas fa-clock me-1"></i> {% trans "Extend Deadline" %}
</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}
<script>
function copyToClipboard(text) {
navigator.clipboard.writeText(text).then(function() {
// Show success message
const toast = document.createElement('div');
toast.className = 'position-fixed top-0 end-0 p-3';
toast.style.zIndex = '1050';
toast.innerHTML = `
<div class="toast show" role="alert">
<div class="toast-header">
<strong class="me-auto">{% trans "Success" %}</strong>
<button type="button" class="btn-close" data-bs-dismiss="toast"></button>
</div>
<div class="toast-body">
{% trans "Token copied to clipboard!" %}
</div>
</div>
`;
document.body.appendChild(toast);
setTimeout(() => {
toast.remove();
}, 3000);
});
}
function copyToClipboard(elementId) {
const element = document.getElementById(elementId);
element.select();
document.execCommand('copy');
// Show feedback
const button = element.nextElementSibling;
const originalHTML = button.innerHTML;
button.innerHTML = '<i class="fas fa-check"></i>';
button.classList.add('btn-success');
button.classList.remove('btn-outline-secondary');
setTimeout(() => {
button.innerHTML = originalHTML;
button.classList.remove('btn-success');
button.classList.add('btn-outline-secondary');
}, 2000);
}
function confirmDeactivate() {
if (confirm('{% trans "Are you sure you want to deactivate this access link? Agencies will no longer be able to use it." %}')) {
// Submit form to deactivate
window.location.href = '{% url "agency_access_link_deactivate" access_link.slug %}';
}
}
function confirmReactivate() {
if (confirm('{% trans "Are you sure you want to reactivate this access link?" %}')) {
// Submit form to reactivate
window.location.href = '{% url "agency_access_link_reactivate" access_link.slug %}';
}
}
document.addEventListener('DOMContentLoaded', function() {
// Set minimum datetime for new deadline
const deadlineInput = document.getElementById('new_deadline');
if (deadlineInput) {
const currentDeadline = new Date('{{ assignment.deadline_date|date:"Y-m-d\\TH:i" }}');
const now = new Date();
const minDateTime = new Date(Math.max(currentDeadline, now));
const localDateTime = new Date(minDateTime.getTime() - minDateTime.getTimezoneOffset() * 60000)
.toISOString()
.slice(0, 16);
deadlineInput.min = localDateTime;
deadlineInput.value = localDateTime;
}
});
</script>
{% endblock %}