kaauh_ats/templates/interviews/schedule_interviews.html

298 lines
11 KiB
HTML

{% extends 'base.html' %}
{% load static i18n %}
{% block title %}Bulk Interview Scheduling - {{ job.title }} - ATS{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<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;
}
/* 1. Card & Container Styling */
.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;
padding: 1.5rem;
}
.container-fluid.py-4 { padding-top: 1.5rem !important; padding-bottom: 1.5rem !important; }
/* 2. Typography & Headers */
.page-header {
color: var(--kaauh-teal-dark);
font-weight: 700;
}
.section-header {
color: var(--kaauh-primary-text);
font-weight: 600;
border-bottom: 2px solid var(--kaauh-border);
padding-bottom: 0.5rem;
margin-bottom: 1rem;
}
label {
font-weight: 500;
color: var(--kaauh-primary-text);
font-size: 0.9rem;
margin-bottom: 0.25rem;
}
.form-control, .form-select {
border-radius: 0.5rem;
border: 1px solid #ced4da;
padding: 0.5rem 0.75rem;
font-size: 0.9rem;
}
.form-group > .form-check {
margin-top: 0.5rem;
}
/* FIX: SCROLLABLE CANDIDATE LIST */
.form-group select[multiple] {
max-height: 450px;
overflow-y: auto;
min-height: 250px;
padding: 0;
}
/* 3. Button Styling */
.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);
}
.btn-secondary {
color: var(--kaauh-teal-dark);
border-color: var(--kaauh-border);
background-color: #f1f3f4;
}
/* 4. Break Times Section Styling */
.break-time-form {
background-color: #f8f9fa;
padding: 0.75rem;
border-radius: 0.5rem;
border: 1px solid var(--kaauh-border);
align-items: flex-end;
}
.remove-break {
width: 100%;
}
.note-box {
background-color: #fff3cd;
border-left: 5px solid var(--kaauh-warning);
padding: 1rem;
border-radius: 0.25rem;
font-size: 0.9rem;
margin-bottom: 1rem;
}
</style>
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h1 class="h3 page-header">
<i class="fas fa-calendar-alt me-2"></i>
{% trans "Bulk Interview Scheduling" %}
</h1>
<h2 class="h5 text-muted mb-0">
{% trans "Configure time slots for:" %} **{{ job.title }}**
</h2>
</div>
<a href="{% url 'job_detail' slug=job.slug %}" class="btn btn-outline-secondary">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Job" %}
</a>
</div>
<div class="kaauh-card shadow-sm">
<form method="post" id="schedule-form">
{% csrf_token %}
<div class="row">
<div class="col-md-4">
<h5 class="section-header">{% trans "Select Candidates" %}</h5>
<div class="form-group">
<label for="{{ form.candidates.id_for_label }}">
{% trans "Candidates to Schedule (Hold Ctrl/Cmd to select multiple)" %}
</label>
{{ form.candidates }}
{% if form.candidates.errors %}
<div class="text-danger small mt-1">{{ form.candidates.errors }}</div>
{% endif %}
</div>
</div>
<div class="col-md-8">
<h5 class="section-header">{% trans "Schedule Details" %}</h5>
<div class="row">
<div class="col-md-6">
<div class="form-group mb-3">
<label for="{{ form.start_date.id_for_label }}">{% trans "Start Date" %}</label>
{{ form.start_date }}
</div>
</div>
<div class="col-md-6">
<div class="form-group mb-3">
<label for="{{ form.end_date.id_for_label }}">{% trans "End Date" %}</label>
{{ form.end_date }}
</div>
</div>
</div>
<div class="form-group mb-3">
<label>{% trans "Working Days" %}</label>
<div class="d-flex flex-wrap gap-3 p-2 border rounded" style="background-color: #f8f9fa;">
{{ form.working_days }}
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="form-group mb-3">
<label for="{{ form.start_time.id_for_label }}">{% trans "Start Time" %}</label>
{{ form.start_time }}
</div>
</div>
<div class="col-md-3">
<div class="form-group mb-3">
<label for="{{ form.end_time.id_for_label }}">{% trans "End Time" %}</label>
{{ form.end_time }}
</div>
</div>
<div class="col-md-3">
<div class="form-group mb-3">
<label for="{{ form.interview_duration.id_for_label }}">{% trans "Duration (min)" %}</label>
{{ form.interview_duration }}
</div>
</div>
<div class="col-md-3">
<div class="form-group mb-3">
<label for="{{ form.buffer_time.id_for_label }}">{% trans "Buffer (min)" %}</label>
{{ form.buffer_time }}
</div>
</div>
</div>
<div class="mt-4 pt-4 border-top">
<h5 class="section-header">{% trans "Daily Break Times" %}</h5>
<div id="break-times-container">
<div class="break-time-form row mb-2 g-2">
<div class="col-5">
<label for="{{ form.break_start_time.id_for_label }}">{% trans "Start Time" %}</label>
{{ form.break_start_time }}
</div>
<div class="col-5">
<label for="{{ form.break_end_time.id_for_label }}">{% trans "End Time" %}</label>
{{ form.break_end_time }}
</div>
</div>
</div>
</div>
</div>
</div>
<div class="mt-4 pt-4 border-top d-flex justify-content-end gap-2">
<button type="submit" class="btn btn-main-action">
<i class="fas fa-calendar-check me-1"></i> {% trans "Preview Schedule" %}
</button>
<a href="{% url 'job_detail' slug=job.slug %}" class="btn btn-secondary">
{% trans "Cancel" %}
</a>
</div>
</form>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const addBreakBtn = document.getElementById('add-break');
const breakTimesContainer = document.getElementById('break-times-container');
// *** FIX: Hardcode formset prefix for reliability (requires matching Python change) ***
const FORMSET_PREFIX = 'breaktime';
const totalFormsInput = document.querySelector(`input[name="${FORMSET_PREFIX}-TOTAL_FORMS"]`);
if (!totalFormsInput) {
console.error(`TOTAL_FORMS input with name ${FORMSET_PREFIX}-TOTAL_FORMS not found. Cannot add break dynamically. Please ensure formset prefix is set to '${FORMSET_PREFIX}' in the Python view and management_form is rendered.`);
return;
}
addBreakBtn.addEventListener('click', function() {
const formCount = parseInt(totalFormsInput.value);
// Template for a new form, ensuring the correct classes are applied
// Use the hardcoded prefix in all new form fields
const newFormHtml = `
<div class="break-time-form row mb-2 g-2">
<div class="col-5">
<label for="id_${FORMSET_PREFIX}-${formCount}-start_time">Start Time</label>
<input type="time" name="${FORMSET_PREFIX}-${formCount}-start_time" class="form-control" id="id_${FORMSET_PREFIX}-${formCount}-start_time">
</div>
<div class="col-5">
<label for="id_${FORMSET_PREFIX}-${formCount}-end_time">End Time</label>
<input type="time" name="${FORMSET_PREFIX}-${formCount}-end_time" class="form-control" id="id_${FORMSET_PREFIX}-${formCount}-end_time">
</div>
<div class="col-2 d-flex align-items-end">
<!-- Hidden management fields for new forms (ID and DELETE) -->
<input type="hidden" name="${FORMSET_PREFIX}-${formCount}-id" id="id_${FORMSET_PREFIX}-${formCount}-id" value="">
<input type="checkbox" name="${FORMSET_PREFIX}-${formCount}-DELETE" id="id_${FORMSET_PREFIX}-${formCount}-DELETE" style="display:none;">
<button type="button" class="btn btn-danger btn-sm remove-break w-100">
<i class="fas fa-trash-alt"></i> Remove
</button>
</div>
</div>
`;
const tempDiv = document.createElement('div');
tempDiv.innerHTML = newFormHtml.trim();
const newForm = tempDiv.firstChild;
breakTimesContainer.appendChild(newForm);
totalFormsInput.value = formCount + 1;
});
// Handle remove button clicks (both existing and dynamically added)
breakTimesContainer.addEventListener('click', function(e) {
if (e.target.closest('.remove-break')) {
const form = e.target.closest('.break-time-form');
if (form) {
const deleteCheckbox = form.querySelector('input[name$="-DELETE"]');
if (deleteCheckbox) {
// Check the DELETE box and hide the form
deleteCheckbox.checked = true;
form.style.display = 'none';
} else {
// If it's a new form, remove it entirely
form.remove();
}
}
}
});
});
</script>
{% endblock %}