ATS/templates/meetings/meeting_details.html
2026-01-29 14:19:03 +03:00

407 lines
20 KiB
HTML

{% extends 'base.html' %}
{% load static i18n %}
{% load widget_tweaks %}
{% block title %}{% trans "Meeting Details" %} - {{ block.super }}{% endblock %}
{% block content %}
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<!-- Top Bar: Back & Actions -->
<div class="flex flex-col sm:flex-row justify-between items-start sm:items-center gap-4 mb-6">
<a href="{% url 'list_meetings' %}"
class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium text-gray-600 hover:bg-gray-50 transition-all duration-200">
<i data-lucide="arrow-left" class="w-4 h-4"></i>
{% trans "Back to Meetings" %}
</a>
<div class="flex flex-wrap gap-2">
<a href="{% url 'update_meeting' meeting.slug %}"
class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium text-white transition-all duration-200"
style="background-color: #9d2235;"
onmouseover="this.style.backgroundColor='#7a1a29'"
onmouseout="this.style.backgroundColor='#9d2235'">
<i data-lucide="edit-2" class="w-4 h-4"></i>
{% trans "Edit Meeting" %}
</a>
<form method="post" action="{% url 'send_application_invitation' meeting.slug %}" style="display: inline;">
{% csrf_token %}
<button type="submit"
onclick="return confirm('{% trans "Send invitation email to candidate?" %}')"
class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium border-2 border-blue-500 text-blue-600 hover:bg-blue-50 transition-all duration-200">
<i data-lucide="mail" class="w-4 h-4"></i>
{% trans "Send Invitation" %}
</button>
</form>
<form method="post" action="{% url 'delete_meeting' meeting.slug %}" style="display: inline;">
{% csrf_token %}
<button type="submit"
onclick="return confirm('{% trans "Are you sure you want to delete this meeting? This action is permanent." %}')"
class="inline-flex items-center gap-2 px-4 py-2.5 rounded-lg text-sm font-medium text-white bg-red-600 hover:bg-red-700 transition-all duration-200">
<i data-lucide="trash-2" class="w-4 h-4"></i>
{% trans "Delete" %}
</button>
</form>
</div>
</div>
<!-- Main Title -->
<div class="mb-6">
<h1 class="text-2xl sm:text-3xl font-bold text-gray-900 flex flex-wrap items-center gap-3">
<span class="flex items-center gap-3">
<i data-lucide="video" class="w-8 h-8" style="color: #9d2235;"></i>
{{ meeting.topic|default:"[Meeting Topic N/A]" }}
</span>
<span class="inline-block px-4 py-1.5 rounded-full text-xs font-semibold uppercase tracking-wide bg-green-100 text-green-800">
{{ meeting.status|title|default:'N/A' }}
</span>
</h1>
</div>
<!-- Main Cards Grid -->
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
<!-- Interview Detail Card -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<h2 class="text-lg font-bold mb-6 pb-3 border-b border-gray-200 flex items-center gap-2" style="color: #9d2235;">
<i data-lucide="briefcase" class="w-5 h-5"></i>
{% trans "Interview Detail" %}
</h2>
<div class="space-y-4">
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Job Title" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">{{ meeting.get_job.title|default:"N/A" }}</span>
</div>
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Candidate Name" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">
<a href="#" class="hover:underline" style="color: #9d2235;">{{ meeting.candidate_full_name|default:"N/A" }}</a>
</span>
</div>
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Candidate Email" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">
<a href="#" class="hover:underline" style="color: #9d2235;">{{ meeting.get_candidate.email|default:"N/A" }}</a>
</span>
</div>
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Job Type" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">{{ meeting.get_job.job_type|default:"N/A" }}</span>
</div>
{% if meeting.get_candidate.belong_to_agency %}
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Agency" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">
<a href="#" class="hover:underline" style="color: #9d2235;">{{ meeting.get_candidate.hiring_agency.name|default:"N/A" }}</a>
</span>
</div>
{% endif %}
</div>
</div>
<!-- Connection Details Card -->
<div class="bg-white rounded-xl shadow-sm border border-gray-200 p-6">
<h2 class="text-lg font-bold mb-6 pb-3 border-b border-gray-200 flex items-center gap-2" style="color: #9d2235;">
<i data-lucide="info" class="w-5 h-5"></i>
{% trans "Connection Details" %}
</h2>
<div class="space-y-4">
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Date & Time" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">{{ meeting.start_time|date:"M d, Y H:i"|default:"N/A" }}</span>
</div>
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Duration" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">{{ meeting.duration|default:"N/A" }} {% trans "minutes" %}</span>
</div>
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Meeting ID" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">{{ meeting.meeting_id|default:"N/A" }}</span>
</div>
<div class="flex py-3 border-b border-dashed border-gray-200">
<span class="w-2/5 text-sm font-semibold text-gray-700">{% trans "Host Email" %}:</span>
<span class="w-3/5 text-sm text-gray-900 font-medium">{{ meeting.host_email|default:"N/A" }}</span>
</div>
{% if meeting.join_url %}
<div class="pt-4">
<div class="relative">
<div id="copy-message" class="absolute -top-8 left-1/2 transform -translate-x-1/2 px-3 py-1.5 text-white text-sm font-semibold rounded-lg opacity-0 transition-opacity duration-300" style="background-color: #198754;">
{% trans "Copied!" %}
</div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4">
<div class="flex items-center justify-between gap-3">
<div class="flex-1 min-w-0">
<span class="text-sm font-semibold text-gray-700 block mb-1">{% trans "Join URL" %}:</span>
<span id="meeting-join-url" class="text-sm text-gray-900 break-all">{{ meeting.join_url }}</span>
</div>
<button onclick="copyLink()"
class="flex-shrink-0 px-4 py-2 rounded-lg text-sm font-medium text-white transition-all duration-200 hover:opacity-90"
style="background-color: #9d2235;"
title="{% trans 'Copy URL' %}">
<i data-lucide="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
</div>
</div>
{% endif %}
</div>
</div>
</div>
<!-- Manage Participants Button -->
<div class="mb-6">
<button type="button"
class="inline-flex items-center gap-2 px-6 py-3 rounded-lg text-sm font-medium text-white transition-all duration-200"
style="background-color: #9d2235;"
onmouseover="this.style.backgroundColor='#7a1a29'"
onmouseout="this.style.backgroundColor='#9d2235'"
data-bs-toggle="modal"
data-bs-target="#assignParticipants">
<i data-lucide="users" class="w-4 h-4"></i>
{% trans "Manage Participants" %} {% if total_participants %}({{ total_participants }}){% endif %}
</button>
</div>
</div>
<!-- Assign Participants Modal -->
<div class="modal fade" id="assignParticipants" tabindex="-1" aria-labelledby="assignParticipantsLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content rounded-xl">
<div class="modal-header px-6 py-4 border-b border-gray-200" style="background-color: #f8f9fa;">
<h5 class="modal-title text-lg font-bold flex items-center gap-2" style="color: #9d2235;">
<i data-lucide="users" class="w-5 h-5"></i>
{% trans "Manage all participants" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<form method="post" action="{% url 'create_interview_participants' meeting.interview.slug %}">
{% csrf_token %}
<div class="modal-body p-6">
<h4 class="text-xl font-bold text-gray-900 mb-4">{{ meeting.name }}</h4>
<hr class="border-gray-200 mb-4">
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<h5 class="text-lg font-bold mb-3 flex items-center gap-2" style="color: #9d2235;">
<span>👥</span> {% trans "Participants" %}
</h5>
<div>
{% if form.participants.errors %}
<div class="mb-2 text-sm text-red-600">{{ form.participants.errors.0 }}</div>
{% endif %}
{{ form.participants|add_class:"w-full px-4 py-2.5 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition" }}
</div>
</div>
<div>
<h5 class="text-lg font-bold mb-3 flex items-center gap-2" style="color: #9d2235;">
<span>👨‍💼</span> {% trans "Users" %}
</h5>
<div>
{% if form.system_users.errors %}
<div class="mb-2 text-sm text-red-600">{{ form.system_users.errors.0 }}</div>
{% endif %}
{{ form.system_users|add_class:"w-full px-4 py-2.5 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition" }}
</div>
</div>
</div>
</div>
<div class="modal-footer px-6 py-4 border-t border-gray-200 flex justify-end gap-3">
<button type="button" class="btn-close" data-bs-dismiss="modal">
{% trans "Close" %}
</button>
<button type="submit"
class="inline-flex items-center gap-2 px-6 py-2.5 rounded-lg text-sm font-medium text-white transition-all duration-200"
style="background-color: #9d2235;"
onmouseover="this.style.backgroundColor='#7a1a29'"
onmouseout="this.style.backgroundColor='#9d2235'">
<i data-lucide="save" class="w-4 h-4"></i>
{% trans "Save" %}
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Email Modal -->
<div class="modal fade" id="emailModal" tabindex="-1" aria-labelledby="emailModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl modal-dialog-centered">
<div class="modal-content rounded-xl">
<div class="modal-header px-6 py-4 border-b border-gray-200" style="background-color: #f8f9fa;">
<h5 class="modal-title text-lg font-bold flex items-center gap-2" style="color: #9d2235;">
<span>📧</span> {% trans "Compose Interview Invitation" %}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">
<i data-lucide="x" class="w-5 h-5"></i>
</button>
</div>
<form method="post" action="{% url 'send_interview_email' meeting.interview.slug %}">
{% csrf_token %}
<div class="modal-body p-6">
<div class="mb-6">
<label for="{{ email_form.subject.id_for_label }}" class="block text-sm font-semibold text-gray-700 mb-2">
{% trans "Subject" %}
</label>
{{ email_form.subject|add_class:"w-full px-4 py-2.5 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition" }}
</div>
<!-- Tabs -->
<ul class="flex border-b border-gray-200 mb-6" id="messageTabs" role="tablist">
<li class="role-presentation">
<button class="px-6 py-3 text-sm font-semibold border-b-2 transition-colors"
id="candidate-tab"
data-bs-toggle="tab"
data-bs-target="#candidate-pane"
type="button"
role="tab"
aria-controls="candidate-pane"
aria-selected="true"
style="border-color: #9d2235; color: #9d2235;">
{% if candidate.belong_to_an_agency %}
{% trans "Agency Message" %}
{% else %}
{% trans "Candidate Message" %}
{% endif %}
</button>
</li>
<li class="role-presentation">
<button class="px-6 py-3 text-sm font-semibold border-b-2 border-transparent text-gray-600 hover:text-gray-900 transition-colors"
id="participants-tab"
data-bs-toggle="tab"
data-bs-target="#participants-pane"
type="button"
role="tab"
aria-controls="participants-pane"
aria-selected="false">
{% trans "Panel Message (Interviewers)" %}
</button>
</li>
</ul>
<div class="tab-content">
<!-- Candidate/Agency Pane -->
<div class="tab-pane fade show active" id="candidate-pane" role="tabpanel" aria-labelledby="candidate-tab">
<p class="text-sm text-gray-600 mb-4">
{% if candidate.belong_to_an_agency %}
{% trans "This email will be sent to candidate's hiring agency." %}
{% else %}
{% trans "This email will be sent to the candidate." %}
{% endif %}
</p>
{% if not candidate.belong_to_an_agency %}
<div class="mb-4">
{{ email_form.message_for_candidate|add_class:"w-full px-4 py-3 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition resize-vertical" }}
</div>
{% endif %}
{% if candidate.belong_to_an_agency %}
<div class="mb-4">
{{ email_form.message_for_agency|add_class:"w-full px-4 py-3 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition resize-vertical" }}
</div>
{% endif %}
</div>
<!-- Participants Pane -->
<div class="tab-pane fade" id="participants-pane" role="tabpanel" aria-labelledby="participants-tab">
<p class="text-sm text-gray-600 mb-4">
{% trans "This email will be sent to internal and external interview participants." %}
</p>
<div class="mb-4">
{{ email_form.message_for_participants|add_class:"w-full px-4 py-3 border border-gray-200 rounded-lg text-sm focus:ring-2 focus:ring-temple-red/20 focus:border-temple-red outline-none transition resize-vertical" }}
</div>
</div>
</div>
</div>
<div class="modal-footer px-6 py-4 border-t border-gray-200 flex justify-end gap-3">
<button type="button" class="btn-close" data-bs-dismiss="modal">
{% trans "Close" %}
</button>
<button type="submit"
class="inline-flex items-center gap-2 px-6 py-2.5 rounded-lg text-sm font-medium text-white transition-all duration-200"
style="background-color: #9d2235;"
onmouseover="this.style.backgroundColor='#7a1a29'"
onmouseout="this.style.backgroundColor='#9d2235'">
<i data-lucide="send" class="w-4 h-4"></i>
{% trans "Send Invitation" %}
</button>
</div>
</form>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
if (typeof lucide !== 'undefined') {
lucide.createIcons();
}
});
// Copy Link Function
function copyLink() {
const urlElement = document.getElementById('meeting-join-url');
const messageElement = document.getElementById('copy-message');
const textToCopy = urlElement.textContent || urlElement.innerText;
clearTimeout(window.copyMessageTimeout);
function showMessage(success) {
messageElement.textContent = success ? '{% trans "Copied!" %}' : '{% trans "Copy Failed." %}';
messageElement.style.backgroundColor = success ? '#198754' : '#dc3545';
messageElement.style.opacity = '1';
window.copyMessageTimeout = setTimeout(() => {
messageElement.style.opacity = '0';
}, 2000);
}
if (navigator.clipboard && window.isSecureContext) {
navigator.clipboard.writeText(textToCopy).then(() => {
showMessage(true);
}).catch(err => {
console.error('Could not copy text: ', err);
fallbackCopyTextToClipboard(textToCopy, showMessage);
});
} else {
fallbackCopyTextToClipboard(textToCopy, showMessage);
}
}
function fallbackCopyTextToClipboard(text, callback) {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.top = "0";
textArea.style.left = "0";
textArea.style.position = "fixed";
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
let success = false;
try {
success = document.execCommand('copy');
} catch (err) {
console.error('Fallback: Oops, unable to copy', err);
}
document.body.removeChild(textArea);
callback(success);
}
</script>
{% endblock %}