ATS/templates/interviews/interview_detail.html
2026-02-01 13:38:06 +03:00

836 lines
55 KiB
HTML

{% extends 'base.html' %}
{% load static i18n %}
{% block title %}{{ schedule.application.name }} - {% trans "Interview Details" %} - ATS{% endblock %}
{% block content %}
<div class="space-y-4 sm:space-y-6">
<!-- Header -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 sm:gap-4">
<div class="min-w-0 flex-1">
<h1 class="text-xl sm:text-2xl lg:text-3xl font-bold text-gray-900 flex items-center gap-2 sm:gap-3">
<div class="bg-temple-red/10 p-2 sm:p-3 rounded-xl shrink-0">
<i data-lucide="calendar" class="w-5 h-5 sm:w-6 sm:h-6 text-temple-red"></i>
</div>
<span class="truncate">{% trans "Interview Details" %}</span>
</h1>
<p class="text-sm sm:text-base text-gray-600 mt-1 truncate">{{ schedule.application.name }} - {{ schedule.job.title }}</p>
</div>
<div class="flex flex-wrap gap-2 w-full sm:w-auto">
<a href="{% url 'interview_list' %}"
class="inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-2 sm:py-2.5 rounded-lg text-sm font-medium border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target flex-1 sm:flex-none">
<i data-lucide="arrow-left" class="w-4 h-4"></i>
<span class="hidden sm:inline">{% trans "Back to Interviews" %}</span>
<span class="sm:hidden">{% trans "Back" %}</span>
</a>
<a href="{% url 'job_detail' schedule.job.slug %}"
class="inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-2 sm:py-2.5 rounded-lg text-sm font-medium border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target flex-1 sm:flex-none">
<i data-lucide="briefcase" class="w-4 h-4"></i>
<span class="hidden sm:inline">{% trans "View Job" %}</span>
<span class="sm:hidden">{% trans "Job" %}</span>
</a>
{% if schedule.status != 'cancelled' %}
<button type="button"
class="inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-2 sm:py-2.5 rounded-lg text-sm font-medium border-2 border-temple-red text-temple-red hover:bg-temple-red hover:text-white active:bg-temple-red/90 transition-all duration-200 touch-target flex-1 sm:flex-none"
onclick="openModal('statusModal')">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
<span class="hidden sm:inline">{% trans "Update Status" %}</span>
<span class="sm:hidden">{% trans "Status" %}</span>
</button>
{% endif %}
</div>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-4 sm:gap-5 lg:gap-6">
<div class="lg:col-span-2 space-y-4 sm:space-y-5 lg:space-y-6">
<!-- Candidate Information -->
<div class="bg-white rounded-xl sm:rounded-2xl shadow-sm border border-gray-100 p-4 sm:p-5 lg:p-6">
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 sm:gap-4 mb-4 sm:mb-5">
<h2 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2">
<i data-lucide="user" class="w-4 h-4 sm:w-5 sm:h-5 text-temple-red"></i>
{% trans "Candidate Information" %}
</h2>
{% if schedule.application.resume %}
<a href="{{ schedule.application.resume.url }}"
class="inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-2 rounded-lg text-sm font-medium border-2 border-temple-red text-temple-red hover:bg-temple-red hover:text-white active:bg-temple-red/90 transition-all duration-200 touch-target w-full sm:w-auto"
target="_blank">
<i data-lucide="download" class="w-4 h-4"></i>
{% trans "Download Resume" %}
</a>
{% endif %}
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 sm:gap-4">
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4 border-l-4 border-temple-red">
<h3 class="font-semibold text-gray-900 mb-2 sm:mb-3 text-sm sm:text-base">{% trans "Personal Details" %}</h3>
<div class="space-y-1.5 sm:space-y-2">
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Name:" %}</strong> {{ schedule.application.name }}</p>
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Email:" %}</strong> {{ schedule.application.email }}</p>
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Phone:" %}</strong> {{ schedule.application.phone }}</p>
{% if schedule.application.location %}
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Location:" %}</strong> {{ schedule.application.location }}</p>
{% endif %}
</div>
</div>
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4 border-l-4 border-temple-red">
<h3 class="font-semibold text-gray-900 mb-2 sm:mb-3 text-sm sm:text-base">{% trans "Application Details" %}</h3>
<div class="space-y-1.5 sm:space-y-2">
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Job:" %}</strong> {{ schedule.job.title }}</p>
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Department:" %}</strong> {{ schedule.job.department }}</p>
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Applied Date:" %}</strong> {{ schedule.application.created_at|date:"d-m-Y" }}</p>
<p class="text-gray-700 text-xs sm:text-sm"><strong>{% trans "Current Stage:" %}</strong>
<span class="inline-block px-2 sm:px-3 py-0.5 sm:py-1 rounded-full text-xs font-semibold bg-temple-red text-white ml-1">
{{ schedule.application.stage }}
</span>
</p>
</div>
</div>
</div>
</div>
<!-- Interview Details -->
<div class="bg-white rounded-xl sm:rounded-2xl shadow-sm border border-gray-100 p-4 sm:p-5 lg:p-6">
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-3 sm:gap-4 mb-4 sm:mb-5">
<h2 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2">
<i data-lucide="calendar-check" class="w-4 h-4 sm:w-5 sm:h-5 text-temple-red"></i>
{% trans "Interview Details" %}
</h2>
<div class="flex flex-wrap gap-2">
<span class="inline-block px-2 sm:px-3 py-1 rounded-full text-xs font-semibold bg-temple-red text-white">
{{ interview.location_type }}
</span>
<span class="inline-block px-2 sm:px-3 py-1 rounded-full text-xs font-semibold
{% if schedule.status == 'scheduled' %}bg-gray-600
{% elif schedule.status == 'confirmed' %}bg-blue-600
{% elif schedule.status == 'cancelled' %}bg-red-600
{% elif schedule.status == 'completed' %}bg-green-600
{% endif %} text-white">
{{ schedule.status }}
</span>
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-3 sm:gap-4">
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4">
<div class="space-y-2 sm:space-y-2.5">
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Date:" %}</span>
<span class="text-gray-600">{{ schedule.interview_date|date:"d-m-Y" }}</span>
</div>
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Time:" %}</span>
<span class="text-gray-600">{{ schedule.interview_time|date:"h:i A" }}</span>
</div>
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Duration:" %}</span>
<span class="text-gray-600">{{ interview.duration }} {% trans "minutes" %}</span>
</div>
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Status:" %}</span>
<span class="inline-block px-2 py-0.5 rounded text-xs font-semibold bg-temple-red text-white">
{{ interview.status }}
</span>
</div>
</div>
</div>
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4">
{% if interview.location_type == 'Remote' %}
<h3 class="font-semibold text-gray-900 mb-2 sm:mb-3 text-sm sm:text-base">{% trans "Remote Meeting Details" %}</h3>
<div class="space-y-2 sm:space-y-2.5 mb-3">
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Platform:" %}</span>
<span class="text-gray-600">Zoom</span>
</div>
{% if schedule.interview %}
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Meeting ID:" %}</span>
<span class="text-gray-600">{{ interview.meeting_id }}</span>
</div>
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Password:" %}</span>
<span class="text-gray-600">{{ interview.password }}</span>
</div>
{% endif %}
</div>
{% if interview.join_url %}
<div class="space-y-2">
<a href="{{ interview.join_url }}"
target="_blank"
class="w-full inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-2.5 sm:py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-temple-red hover:bg-temple-red/90 active:bg-temple-red/80 touch-target"
id="joinMeetingLink">
<i data-lucide="video" class="w-4 h-4"></i>
{% trans "Join Meeting" %}
</a>
<button onclick="copyJoinUrl()"
class="w-full inline-flex items-center justify-center gap-2 px-3 sm:px-4 py-2.5 sm:py-3 rounded-lg font-medium text-sm border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target">
<i data-lucide="copy" class="w-4 h-4"></i>
{% trans "Copy Join URL" %}
</button>
<p id="copyMessage" class="text-green-600 text-xs sm:text-sm text-center"></p>
</div>
{% endif %}
{% else %}
<h3 class="font-semibold text-gray-900 mb-2 sm:mb-3 text-sm sm:text-base">{% trans "Onsite Location Details" %}</h3>
{% if schedule.interview %}
<div class="space-y-2 sm:space-y-2.5">
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Address:" %}</span>
<span class="text-gray-600 text-right">{{ interview.physical_address }}</span>
</div>
<div class="flex justify-between items-center text-xs sm:text-sm">
<span class="font-semibold text-gray-700">{% trans "Room:" %}</span>
<span class="text-gray-600">{{ interview.room_number }}</span>
</div>
</div>
{% endif %}
{% endif %}
</div>
</div>
</div>
<!-- Interview Timeline -->
<div class="bg-white rounded-xl sm:rounded-2xl shadow-sm border border-gray-100 p-4 sm:p-5 lg:p-6">
<h2 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2 mb-4 sm:mb-5">
<i data-lucide="history" class="w-4 h-4 sm:w-5 sm:h-5 text-temple-red"></i>
{% trans "Interview Timeline" %}
</h2>
<div class="relative pl-6 sm:pl-8">
<div class="absolute left-2.5 sm:left-3 top-0 bottom-0 w-0.5 bg-gray-200"></div>
<div class="space-y-4 sm:space-y-5 lg:space-y-6">
<div class="relative">
<div class="absolute left-[-1.125rem] sm:left-[-1.25rem] top-2 w-3 h-3 rounded-full bg-temple-red border-2 border-white shadow"></div>
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4 border border-gray-200">
<h3 class="font-semibold text-gray-900 mb-1 text-sm sm:text-base">{% trans "Interview Scheduled" %}</h3>
<p class="text-gray-600 text-xs sm:text-sm">{% trans "Interview was scheduled for" %} {{ schedule.interview_date|date:"d-m-Y" }} {{ schedule.interview_time|date:"h:i A" }}</p>
<small class="text-gray-500 text-xs mt-2 block">{{ interview.created_at|date:"d-m-Y h:i A" }}</small>
</div>
</div>
{% if schedule.status == 'confirmed' %}
<div class="relative">
<div class="absolute left-[-1.125rem] sm:left-[-1.25rem] top-2 w-3 h-3 rounded-full bg-blue-600 border-2 border-white shadow"></div>
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4 border border-gray-200">
<h3 class="font-semibold text-gray-900 mb-1 text-sm sm:text-base">{% trans "Interview Confirmed" %}</h3>
<p class="text-gray-600 text-xs sm:text-sm">{% trans "Candidate has confirmed attendance" %}</p>
</div>
</div>
{% endif %}
{% if schedule.status == 'completed' %}
<div class="relative">
<div class="absolute left-[-1.125rem] sm:left-[-1.25rem] top-2 w-3 h-3 rounded-full bg-green-600 border-2 border-white shadow"></div>
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4 border border-gray-200">
<h3 class="font-semibold text-gray-900 mb-1 text-sm sm:text-base">{% trans "Interview Completed" %}</h3>
<p class="text-gray-600 text-xs sm:text-sm">{% trans "Interview has been completed" %}</p>
</div>
</div>
{% endif %}
{% if schedule.status == 'cancelled' %}
<div class="relative">
<div class="absolute left-[-1.125rem] sm:left-[-1.25rem] top-2 w-3 h-3 rounded-full bg-red-600 border-2 border-white shadow"></div>
<div class="bg-gray-50 rounded-lg sm:rounded-xl p-3 sm:p-4 border border-gray-200">
<h3 class="font-semibold text-gray-900 mb-1 text-sm sm:text-base">{% trans "Interview Cancelled" %}</h3>
<p class="text-gray-600 text-xs sm:text-sm">{% trans "Interview was cancelled on: " %}{{ schedule.cancelled_at|date:"d-m-Y h:i A" }}</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="space-y-4 sm:space-y-5 lg:space-y-6">
<!-- Actions Panel -->
<div class="bg-white rounded-xl sm:rounded-2xl shadow-sm border border-gray-100 p-4 sm:p-5 lg:p-6">
<h2 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2 mb-4">
<i data-lucide="settings" class="w-4 h-4 sm:w-5 sm:h-5 text-temple-red"></i>
{% trans "Actions" %}
</h2>
<div class="space-y-2 sm:space-y-3">
{% if schedule.status != 'cancelled' and schedule.status != 'completed' %}
<button type="button"
class="w-full inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-temple-red hover:bg-temple-red/90 active:bg-temple-red/80 touch-target"
onclick="openModal('rescheduleModal')">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
{% trans "Reschedule" %}
</button>
<button type="button"
class="w-full inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-red-600 text-red-600 hover:bg-red-600 hover:text-white active:bg-red-700 transition-all duration-200 touch-target"
onclick="openModal('cancelModal')">
<i data-lucide="x" class="w-4 h-4"></i>
{% trans "Cancel" %}
</button>
{% endif %}
{% if schedule.status == 'cancelled' %}
<p class="text-red-600 text-sm text-center py-2">{% trans "This interview has been cancelled" %}</p>
{% endif %}
<div class="border-t border-gray-200 my-3 sm:my-4"></div>
<button type="button"
class="w-full inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-temple-red text-temple-red hover:bg-temple-red hover:text-white active:bg-temple-red/90 transition-all duration-200 touch-target"
onclick="openModal('emailModal')">
<i data-lucide="mail" class="w-4 h-4"></i>
{% trans "Send Email" %}
</button>
{% if schedule.status == 'completed' %}
<button type="button"
class="w-full inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-temple-red text-temple-red hover:bg-temple-red hover:text-white active:bg-temple-red/90 transition-all duration-200 touch-target"
onclick="openModal('resultModal')">
<i data-lucide="check-circle" class="w-4 h-4"></i>
{% trans "Update Result" %}
</button>
{% if interview.interview_result %}
<div class="mt-4 text-center">
<p class="text-sm text-gray-700 mb-2">{% trans 'Interview Result:' %}</p>
{% if interview.interview_result == 'passed' %}
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-green-100 text-green-800">
<i data-lucide="check-circle" class="w-4 h-4"></i>
<strong class="text-sm">{{ interview.interview_result|upper }}</strong>
</div>
{% elif interview.interview_result == 'failed' %}
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-red-100 text-red-800">
<i data-lucide="x-circle" class="w-4 h-4"></i>
<strong class="text-sm">{{ interview.interview_result|upper }}</strong>
</div>
{% else %}
<div class="inline-flex items-center gap-2 px-4 py-2 rounded-lg bg-temple-red/10 text-temple-red">
<i data-lucide="help-circle" class="w-4 h-4"></i>
<strong class="text-sm">{{ interview.interview_result|upper }}</strong>
</div>
{% endif %}
{% if interview.result_comments %}
<p class="text-sm text-gray-600 mt-3">{{ interview.result_comments }}</p>
{% endif %}
</div>
{% else %}
<span class="inline-block w-full text-center px-3 py-1 rounded-full text-xs font-semibold bg-gray-200 text-gray-700">
{% trans "No Result Yet" %}
</span>
{% endif %}
{% endif %}
</div>
</div>
</div>
</div>
</div>
<!-- Email Modal -->
<div class="fixed inset-0 z-50 hidden overflow-y-auto" id="emailModal" role="dialog" aria-labelledby="emailModalLabel" aria-modal="true">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity bg-black/50 backdrop-blur-sm" id="emailModalBackdrop" onclick="closeModal('emailModal')"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block w-full max-w-2xl my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-2xl rounded-2xl" id="emailModalContent">
<div class="flex items-center justify-between border-b border-gray-100 p-4 sm:p-5">
<h3 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2" id="emailModalLabel">
<i data-lucide="mail" class="w-5 h-5 text-temple-red"></i>
{% trans "Compose Email" %}
</h3>
<button type="button" class="text-gray-400 hover:text-gray-600 transition-colors touch-target" onclick="closeModal('emailModal')">
<i data-lucide="x" class="w-5 h-5 sm:w-6 sm:h-6"></i>
</button>
</div>
<div class="p-4 sm:p-5 lg:p-6 max-h-[70vh] overflow-y-auto">
<form method="post" action="{% url 'send_interview_email' schedule.slug %}" class="space-y-4 sm:space-y-5">
{% csrf_token %}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2">
{% trans "Recipient" %}
</label>
<input type="text" value="{{ schedule.application.email }}" readonly
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 bg-gray-50 text-gray-600 font-medium focus:outline-none cursor-not-allowed text-sm sm:text-base">
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_email_form.subject.id_for_label }}">
{% trans "Subject" %}
</label>
<input type="text" name="subject" id="{{ interview_email_form.subject.id_for_label }}"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 placeholder:text-gray-400"
placeholder="{% trans 'Enter email subject...' %}"
value="{% if interview_email_form.subject.value %}{{ interview_email_form.subject.value }}{% endif %}">
{% if interview_email_form.subject.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_email_form.subject.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_email_form.message.id_for_label }}">
{% trans "Message" %}
</label>
<textarea name="message" id="{{ interview_email_form.message.id_for_label }}" rows="5"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 resize-y min-h-[150px] placeholder:text-gray-400"
placeholder="{% trans 'Enter your message...' %}"></textarea>
{% if interview_email_form.message.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_email_form.message.errors }}
</div>
{% endif %}
</div>
<div class="flex gap-3 pt-2">
<button type="button"
onclick="closeModal('emailModal')"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target">
{% trans "Cancel" %}
</button>
<button type="submit"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-temple-red hover:bg-temple-red/90 active:bg-temple-red/80 touch-target">
<i data-lucide="send" class="w-4 h-4"></i>
{% trans "Send Email" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Reschedule Modal -->
<div class="fixed inset-0 z-50 hidden overflow-y-auto" id="rescheduleModal" role="dialog" aria-labelledby="rescheduleModalLabel" aria-modal="true">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity bg-black/50 backdrop-blur-sm" id="rescheduleModalBackdrop" onclick="closeModal('rescheduleModal')"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block w-full max-w-lg my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-2xl rounded-2xl" id="rescheduleModalContent">
<div class="flex items-center justify-between border-b border-gray-100 p-4 sm:p-5">
<h3 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2" id="rescheduleModalLabel">
<i data-lucide="refresh-cw" class="w-5 h-5 text-temple-red"></i>
{% trans "Reschedule Interview" %}
</h3>
<button type="button" class="text-gray-400 hover:text-gray-600 transition-colors touch-target" onclick="closeModal('rescheduleModal')">
<i data-lucide="x" class="w-5 h-5 sm:w-6 sm:h-6"></i>
</button>
</div>
<div class="p-4 sm:p-5 lg:p-6 max-h-[70vh] overflow-y-auto">
<form method="post" action="{% url 'reschedule_meeting_for_application' schedule.slug %}" class="space-y-4 sm:space-y-5">
{% csrf_token %}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ reschedule_form.new_date.id_for_label }}">
{% trans "New Date" %}
</label>
<input type="date" name="new_date" id="{{ reschedule_form.new_date.id_for_label }}"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200">
{% if reschedule_form.new_date.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ reschedule_form.new_date.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ reschedule_form.new_time.id_for_label }}">
{% trans "New Time" %}
</label>
<input type="time" name="new_time" id="{{ reschedule_form.new_time.id_for_label }}"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200">
{% if reschedule_form.new_time.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ reschedule_form.new_time.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ reschedule_form.reason.id_for_label }}">
{% trans "Reason for Rescheduling" %}
</label>
<textarea name="reason" id="{{ reschedule_form.reason.id_for_label }}" rows="3"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 resize-y min-h-[100px] placeholder:text-gray-400"
placeholder="{% trans 'Enter the reason for rescheduling...' %}"></textarea>
{% if reschedule_form.reason.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ reschedule_form.reason.errors }}
</div>
{% endif %}
</div>
<div class="flex gap-3 pt-2">
<button type="button"
onclick="closeModal('rescheduleModal')"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target">
{% trans "Cancel" %}
</button>
<button type="submit"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-temple-red hover:bg-temple-red/90 active:bg-temple-red/80 touch-target">
<i data-lucide="refresh-cw" class="w-4 h-4"></i>
{% trans "Reschedule" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Cancel Modal -->
<div class="fixed inset-0 z-50 hidden overflow-y-auto" id="cancelModal" role="dialog" aria-labelledby="cancelModalLabel" aria-modal="true">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity bg-black/50 backdrop-blur-sm" id="cancelModalBackdrop" onclick="closeModal('cancelModal')"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block w-full max-w-lg my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-2xl rounded-2xl" id="cancelModalContent">
<div class="flex items-center justify-between border-b border-gray-100 p-4 sm:p-5">
<h3 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2" id="cancelModalLabel">
<i data-lucide="alert-triangle" class="w-5 h-5 text-red-600"></i>
{% trans "Cancel Interview" %}
</h3>
<button type="button" class="text-gray-400 hover:text-gray-600 transition-colors touch-target" onclick="closeModal('cancelModal')">
<i data-lucide="x" class="w-5 h-5 sm:w-6 sm:h-6"></i>
</button>
</div>
<div class="p-4 sm:p-5 lg:p-6 max-h-[70vh] overflow-y-auto">
<form method="post" action="{% url 'cancel_interview_for_application' schedule.slug %}" class="space-y-4 sm:space-y-5">
{% csrf_token %}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ cancel_form.cancellation_reason.id_for_label }}">
{% trans "Reason for Cancellation" %}
</label>
<textarea name="cancellation_reason" id="{{ cancel_form.cancellation_reason.id_for_label }}" rows="3"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 resize-y min-h-[100px] placeholder:text-gray-400"
placeholder="{% trans 'Enter the reason for cancellation...' %}"></textarea>
{% if cancel_form.cancellation_reason.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ cancel_form.cancellation_reason.errors }}
</div>
{% endif %}
</div>
<div class="bg-yellow-50 border-l-4 border-yellow-400 rounded-lg p-4">
<div class="flex items-start gap-3">
<i data-lucide="alert-triangle" class="w-5 h-5 text-yellow-600 flex-shrink-0 mt-0.5"></i>
<p class="text-yellow-800 text-sm">{% trans "Are you sure you want to cancel this interview? This action cannot be undone." %}</p>
</div>
</div>
<div class="flex gap-3 pt-2">
<button type="button"
onclick="closeModal('cancelModal')"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target">
{% trans "Close" %}
</button>
<button type="submit"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-red-600 hover:bg-red-700 active:bg-red-800 touch-target">
<i data-lucide="x" class="w-4 h-4"></i>
{% trans "Cancel Interview" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Result Modal -->
<div class="fixed inset-0 z-50 hidden overflow-y-auto" id="resultModal" role="dialog" aria-labelledby="resultModalLabel" aria-modal="true">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity bg-black/50 backdrop-blur-sm" id="resultModalBackdrop" onclick="closeModal('resultModal')"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block w-full max-w-lg my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-2xl rounded-2xl" id="resultModalContent">
<div class="flex items-center justify-between border-b border-gray-100 p-4 sm:p-5">
<h3 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2" id="resultModalLabel">
<i data-lucide="check-circle" class="w-5 h-5 text-temple-red"></i>
{% trans "Update Interview Result" %}
</h3>
<button type="button" class="text-gray-400 hover:text-gray-600 transition-colors touch-target" onclick="closeModal('resultModal')">
<i data-lucide="x" class="w-5 h-5 sm:w-6 sm:h-6"></i>
</button>
</div>
<div class="p-4 sm:p-5 lg:p-6 max-h-[70vh] overflow-y-auto">
<form method="post" action="{% url 'update_interview_result' interview.slug %}" class="space-y-4 sm:space-y-5">
{% csrf_token %}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_result_form.interview_result.id_for_label }}">
{% trans "Interview Result" %}
</label>
<select name="interview_result" id="{{ interview_result_form.interview_result.id_for_label }}"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base bg-white focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 cursor-pointer">
<option value="">-- {% trans "Select Result" %} --</option>
<option value="passed">{% trans "Passed" %}</option>
<option value="failed">{% trans "Failed" %}</option>
<option value="pending">{% trans "Pending" %}</option>
</select>
{% if interview_result_form.interview_result.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_result_form.interview_result.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_result_form.result_comments.id_for_label }}">
{% trans "Comments" %}
</label>
<textarea name="result_comments" id="{{ interview_result_form.result_comments.id_for_label }}" rows="3"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 resize-y min-h-[100px] placeholder:text-gray-400"
placeholder="{% trans 'Enter any comments...' %}"></textarea>
{% if interview_result_form.result_comments.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_result_form.result_comments.errors }}
</div>
{% endif %}
</div>
<div class="flex gap-3 pt-2">
<button type="button"
onclick="closeModal('resultModal')"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target">
{% trans "Cancel" %}
</button>
<button type="submit"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-temple-red hover:bg-temple-red/90 active:bg-temple-red/80 touch-target">
<i data-lucide="check" class="w-4 h-4"></i>
{% trans "Update Result" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Status Modal -->
<div class="fixed inset-0 z-50 hidden overflow-y-auto" id="statusModal" role="dialog" aria-labelledby="statusModalLabel" aria-modal="true">
<div class="flex items-center justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0">
<div class="fixed inset-0 transition-opacity bg-black/50 backdrop-blur-sm" id="statusModalBackdrop" onclick="closeModal('statusModal')"></div>
<span class="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">&#8203;</span>
<div class="inline-block w-full max-w-lg my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-2xl rounded-2xl" id="statusModalContent">
<div class="flex items-center justify-between border-b border-gray-100 p-4 sm:p-5">
<h3 class="text-base sm:text-lg font-bold text-gray-900 flex items-center gap-2" id="statusModalLabel">
<i data-lucide="refresh-cw" class="w-5 h-5 text-temple-red"></i>
{% trans "Update Interview Status" %}
</h3>
<button type="button" class="text-gray-400 hover:text-gray-600 transition-colors touch-target" onclick="closeModal('statusModal')">
<i data-lucide="x" class="w-5 h-5 sm:w-6 sm:h-6"></i>
</button>
</div>
<div class="p-4 sm:p-5 lg:p-6 max-h-[70vh] overflow-y-auto">
<form method="post" action="{% url 'update_interview_status' schedule.slug %}" class="space-y-4 sm:space-y-5">
{% csrf_token %}
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_result_form.interview_result.id_for_label }}">
{% trans "Interview Result" %}
</label>
<select name="interview_result" id="{{ interview_result_form.interview_result.id_for_label }}"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base bg-white focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 cursor-pointer">
<option value="">-- {% trans "Select Result" %} --</option>
<option value="passed">{% trans "Passed" %}</option>
<option value="failed">{% trans "Failed" %}</option>
<option value="pending">{% trans "Pending" %}</option>
</select>
{% if interview_result_form.interview_result.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_result_form.interview_result.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_result_form.result_comments.id_for_label }}">
{% trans "Comments" %}
</label>
<textarea name="result_comments" id="{{ interview_result_form.result_comments.id_for_label }}" rows="3"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 resize-y min-h-[100px] placeholder:text-gray-400"
placeholder="{% trans 'Enter any comments...' %}"></textarea>
{% if interview_result_form.result_comments.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_result_form.result_comments.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_status_form.status.id_for_label }}">
{% trans "Interview Status" %}
</label>
<select name="status" id="{{ interview_status_form.status.id_for_label }}"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base bg-white focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 cursor-pointer">
<option value="">-- {% trans "Select Status" %} --</option>
<option value="scheduled">{% trans "Scheduled" %}</option>
<option value="confirmed">{% trans "Confirmed" %}</option>
<option value="completed">{% trans "Completed" %}</option>
<option value="cancelled">{% trans "Cancelled" %}</option>
</select>
{% if interview_status_form.status.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_status_form.status.errors }}
</div>
{% endif %}
</div>
<div>
<label class="block text-sm font-semibold text-gray-700 mb-2" for="{{ interview_status_form.status_notes.id_for_label }}">
{% trans "Notes" %}
</label>
<textarea name="status_notes" id="{{ interview_status_form.status_notes.id_for_label }}" rows="3"
class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 text-gray-700 text-sm sm:text-base focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition-all duration-200 resize-y min-h-[100px] placeholder:text-gray-400"
placeholder="{% trans 'Enter any notes...' %}"></textarea>
{% if interview_status_form.status_notes.errors %}
<div class="mt-1 text-red-600 text-xs">
{{ interview_status_form.status_notes.errors }}
</div>
{% endif %}
</div>
<div class="flex gap-3 pt-2">
<button type="button"
onclick="closeModal('statusModal')"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm border-2 border-gray-300 text-gray-700 hover:bg-gray-50 active:bg-gray-100 transition-all duration-200 touch-target">
{% trans "Close" %}
</button>
<button type="submit"
class="flex-1 inline-flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium text-sm text-white transition-all duration-200 bg-temple-red hover:bg-temple-red/90 active:bg-temple-red/80 touch-target">
<i data-lucide="check" class="w-4 h-4"></i>
{% trans "Update Status" %}
</button>
</div>
</form>
</div>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}
<script>
document.addEventListener('DOMContentLoaded', function() {
// Initialize Lucide icons
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
// Style form fields
setTimeout(styleFormFields, 100);
});
// Style form fields function
function styleFormFields() {
// Style text inputs (including those wrapped by crispy forms)
const inputs = document.querySelectorAll('input[type="text"], input[type="email"], input[type="number"], input[type="date"], input[type="time"], input[type="url"], input[type="tel"]');
inputs.forEach(input => {
if (!input.classList.contains('styled')) {
// Remove any existing conflicting classes
input.className = input.className.replace(/form-control/g, 'styled');
input.className = input.className.replace(/textinput/g, '');
// Add base input styling
input.classList.add('w-full', 'px-4', 'py-3', 'rounded-xl', 'border-2', 'border-gray-200', 'text-gray-700', 'text-sm', 'sm:text-base', 'focus:ring-2', 'focus:ring-temple-red/20', 'focus:border-temple-red', 'outline-none', 'transition-all', 'duration-200', 'placeholder:text-gray-400', 'styled');
}
});
// Style select dropdowns
const selects = document.querySelectorAll('select');
selects.forEach(select => {
if (!select.classList.contains('styled')) {
// Remove any existing conflicting classes
select.className = select.className.replace(/form-control/g, 'styled');
select.className = select.className.replace(/select/g, '');
// Add base select styling
select.classList.add('w-full', 'px-4', 'py-3', 'rounded-xl', 'border-2', 'border-gray-200', 'text-gray-700', 'text-sm', 'sm:text-base', 'bg-white', 'focus:ring-2', 'focus:ring-temple-red/20', 'focus:border-temple-red', 'outline-none', 'transition-all', 'duration-200', 'cursor-pointer', 'styled');
}
});
// Style textareas
const textareas = document.querySelectorAll('textarea');
textareas.forEach(textarea => {
if (!textarea.classList.contains('styled')) {
// Remove any existing conflicting classes
textarea.className = textarea.className.replace(/form-control/g, 'styled');
textarea.className = textarea.className.replace(/textarea/g, '');
// Add base textarea styling
textarea.classList.add('w-full', 'px-4', 'py-3', 'rounded-xl', 'border-2', 'border-gray-200', 'text-gray-700', 'text-sm', 'sm:text-base', 'focus:ring-2', 'focus:ring-temple-red/20', 'focus:border-temple-red', 'outline-none', 'transition-all', 'duration-200', 'resize-y', 'min-h-[100px]', 'placeholder:text-gray-400', 'styled');
}
});
// Reinitialize icons after form field styling
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
}
// Open modal function
function openModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.classList.remove('hidden');
document.body.style.overflow = 'hidden';
// Style form fields after modal opens with multiple retries
setTimeout(function() {
styleFormFields();
}, 100);
setTimeout(function() {
styleFormFields();
}, 300);
setTimeout(function() {
styleFormFields();
}, 500);
}
}
// Close modal function
function closeModal(modalId) {
const modal = document.getElementById(modalId);
if (modal) {
modal.classList.add('hidden');
document.body.style.overflow = '';
}
}
// Close modal on ESC key
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
const openModals = document.querySelectorAll('.fixed.inset-0.z-50:not(.hidden)');
openModals.forEach(modal => {
closeModal(modal.id);
});
}
});
// Copy Join URL function
async function copyJoinUrl() {
const joinUrlElement = document.getElementById('joinMeetingLink');
const urlToCopy = joinUrlElement.href;
const messageElement = document.getElementById('copyMessage');
try {
await navigator.clipboard.writeText(urlToCopy);
messageElement.textContent = '✓ {% trans "Join URL copied successfully!" %}';
messageElement.classList.add('text-green-600');
messageElement.classList.remove('text-red-600');
setTimeout(function() {
messageElement.textContent = '';
}, 3000);
} catch (e) {
messageElement.textContent = '✗ {% trans "Failed to copy Join URL." %}';
messageElement.classList.add('text-red-600');
messageElement.classList.remove('text-green-600');
console.error('Could not copy URL', e);
}
}
</script>
{% endblock %}