kaauh_ats/templates/recruitment/agency_portal_submit_candidate.html

413 lines
15 KiB
HTML

{% extends 'portal_base.html' %}
{% load static i18n crispy_forms_tags %}
{% block title %}{% trans "Submit Candidate" %} - {{ assignment.job.title }} - Agency Portal{% 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);
}
.form-control:focus {
border-color: var(--kaauh-teal);
box-shadow: 0 0 0 0.2rem rgba(0, 99, 110, 0.25);
}
.form-select:focus {
border-color: var(--kaauh-teal);
box-shadow: 0 0 0 0.2rem rgba(0, 99, 110, 0.25);
}
.file-upload-area {
border: 2px dashed var(--kaauh-border);
border-radius: 0.5rem;
padding: 2rem;
text-align: center;
transition: all 0.3s ease;
background-color: #f8f9fa;
}
.file-upload-area:hover {
border-color: var(--kaauh-teal);
background-color: #e9ecef;
}
.file-upload-area.has-file {
border-color: var(--kaauh-success);
background-color: #d4edda;
}
.progress-indicator {
height: 4px;
background-color: var(--kaauh-teal);
border-radius: 2px;
transition: width 0.3s ease;
}
.assignment-info {
background: linear-gradient(135deg, var(--kaauh-teal) 0%, var(--kaauh-teal-dark) 100%);
color: white;
border-radius: 0.75rem;
padding: 1.5rem;
}
.required-field::after {
content: " *";
color: var(--kaauh-danger);
}
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- Breadcrumb Navigation -->
<nav aria-label="breadcrumb" class="mb-4">
<ol class="breadcrumb">
<li class="breadcrumb-item">
<a href="{% url 'agency_portal_dashboard' %}" class="text-decoration-none text-secondary">
<i class="fas fa-home me-1"></i>{% trans "Dashboard" %}
</a>
</li>
{% comment %} <li class="breadcrumb-item active" aria-current="page">
{% trans "Submit Candidate" %}
</li> {% endcomment %}
<li class="breadcrumb-item active" aria-current="page" style="
color: #F43B5E; /* Rosy Accent Color */
font-weight: 600; ">
{% trans "Submit Candidate" %}</li>
</ol>
</nav>
<!-- 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-user-plus me-2"></i>
{% trans "Submit New Candidate" %}
</h1>
<p class="text-muted mb-0">
<!-- Button trigger modal -->
{% trans "Submit a candidate for" %}
{{ assignment.job.title }}
</p>
</div>
<div>
<a href="{% url 'agency_portal_assignment_detail' assignment.slug %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Assignment" %}
</a>
</div>
</div>
<div class="row">
<!-- Assignment Info Card -->
<div class="col-lg-4 mb-4">
<div class="assignment-info">
<h5 class="mb-3">
<i class="fas fa-info-circle me-2"></i>
{% trans "Assignment Details" %}
</h5>
<div class="mb-2">
<strong>{% trans "Position:" %}</strong> {{ assignment.job.title }}
</div>
<div class="mb-2">
<strong>{% trans "Department:" %}</strong> {{ assignment.job.department|default:"N/A" }}
</div>
<div class="mb-2">
<strong>{% trans "Deadline:" %}</strong> {{ assignment.deadline_date|date:"Y-m-d H:i" }}
</div>
<div class="mb-2">
<strong>{% trans "Days Remaining:" %}</strong>
<span class="{% if assignment.days_remaining <= 3 %}text-warning{% endif %}">
{{ assignment.days_remaining }} {% trans "days" %}
</span>
</div>
<div class="mb-2">
<strong>{% trans "Submitted:" %}</strong> {{ total_submitted }}/{{ assignment.max_candidates }}
</div>
<div>
<strong>{% trans "Status:" %}</strong>
{% if assignment.can_submit %}
<span class="badge bg-success">{% trans "Can Submit" %}</span>
{% else %}
<span class="badge bg-danger">{% trans "Cannot Submit" %}</span>
{% endif %}
</div>
</div>
</div>
<!-- Submission Form -->
<div class="col-lg-8">
{% if assignment.can_submit %}
<div class="kaauh-card p-4">
<h5 class="mb-4" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-user-edit me-2"></i>
{% trans "Candidate Information" %}
</h5>
<form method="post" enctype="multipart/form-data" id="candidateForm"
action="{% url 'agency_portal_submit_application_page' assignment.slug %}">
{% csrf_token %}
{{form|crispy}}
<button type="submit" class="btn btn-main-action">
<i class="fas fa-user-plus me-2"></i>
{% trans "Submit Candidate" %}
</button>
</form>
</div>
{% else %}
<div class="kaauh-card p-4">
<div class="text-center py-5">
<i class="fas fa-exclamation-triangle fa-4x text-warning mb-4"></i>
<h4 class="text-warning mb-3">{% trans "Cannot Submit Candidates" %}</h4>
<div class="alert alert-warning d-inline-block">
{% if assignment.is_expired %}
<i class="fas fa-clock me-2"></i>
{% trans "This assignment has expired. Submissions are no longer accepted." %}
{% elif assignment.is_full %}
<i class="fas fa-users me-2"></i>
{% trans "Maximum candidate limit reached for this assignment." %}
{% else %}
<i class="fas fa-pause me-2"></i>
{% trans "This assignment is not currently active." %}
{% endif %}
</div>
<div class="mt-4">
<a href="{% url 'agency_assignment_detail' assignment.slug %}" class="btn btn-outline-primary">
<i class="fas fa-arrow-left me-1"></i>
{% trans "Back to Assignment" %}
</a>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Loading Overlay -->
<div class="modal fade" id="loadingModal" tabindex="-1" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-body text-center py-4">
<div class="spinner-border text-primary mb-3" role="status">
<span class="visually-hidden">{% trans "Loading..." %}</span>
</div>
<h6>{% trans "Submitting candidate..." %}</h6>
<p class="text-muted small">{% trans "Please wait while we process your submission." %}</p>
</div>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const fileInput = document.getElementById('resume');
const fileUploadArea = document.getElementById('fileUploadArea');
const uploadPlaceholder = document.getElementById('uploadPlaceholder');
const filePreview = document.getElementById('filePreview');
const fileName = document.getElementById('fileName');
const removeFileBtn = document.getElementById('removeFile');
const form = document.getElementById('candidateForm');
const submitBtn = document.getElementById('submitBtn');
// File upload area click handler
fileUploadArea.addEventListener('click', function() {
fileInput.click();
});
// Drag and drop handlers
fileUploadArea.addEventListener('dragover', function(e) {
e.preventDefault();
this.classList.add('border-primary');
});
fileUploadArea.addEventListener('dragleave', function(e) {
e.preventDefault();
this.classList.remove('border-primary');
});
fileUploadArea.addEventListener('drop', function(e) {
e.preventDefault();
this.classList.remove('border-primary');
const files = e.dataTransfer.files;
if (files.length > 0) {
fileInput.files = files;
handleFileSelect(files[0]);
}
});
// File input change handler
fileInput.addEventListener('change', function() {
if (this.files.length > 0) {
handleFileSelect(this.files[0]);
}
});
// Remove file handler
removeFileBtn.addEventListener('click', function() {
fileInput.value = '';
uploadPlaceholder.classList.remove('d-none');
filePreview.classList.add('d-none');
fileUploadArea.classList.remove('has-file');
});
// Handle file selection
function handleFileSelect(file) {
// Validate file type
const allowedTypes = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
if (!allowedTypes.includes(file.type)) {
alert('{% trans "Please upload a PDF, DOC, or DOCX file." %}');
return;
}
// Validate file size (5MB)
const maxSize = 5 * 1024 * 1024; // 5MB in bytes
if (file.size > maxSize) {
alert('{% trans "File size must be less than 5MB." %}');
return;
}
// Show file preview
fileName.textContent = file.name;
uploadPlaceholder.classList.add('d-none');
filePreview.classList.remove('d-none');
fileUploadArea.classList.add('has-file');
}
// Form submission handler
form.addEventListener('submit', function(e) {
e.preventDefault();
// Show loading modal
const loadingModal = new bootstrap.Modal(document.getElementById('loadingModal'));
loadingModal.show();
// Disable submit button
submitBtn.disabled = true;
submitBtn.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> {% trans "Submitting..." %}';
const formData = new FormData(this);
fetch(this.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest'
}
})
.then(response => response.json())
.then(data => {
loadingModal.hide();
if (data.success) {
// Show success message
const successAlert = document.createElement('div');
successAlert.className = 'alert alert-success alert-dismissible fade show position-fixed';
successAlert.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
successAlert.innerHTML = `
<i class="fas fa-check-circle me-2"></i>
{% trans "Candidate submitted successfully!" %}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(successAlert);
// Reset form
form.reset();
fileInput.value = '';
uploadPlaceholder.classList.remove('d-none');
filePreview.classList.add('d-none');
fileUploadArea.classList.remove('has-file');
// Remove alert after 5 seconds
setTimeout(() => {
if (successAlert.parentNode) {
successAlert.parentNode.removeChild(successAlert);
}
}, 5000);
// Redirect to assignment detail after 2 seconds
setTimeout(() => {
window.location.href = '{% url "agency_portal_assignment_detail" assignment.slug %}';
}, 2000);
} else {
// Show error message
const errorAlert = document.createElement('div');
errorAlert.className = 'alert alert-danger alert-dismissible fade show position-fixed';
errorAlert.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
errorAlert.innerHTML = `
<i class="fas fa-exclamation-triangle me-2"></i>
${data.message || '{% trans "Error submitting candidate. Please try again." %}'}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(errorAlert);
// Remove alert after 5 seconds
setTimeout(() => {
if (errorAlert.parentNode) {
errorAlert.parentNode.removeChild(errorAlert);
}
}, 5000);
}
})
.catch(error => {
loadingModal.hide();
console.error('Error:', error);
const errorAlert = document.createElement('div');
errorAlert.className = 'alert alert-danger alert-dismissible fade show position-fixed';
errorAlert.style.cssText = 'position: fixed; top: 20px; right: 20px; z-index: 9999; min-width: 300px;';
errorAlert.innerHTML = `
<i class="fas fa-exclamation-triangle me-2"></i>
{% trans "Network error. Please check your connection and try again." %}
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
`;
document.body.appendChild(errorAlert);
})
.finally(() => {
// Re-enable submit button
submitBtn.disabled = false;
submitBtn.innerHTML = '<i class="fas fa-paper-plane me-1"></i> {% trans "Submit Candidate" %}';
});
});
// Auto-focus on first field
document.getElementById('first_name').focus();
});
</script>
{% endblock %}