kaauh_ats/templates/interviews/detail_interview.html

499 lines
24 KiB
HTML

{% extends 'base.html' %}
{% load static i18n %}
{% load widget_tweaks %}
{% block customCSS %}
<style>
:root {
--kaauh-teal: #00636e;
--kaauh-teal-dark: #004a53;
--kaauh-teal-light: #e0f7f9;
--kaauh-border: #e9ecef;
--kaauh-primary-text: #212529;
--kaauh-secondary-text: #6c757d;
--kaauh-gray-light: #f8f9fa;
--kaauh-success: #198754;
--kaauh-danger: #dc3545;
--kaauh-link: #007bff;
--kaauh-link-hover: #0056b3;
}
body { background-color: #f0f2f5; font-family: 'Inter', sans-serif; }
.card { border: none; border-radius: 8px; box-shadow: 0 3px 10px rgba(0,0,0,0.04); margin-bottom: 1rem; }
.card-body { padding: 1rem 1.25rem; }
#comments-card .card-header {
background-color: white;
color: var(--kaauh-teal-dark);
padding: 0.75rem 1.25rem;
font-weight: 600;
border-radius: 8px 8px 0 0;
border-bottom: 1px solid var(--kaauh-border);
}
.main-title-container h1 {
font-size: 1.75rem; font-weight: 700;
}
.status-badge {
font-size: 0.7rem; padding: 0.3em 0.7em; border-radius: 12px;
}
.bg-scheduled { background-color: #00636e !important; color: white !important; }
.bg-completed { background-color: #198754 !important; color: white !important; }
.bg-waiting { background-color: #ffc107 !important; color: var(--kaauh-primary-text) !important; }
.bg-started { background-color: var(--kaauh-teal) !important; color: white !important; }
.bg-ended { background-color: var(--kaauh-danger) !important; color: white !important; }
.bg-cancelled { background-color: #6c757d !important; color: white !important; }
.detail-section h2, .card h2 {
color: var(--kaauh-teal-dark); font-weight: 700; font-size: 1.25rem;
margin-bottom: 0.75rem; padding-bottom: 0.5rem; border-bottom: 1px solid var(--kaauh-border);
}
.detail-row-simple {
display: flex; padding: 0.4rem 0; border-bottom: 1px dashed var(--kaauh-border); font-size: 0.85rem;
}
.detail-label-simple { font-weight: 600; color: var(--kaauh-teal-dark); flex-basis: 40%; }
.detail-value-simple { color: var(--kaauh-primary-text); font-weight: 500; flex-basis: 60%; }
.btn-primary-teal {
background-color: var(--kaauh-teal); border-color: var(--kaauh-teal); padding: 0.6rem 1.2rem;
font-size: 0.95rem; border-radius: 6px; color: white;
}
.btn-primary-teal:hover { background-color: var(--kaauh-teal-dark); }
.btn-danger-red {
background-color: var(--kaauh-danger); border-color: var(--kaauh-danger); color: white;
padding: 0.6rem 1.2rem; font-size: 0.95rem; border-radius: 6px; font-weight: 600;
}
.btn-danger-red:hover { background-color: #c82333; border-color: #bd2130; }
.btn-secondary-back {
background-color: transparent; border: none; color: var(--kaauh-secondary-text);
font-weight: 600; font-size: 1rem; padding: 0.5rem 0.75rem; transition: color 0.2s;
}
.btn-secondary-back:hover { color: var(--kaauh-teal); text-decoration: underline; }
.join-url-display {
background-color: white; border: 1px solid var(--kaauh-border); padding: 0.5rem; font-size: 0.85rem;
}
.btn-copy-simple {
padding: 0.5rem 0.75rem; background-color: var(--kaauh-teal-dark); border: none; color: white; border-radius: 4px;
}
.btn-copy-simple:hover { background-color: var(--kaauh-teal); }
.simple-table {
width: 100%; margin-top: 0.5rem; border-collapse: collapse;
}
.simple-table th {
background-color: var(--kaauh-teal); color: white; font-weight: 700;
padding: 8px 12px; border: 1px solid var(--kaauh-border); font-size: 0.8rem;
}
.simple-table td {
padding: 8px 12px; border: 1px solid var(--kaauh-border); background-color: white; font-size: 0.85rem;
}
.comment-item { border: 1px solid var(--kaauh-border); background-color: var(--kaauh-gray-light); border-radius: 6px; }
.btn-edit-comment {
background-color: transparent; border: 1px solid var(--kaauh-teal); color: var(--kaauh-teal);
padding: 0.25rem 0.5rem; font-size: 0.75rem; border-radius: 4px; font-weight: 500;
}
.btn-edit-comment:hover { background-color: var(--kaauh-teal-light); }
</style>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
{# --- TOP BAR --- #}
<div class="d-flex justify-content-between align-items-center mb-4">
<a href="{% url 'list_meetings' %}" class="btn btn-secondary-back">
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Meetings" %}
</a>
<div class="d-flex gap-2">
<a href="{% url 'update_meeting' meeting.slug %}" class="btn btn-primary-teal btn-sm">
<i class="fas fa-edit me-1"></i> {% trans "Edit Meeting" %}
</a>
<form method="post" action="{% url 'delete_meeting' meeting.slug %}" style="display: inline;">
{% csrf_token %}
<button type="submit" class="btn btn-danger-red btn-sm" onclick="return confirm('{% trans "Are you sure you want to delete this meeting? This action is permanent." %}')">
<i class="fas fa-trash-alt me-1"></i> {% trans "Delete Meeting" %}
</button>
</form>
</div>
</div>
{# --- MAIN TITLE --- #}
<div class="main-title-container mb-4">
<h1 class="text-start" style="color: var(--kaauh-teal-dark);">
<i class="fas fa-video me-2" style="color: var(--kaauh-teal);"></i>
{{ meeting.topic|default:"[Meeting Topic]" }}
<span class="status-badge bg-{{ interview.status|lower|default:'scheduled' }} ms-3">
{{ interview.get_status_display|default:"Scheduled" }}
</span>
</h1>
</div>
{# --- INTERVIEW & CONNECTION CARDS --- #}
<div class="row g-4 mb-5 align-items-stretch">
{# Interview Detail #}
<div class="col-lg-6">
<div class="p-3 bg-white rounded shadow-sm h-100 d-flex flex-column">
<h2 class="text-start"><i class="fas fa-briefcase me-2"></i> {% trans "Interview Detail" %}</h2>
<div class="detail-row-group flex-grow-1">
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Job Title" %}:</div>
<div class="detail-value-simple">{{ job.title|default:"N/A" }}</div>
</div>
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Candidate Name" %}:</div>
<div class="detail-value-simple">{{ candidate.full_name|default:"N/A" }}</div>
</div>
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Candidate Email" %}:</div>
<div class="detail-value-simple">{{ candidate.email|default:"N/A" }}</div>
</div>
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Job Type" %}:</div>
<div class="detail-value-simple">{{ job.job_type|default:"N/A" }}</div>
</div>
{% if candidate.belong_to_agency %}
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Agency" %}:</div>
<div class="detail-value-simple">{{ candidate.hiring_agency.name|default:"N/A" }}</div>
</div>
{% endif %}
</div>
</div>
</div>
{# Connection Details #}
<div class="col-lg-6">
<div class="p-3 bg-white rounded shadow-sm h-100 d-flex flex-column">
<h2 class="text-start"><i class="fas fa-info-circle me-2"></i> {% trans "Connection Details" %}</h2>
<div class="detail-row-group flex-grow-1">
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Date & Time" %}:</div>
<div class="detail-value-simple">
{{ interview.interview_date }} {{ interview.interview_time }} ({{ meeting.timezone }})
</div>
</div>
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Duration" %}:</div>
<div class="detail-value-simple">
{% if meeting.location_type == "Remote" %}
{{ meeting.zoommeetingdetails.duration|default:"N/A" }}
{% elif meeting.location_type == "Onsite" %}
{{ meeting.onsitelocationdetails.duration|default:"N/A" }}
{% else %}
N/A
{% endif %}
{% trans "minutes" %}
</div>
</div>
{% if meeting.location_type == "Remote" %}
{% with zoom=meeting.zoommeetingdetails %}
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Meeting ID" %}:</div>
<div class="detail-value-simple">{{ zoom.meeting_id|default:"N/A" }}</div>
</div>
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Host Email" %}:</div>
<div class="detail-value-simple">{{ zoom.host_email|default:"N/A" }}</div>
</div>
{% if meeting.details_url %}
<div class="join-url-container pt-3" style="position: relative;">
<div id="copy-message" class="text-white rounded px-2 py-1 small fw-bold mb-2 text-center" style="opacity: 0; transition: opacity 0.3s; position: absolute; right: 0; top: -35px; background-color: var(--kaauh-success); z-index: 10;">
{% trans "Copied!" %}
</div>
<div class="join-url-display d-flex justify-content-between align-items-center">
<div class="text-truncate me-2">
<strong>{% trans "Join URL" %}:</strong>
<span id="meeting-join-url">{{ meeting.details_url }}</span>
</div>
<button class="btn-copy-simple ms-2 flex-shrink-0" onclick="copyLink()" title="{% trans 'Copy URL' %}">
<i class="fas fa-copy"></i>
</button>
</div>
</div>
{% endif %}
{% endwith %}
{% elif meeting.location_type == "Onsite" %}
{% with onsite=meeting.onsitelocationdetails %}
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Address" %}:</div>
<div class="detail-value-simple">{{ onsite.physical_address|default:"N/A" }}</div>
</div>
<div class="detail-row-simple">
<div class="detail-label-simple">{% trans "Room" %}:</div>
<div class="detail-value-simple">{{ onsite.room_number|default:"TBD" }}</div>
</div>
{% endwith %}
{% endif %}
</div>
</div>
</div>
</div>
{# --- PARTICIPANTS --- #}
<div class="row g-4 mt-1 mb-5">
<div class="col-lg-12">
<div class="p-3 bg-white rounded shadow-sm">
<div class="d-flex justify-content-between align-items-center">
<h2 class="text-start"><i class="fas fa-users-cog me-2"></i> {% trans "Assigned Participants" %}</h2>
<div class="d-flex gap-2">
<button type="button" class="btn btn-primary-teal btn-sm"
data-bs-toggle="modal" data-bs-target="#assignParticipants">
<i class="fas fa-users-cog me-1"></i> {% trans "Manage Participants" %} ({{ total_participants }})
</button>
<button type="button" class="btn btn-outline-info" data-bs-toggle="modal" data-bs-target="#emailModal">
<i class="fas fa-envelope"></i>
</button>
</div>
</div>
<table class="simple-table">
<thead>
<tr>
<th>{% trans "Name" %}</th>
<th>{% trans "Role" %}</th>
<th>{% trans "Email" %}</th>
<th>{% trans "Phone" %}</th>
<th>{% trans "Type" %}</th>
</tr>
</thead>
<tbody>
{% for participant in external_participants %}
<tr>
<td>{{ participant.name }}</td>
<td>{{ participant.designation|default:"Participant" }}</td>
<td>{{ participant.email|default:"N/A" }}</td>
<td>{{ participant.phone|default:"N/A" }}</td>
<td>{% trans "External" %}</td>
</tr>
{% endfor %}
{% for user in system_participants %}
<tr>
<td>{{ user.get_full_name|default:user.username }}</td>
<td>Admin</td>
<td>{{ user.email|default:"N/A" }}</td>
<td>{{ user.phone|default:"N/A" }}</td>
<td>{% trans "System User" %}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{# --- COMMENTS --- #}
<div class="row g-4 mt-1">
<div class="col-lg-12">
<div class="card" id="comments-card">
<div class="card-header d-flex justify-content-between align-items-center">
<h5 class="card-title mb-0">
<i class="fas fa-comments me-2"></i>
{% trans "Comments" %} ({{ interview.notes.count }})
</h5>
</div>
<div class="card-body">
<div id="comment-section" class="mb-4">
{% for note in interview.notes.all|dictsortreversed:"created_at" %}
<div class="comment-item mb-3 p-3">
<div id="comment-view-{{ note.pk }}">
<div class="d-flex justify-content-between align-items-start mb-2">
<div class="comment-metadata" style="font-size: 0.9rem;">
<strong>{{ note.author.get_full_name|default:note.author.username }}</strong>
<span class="text-muted small ms-2">{{ note.created_at|date:"M d, Y H:i" }}</span>
</div>
{% if note.author == user or user.is_staff %}
<div class="comment-actions d-flex align-items-center gap-1">
<button type="button" class="btn btn-edit-comment py-0 px-1" onclick="toggleCommentEdit('{{ note.pk }}')" id="edit-btn-{{ note.pk }}">
<i class="fas fa-edit"></i>
</button>
<form method="post" action="{% url 'delete_meeting_comment' meeting.slug note.pk %}" style="display: inline;">
{% csrf_token %}
<button type="submit" class="btn btn-outline-danger py-0 px-1" onclick="return confirm('{% trans "Are you sure you want to delete this comment?" %}')">
<i class="fas fa-trash"></i>
</button>
</form>
</div>
{% endif %}
</div>
<p class="mb-0" style="font-size: 0.85rem; white-space: pre-wrap;">{{ note.content|linebreaksbr }}</p>
</div>
<div id="comment-edit-form-{{ note.pk }}" style="display: none; margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--kaauh-border);">
<form method="POST" action="{% url 'edit_meeting_comment' meeting.slug note.pk %}">
{% csrf_token %}
<div class="mb-2">
<label class="form-label small">{% trans "Edit Comment" %}</label>
<textarea name="content" class="form-control" rows="3" required>{{ note.content }}</textarea>
</div>
<button type="submit" class="btn btn-success btn-sm me-2">
<i class="fas fa-save me-1"></i> {% trans "Save Changes" %}
</button>
<button type="button" class="btn btn-secondary btn-sm" onclick="toggleCommentEdit('{{ note.pk }}')">
{% trans "Cancel" %}
</button>
</form>
</div>
</div>
{% empty %}
<p class="text-muted">{% trans "No comments yet. Be the first to comment!" %}</p>
{% endfor %}
</div>
<hr>
<h6 class="mb-3">{% trans "Add a New Comment" %}</h6>
<form method="POST" action="{% url 'add_meeting_comment' meeting.slug %}">
{% csrf_token %}
<div class="mb-3">
<label class="form-label small">{% trans "Comment" %}</label>
<textarea name="content" class="form-control" rows="3" required></textarea>
</div>
<button type="submit" class="btn btn-primary-teal btn-sm">
<i class="fas fa-paper-plane me-1"></i> {% trans "Submit Comment" %}
</button>
</form>
</div>
</div>
</div>
</div>
</div>
{# MODALS #}
<!-- Participants Modal -->
<div class="modal fade" id="assignParticipants" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">{% trans "Manage all participants" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="post" action="{% url 'create_interview_participants' interview.slug %}">
{% csrf_token %}
<div class="modal-body table-responsive">
{{ meeting.name }}
<hr>
<table class="table tab table-bordered mt-3">
<thead>
<th class="col">👥 {% trans "Participants" %}</th>
<th class="col">🧑‍💼 {% trans "Users" %}</th>
</thead>
<tbody>
<tr>
<td>
{{ form.participants.errors }}
{{ form.participants }}
</td>
<td> {{ form.system_users.errors }}
{{ form.system_users }}
</td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger-red" data-bs-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary-teal">{% trans "Save" %}</button>
</div>
</form>
</div>
</div>
</div>
<!-- Email Modal -->
<div class="modal fade" id="emailModal" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header bg-light">
<h5 class="modal-title">📧 {% trans "Compose Interview Invitation" %}</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<form method="post" action="{% url 'send_interview_email' interview.slug %}">
{% csrf_token %}
<div class="modal-body">
<div class="mb-3">
<label class="form-label fw-bold">{% trans "Subject" %}</label>
{{ email_form.subject|add_class:"form-control" }}
</div>
<ul class="nav nav-tabs" id="messageTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="candidate-tab" data-bs-toggle="tab" data-bs-target="#candidate-pane" type="button">
{% if candidate.belong_to_agency %}
{% trans "Agency Message" %}
{% else %}
{% trans "Candidate Message" %}
{% endif %}
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="participants-tab" data-bs-toggle="tab" data-bs-target="#participants-pane" type="button">
{% trans "Panel Message" %}
</button>
</li>
</ul>
<div class="tab-content border border-top-0 p-3 bg-light-subtle">
<div class="tab-pane fade show active" id="candidate-pane">
<p class="text-muted small">
{% if candidate.belong_to_agency %}
{% trans "This email will be sent to the hiring agency." %}
{% else %}
{% trans "This email will be sent to the candidate." %}
{% endif %}
</p>
{% if candidate.belong_to_agency %}
{{ email_form.message_for_agency|add_class:"form-control" }}
{% else %}
{{ email_form.message_for_candidate|add_class:"form-control" }}
{% endif %}
</div>
<div class="tab-pane fade" id="participants-pane">
<p class="text-muted small">{% trans "This email will be sent to all interview participants." %}</p>
{{ email_form.message_for_participants|add_class:"form-control" }}
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger-red" data-bs-dismiss="modal">{% trans "Close" %}</button>
<button type="submit" class="btn btn-primary-teal">{% trans "Send Invitation" %}</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block customJS %}
<script>
function toggleCommentEdit(commentPk) {
const viewDiv = document.getElementById(`comment-view-${commentPk}`);
const editFormDiv = document.getElementById(`comment-edit-form-${commentPk}`);
if (viewDiv.style.display === 'none') {
viewDiv.style.display = 'block';
editFormDiv.style.display = 'none';
} else {
viewDiv.style.display = 'none';
editFormDiv.style.display = 'block';
}
}
function copyLink() {
const urlElement = document.getElementById('meeting-join-url');
const textToCopy = urlElement.textContent || urlElement.innerText;
const messageElement = document.getElementById('copy-message');
navigator.clipboard.writeText(textToCopy).then(() => {
messageElement.style.opacity = '1';
setTimeout(() => {
messageElement.style.opacity = '0';
}, 2000);
}).catch(err => {
console.error('Failed to copy: ', err);
});
}
</script>
{% endblock %}