687 lines
31 KiB
HTML
687 lines
31 KiB
HTML
{% extends 'base.html' %}
|
|
{% load static i18n %}
|
|
{% load widget_tweaks %}
|
|
{% block customCSS %}
|
|
<style>
|
|
/* -------------------------------------------------------------------------- */
|
|
/* KAAT-S Redesign CSS - Compacted and Reordered Layout */
|
|
/* -------------------------------------------------------------------------- */
|
|
|
|
: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 & Header Styles ------------------ */
|
|
|
|
.card {
|
|
border: none;
|
|
border-radius: 8px; /* Slightly smaller radius */
|
|
box-shadow: 0 3px 10px rgba(0,0,0,0.04); /* Lighter shadow */
|
|
margin-bottom: 1rem;
|
|
}
|
|
.card-body {
|
|
padding: 1rem 1.25rem; /* Reduced padding */
|
|
}
|
|
#comments-card .card-header {
|
|
background-color: white;
|
|
color: var(--kaauh-teal-dark);
|
|
padding: 0.75rem 1.25rem; /* Reduced header padding */
|
|
font-weight: 600;
|
|
border-radius: 8px 8px 0 0;
|
|
border-bottom: 1px solid var(--kaauh-border);
|
|
}
|
|
|
|
/* ------------------ Main Title & Status ------------------ */
|
|
.main-title-container {
|
|
padding: 0 0 1rem 0; /* Space below the main title */
|
|
}
|
|
.main-title-container h1 {
|
|
font-size: 1.75rem; /* Reduced size */
|
|
font-weight: 700;
|
|
}
|
|
|
|
.status-badge {
|
|
font-size: 0.7rem; /* Smaller badge */
|
|
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;}
|
|
|
|
/* ------------------ Detail Row & Content Styles (Made Smaller) ------------------ */
|
|
|
|
.detail-section h2, .card h2 {
|
|
color: var(--kaauh-teal-dark);
|
|
font-weight: 700;
|
|
font-size: 1.25rem; /* Reduced size */
|
|
margin-bottom: 0.75rem;
|
|
padding-bottom: 0.5rem;
|
|
border-bottom: 1px solid var(--kaauh-border);
|
|
}
|
|
|
|
.detail-row-simple {
|
|
display: flex;
|
|
padding: 0.4rem 0; /* Reduced vertical padding */
|
|
border-bottom: 1px dashed var(--kaauh-border);
|
|
font-size: 0.85rem; /* Smaller text */
|
|
}
|
|
.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%;
|
|
}
|
|
|
|
/* ------------------ Join Info & Copy Button ------------------ */
|
|
|
|
.btn-primary-teal {
|
|
background-color: var(--kaauh-teal);
|
|
border-color: var(--kaauh-teal);
|
|
padding: 0.6rem 1.2rem;
|
|
font-size: 0.95rem; /* Slightly smaller button */
|
|
border-radius: 6px;
|
|
color: white; /* Ensure text color is white for teal primary */
|
|
}
|
|
.btn-primary-teal:hover {
|
|
background-color: var(--kaauh-teal-dark);
|
|
border-color: var(--kaauh-teal-dark);
|
|
}
|
|
|
|
/* Added Danger Button Style for main delete */
|
|
.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 {
|
|
/* Subtle Back Button */
|
|
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; /* Reduced padding */
|
|
font-size: 0.85rem; /* Smaller text */
|
|
}
|
|
|
|
.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 Styles ------------------ */
|
|
.simple-table {
|
|
width: 100%;
|
|
margin-top: 0.5rem;
|
|
border-collapse: collapse;
|
|
}
|
|
.simple-table th {
|
|
background-color: var(--kaauh-teal-light);
|
|
color: var(--kaauh-teal-dark);
|
|
font-weight: 700;
|
|
padding: 8px 12px; /* Reduced padding */
|
|
border: 1px solid var(--kaauh-border);
|
|
font-size: 0.8rem; /* Smaller table header text */
|
|
}
|
|
.simple-table td {
|
|
padding: 8px 12px; /* Reduced padding */
|
|
border: 1px solid var(--kaauh-border);
|
|
background-color: white;
|
|
font-size: 0.85rem; /* Smaller table body text */
|
|
}
|
|
|
|
/* ------------------ Comment Specific Styles ------------------ */
|
|
.comment-item {
|
|
border: 1px solid var(--kaauh-border);
|
|
background-color: var(--kaauh-gray-light);
|
|
border-radius: 6px;
|
|
}
|
|
/* Style for in-page edit button */
|
|
.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 / BACK BUTTON & ACTIONS (EDIT/DELETE) --- #}
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
{# Back Button #}
|
|
<a href="{% url 'list_meetings' %}" class="btn btn-secondary-back">
|
|
<i class="fas fa-arrow-left me-1"></i> {% trans "Back to Meetings" %}
|
|
</a>
|
|
|
|
{# Edit and Delete Buttons #}
|
|
<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>
|
|
|
|
{# Send Candidate Invitation Button #}
|
|
<form method="post" action="{% url 'send_candidate_invitation' meeting.slug %}" style="display: inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-outline-info btn-sm" onclick="return confirm('{% trans "Send invitation email to the candidate?" %}')">
|
|
<i class="fas fa-envelope me-1"></i> {% trans "Send Candidate Invitation" %}
|
|
</button>
|
|
</form>
|
|
|
|
{# DELETE MEETING FORM #}
|
|
<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 AT TOP --- #}
|
|
{# ========================================================= #}
|
|
<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 N/A]" }}
|
|
<span class="status-badge bg-{{ meeting.status|lower|default:'bg-secondary' }} ms-3">
|
|
{{ meeting.status|title|default:'N/A' }}
|
|
</span>
|
|
</h1>
|
|
</div>
|
|
|
|
{# ========================================================= #}
|
|
{# --- SECTION 1: INTERVIEW & CONNECTION CARDS SIDE BY SIDE --- #}
|
|
{# ========================================================= #}
|
|
<div class="row g-4 mb-5 align-items-stretch">
|
|
|
|
{# --- LEFT HALF: INTERVIEW DETAIL CARD --- #}
|
|
<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">{{ meeting.get_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"><a href="">{{ meeting.candidate_full_name|default:"N/A" }}</a></div></div>
|
|
<div class="detail-row-simple"><div class="detail-label-simple">{% trans "Candidate Email" %}:</div><div class="detail-value-simple"><a href="">{{ meeting.get_candidate.email|default:"N/A" }}</a></div></div>
|
|
<div class="detail-row-simple"><div class="detail-label-simple">{% trans "Job Type" %}:</div><div class="detail-value-simple">{{ meeting.get_job.job_type|default:"N/A" }}</div></div>
|
|
{% if meeting.get_candidate.belong_to_agency %}
|
|
<div class="detail-row-simple"><div class="detail-label-simple">{% trans "Agency" %}:</div><div class="detail-value-simple"><a href="">{{ meeting.get_candidate.hiring_agency.name|default:"N/A" }}</a></div></div>
|
|
{% endif %}
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{# --- RIGHT HALF: CONNECTION DETAILS CARD --- #}
|
|
<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">{{ meeting.start_time|date:"M d, Y H:i"|default:"N/A" }}</div></div>
|
|
<div class="detail-row-simple"><div class="detail-label-simple">{% trans "Duration" %}:</div><div class="detail-value-simple">{{ meeting.duration|default:"N/A" }} {% trans "minutes" %}</div></div>
|
|
<div class="detail-row-simple"><div class="detail-label-simple">{% trans "Meeting ID" %}:</div><div class="detail-value-simple">{{ meeting.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">{{ meeting.host_email|default:"N/A" }}</div></div>
|
|
{% if meeting.join_url %}
|
|
<div class="join-url-container pt-3">
|
|
<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: 5px; background-color: var(--kaauh-success); z-index: 10;">{% trans "Copied!" %}</div>
|
|
|
|
<div class="join-url-display d-flex justify-content-between align-items-center position-relative">
|
|
<div class="text-truncate me-2">
|
|
<strong>{% trans "Join URL" %}:</strong>
|
|
<span id="meeting-join-url">{{ meeting.join_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 %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{# ========================================================= #}
|
|
{# --- SECTION 2: PERSONNEL TABLES --- #}
|
|
{# ========================================================= #}
|
|
<div class="row g-4 mt-1 mb-5">
|
|
|
|
|
|
{# --- PARTICIPANTS TABLE --- #}
|
|
{% comment %} <div class="col-lg-12">
|
|
<div class="p-3 bg-white rounded shadow-sm">
|
|
<div class="d-flex justify-content-between align-item-center" >
|
|
<h2 class="text-start"><i class="fas fa-users-cog me-2"></i> {% trans "Assigned Participants" %}</h2>
|
|
<!--manage participants for interview-->
|
|
<div class="d-flex justify-content-center align-item-center">
|
|
<button type="button" class="btn btn-primary-teal btn-sm me-2"
|
|
data-bs-toggle="modal"
|
|
data-bs-target="#assignParticipants">
|
|
<i class="fas fa-users-cog me-1"></i> {% trans "Manage Participants" %} ({{total_participants}})
|
|
</button>
|
|
|
|
{# Send Participants Invitation Button #}
|
|
<form method="post" action="{% url 'send_participants_invitation' meeting.slug %}" style="display: inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-outline-info btn-sm me-2" onclick="return confirm('{% trans "Send invitation email to all participants?" %}')">
|
|
<i class="fas fa-envelope me-1"></i> {% trans "Send Participants Invitation" %}
|
|
</button>
|
|
</form>
|
|
|
|
<button type="button" class="btn btn-outline-info"
|
|
data-bs-toggle="modal"
|
|
title="Send Interview Emails"
|
|
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/Designation" %}</th>
|
|
<th>{% trans "Email" %}</th>
|
|
<th>{% trans "Phone Number" %}</th>
|
|
<th>{% trans "Source Type" %}</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for participant in meeting.get_participants %}
|
|
<tr>
|
|
<td>{{participant.name}}</td>
|
|
<td>{{participant.designation}}</td>
|
|
<td>{{participant.email}}</td>
|
|
<td>{{participant.phone}}</td>
|
|
<td>{% trans "External Participants" %}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
{% for user in meeting.get_users %}
|
|
<tr>
|
|
<td>{{user.get_full_name}}</td>
|
|
<td>Admin</td>
|
|
<td>{{user.email}}</td>
|
|
<td>{{user.phone}}</td>
|
|
<td>{% trans "System User" %}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div> {% endcomment %}
|
|
</div>
|
|
|
|
{# ========================================================= #}
|
|
{# --- SECTION 3: COMMENTS (CORRECTED) --- #}
|
|
{# ========================================================= #}
|
|
<div class="row g-4 mt-1">
|
|
|
|
{% comment %} <div class="col-lg-12">
|
|
<div class="card" id="comments-card" style="height: 100%;">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="card-title mb-0" style="color: var(--kaauh-teal-dark);">
|
|
<i class="fas fa-comments me-2"></i>
|
|
{% trans "Comments" %} ({% if meeting.comments %}{{ meeting.comments.count }}{% else %}0{% endif %})
|
|
</h5>
|
|
</div>
|
|
<div class="card-body overflow-auto">
|
|
{# 1. COMMENT DISPLAY & IN-PAGE EDIT FORMS #}
|
|
<div id="comment-section" class="mb-4">
|
|
{% if meeting.comments.all %}
|
|
{% for comment in meeting.comments.all|dictsortreversed:"created_at" %}
|
|
|
|
<div class="comment-item mb-3 p-3">
|
|
|
|
{# Read-Only Comment View #}
|
|
<div id="comment-view-{{ comment.pk }}">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<div class="comment-metadata" style="font-size: 0.9rem;">
|
|
<strong>{{ comment.author.get_full_name|default:comment.author.username }}</strong>
|
|
<span class="text-muted small ms-2">{{ comment.created_at|date:"M d, Y H:i" }}</span>
|
|
</div>
|
|
|
|
{% if comment.author == user or user.is_staff %}
|
|
<div class="comment-actions d-flex align-items-center gap-1">
|
|
{# Edit Button: Toggles the hidden form #}
|
|
<button type="button" class="btn btn-edit-comment py-0 px-1" onclick="toggleCommentEdit('{{ comment.pk }}')" id="edit-btn-{{ comment.pk }}" title="{% trans 'Edit Comment' %}">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
|
|
{# Delete Form: Submits a POST request #}
|
|
<form method="post" action="{% url 'delete_meeting_comment' meeting.slug comment.pk %}" style="display: inline;" id="delete-form-{{ comment.pk }}">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-outline-danger py-0 px-1" title="{% trans 'Delete Comment' %}" 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 comment-content" style="font-size: 0.85rem; white-space: pre-wrap;">{{ comment.content|linebreaksbr }}</p>
|
|
</div>
|
|
|
|
{# Hidden Edit Form #}
|
|
<div id="comment-edit-form-{{ comment.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 comment.pk %}" id="form-{{ comment.pk }}">
|
|
{% csrf_token %}
|
|
<div class="mb-2">
|
|
<label for="id_content_{{ comment.pk }}" class="form-label small">{% trans "Edit Comment" %}</label>
|
|
{# NOTE: The textarea name must match your Comment model field (usually 'content') #}
|
|
<textarea name="content" id="id_content_{{ comment.pk }}" rows="3" class="form-control" required>{{ comment.content }}</textarea>
|
|
</div>
|
|
<button type="submit" class="btn btn-sm btn-success me-2">
|
|
<i class="fas fa-save me-1"></i> {% trans "Save Changes" %}
|
|
</button>
|
|
<button type="button" class="btn btn-sm btn-secondary" onclick="toggleCommentEdit('{{ comment.pk }}')">
|
|
{% trans "Cancel" %}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
|
|
</div>
|
|
{% endfor %}
|
|
{% else %}
|
|
<p class="text-muted">{% trans "No comments yet. Be the first to comment!" %}</p>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<hr>
|
|
|
|
{# 2. NEW COMMENT SUBMISSION (Remains the same) #}
|
|
<h6 class="mb-3" style="color: var(--kaauh-teal-dark);">{% trans "Add a New Comment" %}</h6>
|
|
{% if user.is_authenticated %}
|
|
<form method="POST" action="{% url 'add_meeting_comment' meeting.slug %}">
|
|
{% csrf_token %}
|
|
{% if comment_form %}
|
|
{{ comment_form.as_p }}
|
|
{% else %}
|
|
<div class="mb-3">
|
|
<label for="id_content" class="form-label small">{% trans "Comment" %}</label>
|
|
<textarea name="content" id="id_content" rows="3" class="form-control" required></textarea>
|
|
</div>
|
|
{% endif %}
|
|
<button type="submit" class="btn btn-primary-teal btn-sm mt-2">
|
|
<i class="fas fa-paper-plane me-1"></i> {% trans "Submit Comment" %}
|
|
</button>
|
|
</form>
|
|
{% else %}
|
|
<p class="text-muted small">{% trans "You must be logged in to add a comment." %}</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div> {% endcomment %}
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<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">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="jobAssignmentLabel">{% 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' meeting.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 btn-sm">{% trans "Save" %}</button>
|
|
</div>
|
|
</form>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!--email modal class-->
|
|
<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">
|
|
<div class="modal-header bg-light">
|
|
<h5 class="modal-title" id="emailModalLabel">📧 {% 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' meeting.interview.slug %}">
|
|
{% csrf_token %}
|
|
<div class="modal-body">
|
|
|
|
<div class="mb-3">
|
|
<label for="{{ email_form.subject.id_for_label }}" class="form-label fw-bold">Subject</label>
|
|
{{ email_form.subject | add_class:"form-control" }}
|
|
</div>
|
|
|
|
<ul class="nav nav-tabs" id="messageTabs" role="tablist">
|
|
{# Candidate/Agency Tab - Active by default #}
|
|
<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" role="tab" aria-controls="candidate-pane" aria-selected="true">
|
|
{% if candidate.belong_to_an_agency %}
|
|
{% trans "Agency Message" %}
|
|
{% else %}
|
|
{% trans "Candidate Message" %}
|
|
{% endif %}
|
|
</button>
|
|
</li>
|
|
{# Participants Tab #}
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link" 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 border border-top-0 p-3 bg-light-subtle">
|
|
|
|
{# --- Candidate/Agency Pane --- #}
|
|
<div class="tab-pane fade show active" id="candidate-pane" role="tabpanel" aria-labelledby="candidate-tab">
|
|
<p class="text-muted small">{% trans "This email will be sent to the candidate or their hiring agency." %}</p>
|
|
|
|
{% if not candidate.belong_to_an_agency %}
|
|
<div class="form-group">
|
|
<label for="{{ email_form.message_for_candidate.id_for_label }}" class="form-label d-none">{% trans "Candidate Message" %}</label>
|
|
{{ email_form.message_for_candidate | add_class:"form-control" }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if candidate.belong_to_an_agency %}
|
|
<div class="form-group">
|
|
<label for="{{ email_form.message_for_agency.id_for_label }}" class="form-label d-none">{% trans "Agency Message" %}</label>
|
|
{{ email_form.message_for_agency | add_class:"form-control" }}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
|
|
{# --- Participants Pane --- #}
|
|
<div class="tab-pane fade" id="participants-pane" role="tabpanel" aria-labelledby="participants-tab">
|
|
<p class="text-muted small">{% trans "This email will be sent to the internal and external interview participants." %}</p>
|
|
<div class="form-group">
|
|
<label for="{{ email_form.message_for_participants.id_for_label }}" class="form-label d-none">{% trans "Participants Message" %}</label>
|
|
{{ email_form.message_for_participants | add_class:"form-control" }}
|
|
</div>
|
|
</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>
|
|
// --- COMMENT EDITING FUNCTION ---
|
|
function toggleCommentEdit(commentPk) {
|
|
const viewDiv = document.getElementById(`comment-view-${commentPk}`);
|
|
const editFormDiv = document.getElementById(`comment-edit-form-${commentPk}`);
|
|
const editButton = document.getElementById(`edit-btn-${commentPk}`);
|
|
const deleteForm = document.getElementById(`delete-form-${commentPk}`);
|
|
|
|
if (viewDiv.style.display !== 'none') {
|
|
// Switch to Edit Mode
|
|
viewDiv.style.display = 'none';
|
|
editFormDiv.style.display = 'block';
|
|
if (editButton) editButton.style.display = 'none'; // Hide edit button
|
|
if (deleteForm) deleteForm.style.display = 'none'; // Hide delete button
|
|
} else {
|
|
// Switch back to View Mode (Cancel)
|
|
viewDiv.style.display = 'block';
|
|
editFormDiv.style.display = 'none';
|
|
if (editButton) editButton.style.display = 'inline-block'; // Show edit button
|
|
if (deleteForm) deleteForm.style.display = 'inline'; // Show delete button
|
|
}
|
|
}
|
|
|
|
// --- COPY LINK FUNCTION ---
|
|
// CopyLink function implementation (slightly improved for message placement)
|
|
function copyLink() {
|
|
const urlElement = document.getElementById('meeting-join-url');
|
|
const displayContainer = urlElement.closest('.join-url-display');
|
|
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 ? 'var(--kaauh-success)' : 'var(--kaauh-danger)';
|
|
messageElement.style.opacity = '1';
|
|
|
|
// Position the message relative to the display container
|
|
const rect = displayContainer.getBoundingClientRect();
|
|
// Note: This positioning logic relies on the .join-url-container being position:relative or position:absolute
|
|
messageElement.style.left = (rect.width / 2) - (messageElement.offsetWidth / 2) + 'px';
|
|
messageElement.style.top = '-35px';
|
|
|
|
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 %}
|