208 lines
9.1 KiB
HTML
208 lines
9.1 KiB
HTML
{% extends "base.html" %}
|
|
{% load static i18n %}
|
|
|
|
{% block title %}{% trans "Schedule Meeting" %} - {{ job.title }} - {{ block.super }}{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="px-4 py-6 max-w-2xl mx-auto">
|
|
<!-- Header -->
|
|
<div class="flex flex-col sm:flex-row sm:justify-between sm:items-start gap-4 mb-6">
|
|
<div class="flex-1">
|
|
<h1 class="text-2xl font-bold text-temple-dark mb-1 flex items-center gap-2">
|
|
<i data-lucide="calendar-plus" class="w-7 h-7"></i>
|
|
{% if has_future_meeting %}
|
|
{% trans "Update Interview" %} for {{ application.name }}
|
|
{% else %}
|
|
{% trans "Schedule Interview" %} for {{ application.name }}
|
|
{% endif %}
|
|
</h1>
|
|
<p class="text-gray-600">{% trans "Job" %}: {{ job.title }}</p>
|
|
{% if has_future_meeting %}
|
|
<div class="mt-3 bg-blue-50 border border-blue-200 rounded-lg p-3 flex items-start gap-2">
|
|
<i data-lucide="info" class="w-5 h-5 text-blue-500 flex-shrink-0 mt-0.5"></i>
|
|
<p class="text-sm text-blue-800">
|
|
{% trans "This application has upcoming interviews. You are updating an existing schedule." %}
|
|
</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
<a href="{% url 'applications_interview_view' job.slug %}"
|
|
class="inline-flex items-center gap-2 border border-gray-300 text-gray-700 hover:bg-gray-50 px-4 py-2.5 rounded-lg text-sm font-medium transition">
|
|
<i data-lucide="arrow-left" class="w-4 h-4"></i>
|
|
{% trans "Back to Candidates" %}
|
|
</a>
|
|
</div>
|
|
|
|
<!-- Form Card -->
|
|
<div class="bg-white rounded-xl shadow-md border border-gray-200">
|
|
<div class="p-6">
|
|
<form method="post" id="meetingForm">
|
|
{% csrf_token %}
|
|
|
|
<!-- Topic Field -->
|
|
<div class="mb-6">
|
|
<label for="{{ form.topic.id_for_label }}" class="block text-sm font-semibold text-gray-700 mb-2">
|
|
{% trans "Meeting Topic" %}
|
|
</label>
|
|
{{ form.topic }}
|
|
{% if form.topic.errors %}
|
|
<div class="mt-1 text-sm text-red-600">
|
|
{% for error in form.topic.errors %}
|
|
<p>{{ error }}</p>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
<p class="mt-1 text-sm text-gray-500">
|
|
{% trans "Default topic will be 'Interview: [Job Title] with [Candidate Name]' if left empty." %}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Start Time Field -->
|
|
<div class="mb-6">
|
|
<label for="{{ form.start_time.id_for_label }}" class="block text-sm font-semibold text-gray-700 mb-2">
|
|
{% trans "Start Time" %}
|
|
</label>
|
|
{{ form.start_time }}
|
|
{% if form.start_time.errors %}
|
|
<div class="mt-1 text-sm text-red-600">
|
|
{% for error in form.start_time.errors %}
|
|
<p>{{ error }}</p>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
<p class="mt-1 text-sm text-gray-500">
|
|
{% trans "Please select a date and time for interview." %}
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Duration Field -->
|
|
<div class="mb-8">
|
|
<label for="{{ form.duration.id_for_label }}" class="block text-sm font-semibold text-gray-700 mb-2">
|
|
{% trans "Duration (minutes)" %}
|
|
</label>
|
|
{{ form.duration }}
|
|
{% if form.duration.errors %}
|
|
<div class="mt-1 text-sm text-red-600">
|
|
{% for error in form.duration.errors %}
|
|
<p>{{ error }}</p>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="flex flex-col sm:flex-row gap-3 pt-4 border-t border-gray-200">
|
|
<button type="submit"
|
|
class="flex-1 sm:flex-none bg-temple-red hover:bg-red-800 text-white font-semibold px-8 py-3 rounded-xl transition shadow-md hover:shadow-lg flex items-center justify-center gap-2">
|
|
<i data-lucide="save" class="w-5 h-5"></i>
|
|
{% trans "Schedule Meeting" %}
|
|
</button>
|
|
<a href="{% url 'applications_interview_view' job.slug %}"
|
|
class="flex-1 sm:flex-none border border-gray-300 text-gray-700 hover:bg-gray-50 px-8 py-3 rounded-xl transition flex items-center justify-center gap-2">
|
|
<i data-lucide="x" class="w-5 h-5"></i>
|
|
{% trans "Cancel" %}
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block customJS %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Initialize Lucide icons
|
|
lucide.createIcons();
|
|
|
|
// Add form styling to inputs
|
|
const formInputs = document.querySelectorAll('input, select, textarea');
|
|
formInputs.forEach(input => {
|
|
input.classList.add('w-full', 'px-3', 'py-2.5', 'border', 'border-gray-300', 'rounded-lg', 'focus:ring-2', 'focus:ring-temple-red', 'focus:border-transparent', 'transition', 'text-gray-900');
|
|
});
|
|
|
|
// Form validation
|
|
const form = document.getElementById('meetingForm');
|
|
if (form) {
|
|
form.addEventListener('submit', function(e) {
|
|
const submitBtn = form.querySelector('button[type="submit"]');
|
|
const topic = document.getElementById('id_topic');
|
|
const startTime = document.getElementById('id_start_time');
|
|
const duration = document.getElementById('id_duration');
|
|
|
|
// Add loading state
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = `<i data-lucide="loader-2" class="w-5 h-5 mr-2 animate-spin"></i> {% trans "Scheduling..." %}`;
|
|
|
|
// Basic validation
|
|
if (startTime && !startTime.value) {
|
|
e.preventDefault();
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = `<i data-lucide="save" class="w-5 h-5 mr-2"></i> {% trans "Schedule Meeting" %}`;
|
|
alert('{% trans "Please select a start time." %}');
|
|
return;
|
|
}
|
|
|
|
if (duration && !duration.value) {
|
|
e.preventDefault();
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = `<i data-lucide="save" class="w-5 h-5 mr-2"></i> {% trans "Schedule Meeting" %}`;
|
|
alert('{% trans "Please specify the duration." %}');
|
|
return;
|
|
}
|
|
|
|
// Validate that start time is in the future
|
|
if (startTime && startTime.value) {
|
|
const selectedDate = new Date(startTime.value);
|
|
const now = new Date();
|
|
if (selectedDate <= now) {
|
|
e.preventDefault();
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = `<i data-lucide="save" class="w-5 h-5 mr-2"></i> {% trans "Schedule Meeting" %}`;
|
|
alert('{% trans "Please select a future date and time for the interview." %}');
|
|
return;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Warn before leaving if form has data
|
|
let formChanged = false;
|
|
const inputsToTrack = form ? form.querySelectorAll('input, select, textarea') : [];
|
|
|
|
inputsToTrack.forEach(input => {
|
|
input.addEventListener('change', function() {
|
|
formChanged = true;
|
|
});
|
|
});
|
|
|
|
window.addEventListener('beforeunload', function(e) {
|
|
if (formChanged) {
|
|
e.preventDefault();
|
|
e.returnValue = '{% trans "You have unsaved changes. Are you sure you want to leave?" %}';
|
|
return e.returnValue;
|
|
}
|
|
});
|
|
|
|
if (form) {
|
|
form.addEventListener('submit', function() {
|
|
formChanged = false;
|
|
});
|
|
}
|
|
|
|
// Set minimum date to today for datetime-local input
|
|
const startTimeInput = document.getElementById('id_start_time');
|
|
if (startTimeInput) {
|
|
const now = new Date();
|
|
const year = now.getFullYear();
|
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
|
const day = String(now.getDate()).padStart(2, '0');
|
|
const hours = String(now.getHours()).padStart(2, '0');
|
|
const minutes = String(now.getMinutes()).padStart(2, '0');
|
|
|
|
const minDateTime = `${year}-${month}-${day}T${hours}:${minutes}`;
|
|
startTimeInput.setAttribute('min', minDateTime);
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %} |