151 lines
7.3 KiB
HTML
151 lines
7.3 KiB
HTML
<!-- This snippet is loaded by HTMX into #meetingModalBody -->
|
|
<form id="meetingForm" method="post" action="{{ action_url }}?_target=modal" data-bs-theme="light">
|
|
{% csrf_token %}
|
|
<input type="hidden" name="candidate_pk" value="{{ candidate.pk }}">
|
|
{% if scheduled_interview %}
|
|
<input type="hidden" name="interview_pk" value="{{ scheduled_interview.pk }}">
|
|
{% endif %}
|
|
|
|
<div class="mb-3">
|
|
<label for="id_topic" class="form-label">{% trans "Topic" %}</label>
|
|
<input type="text" class="form-control" id="id_topic" name="topic" value="{{ initial_data.topic|default:'' }}" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="id_start_time" class="form-label">{% trans "Start Time and Date" %}</label>
|
|
<input type="datetime-local" class="form-control" id="id_start_time" name="start_time" value="{{ initial_data.start_time|default:'' }}" required>
|
|
</div>
|
|
|
|
<div class="mb-3">
|
|
<label for="id_duration" class="form-label">{% trans "Duration (minutes)" %}</label>
|
|
<input type="number" class="form-control" id="id_duration" name="duration" value="{{ initial_data.duration|default:60 }}" min="15" step="15" required>
|
|
</div>
|
|
|
|
<div id="meetingDetails" class="alert alert-info" style="display: none;">
|
|
<strong>{% trans "Meeting Details (will appear after scheduling):" %}</strong>
|
|
<p><strong>{% trans "Join URL:" %}</strong> <a id="joinUrlDisplay" href="#" target="_blank"></a></p>
|
|
<p><strong>{% trans "Meeting ID:" %}</strong> <span id="meetingIdDisplay"></span></p>
|
|
</div>
|
|
|
|
<div id="successMessage" class="alert alert-success" style="display: none;">
|
|
<span id="successText"></span>
|
|
<small><a id="joinLinkSuccess" href="#" target="_blank" style="color: inherit; text-decoration: underline;">{% trans "Click here to join meeting" %}</a></small>
|
|
</div>
|
|
|
|
<div id="errorMessage" class="alert alert-danger" style="display: none;">
|
|
<span id="errorText"></span>
|
|
</div>
|
|
|
|
<div class="d-flex justify-content-end gap-2 mt-4">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" data-dismiss="modal">{% trans "Cancel" %}</button>
|
|
<button type="submit" class="btn btn-primary" id="scheduleBtn">
|
|
{% if scheduled_interview %}{% trans "Reschedule Meeting" %}{% else %}{% trans "Schedule Meeting" %}{% endif %}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
{% block customJS %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const form = document.getElementById('meetingForm');
|
|
const scheduleBtn = document.getElementById('scheduleBtn');
|
|
const meetingDetailsDiv = document.getElementById('meetingDetails');
|
|
const joinUrlDisplay = document.getElementById('joinUrlDisplay');
|
|
const meetingIdDisplay = document.getElementById('meetingIdDisplay');
|
|
const successMessageDiv = document.getElementById('successMessage');
|
|
const successText = document.getElementById('successText');
|
|
const joinLinkSuccess = document.getElementById('joinLinkSuccess');
|
|
const errorMessageDiv = document.getElementById('errorMessage');
|
|
const errorText = document.getElementById('errorText');
|
|
const modalElement = document.getElementById('meetingModal'); // This should be on the parent page
|
|
const modalTitle = document.querySelector('#meetingModal .modal-title'); // Parent page element
|
|
|
|
// Update modal title based on data attributes from the triggering button (if available)
|
|
// This is a fallback, ideally the parent page JS updates the title before fetching.
|
|
// Or, the view context could set a variable for the title.
|
|
// For simplicity, we'll assume parent page JS or rely on initial context.
|
|
const modalTitleText = modalTitle.getAttribute('data-current-title') || "{% trans 'Schedule Interview' %}";
|
|
if (modalTitle) {
|
|
modalTitle.textContent = modalTitleText;
|
|
}
|
|
const submitBtnText = scheduleBtn.getAttribute('data-current-submit-text') || "{% trans 'Schedule Meeting' %}";
|
|
scheduleBtn.textContent = submitBtnText;
|
|
|
|
|
|
form.addEventListener('submit', function(event) {
|
|
event.preventDefault();
|
|
|
|
meetingDetailsDiv.style.display = 'none';
|
|
successMessageDiv.style.display = 'none';
|
|
errorMessageDiv.style.display = 'none';
|
|
|
|
scheduleBtn.disabled = true;
|
|
scheduleBtn.innerHTML = '<span class="spinner-border spinner-border-sm me-2" role="status" aria-hidden="true"></span> {% trans "Processing..." %}';
|
|
|
|
const formData = new FormData(form);
|
|
// Check if the target is modal, if so, we might want to close it on success
|
|
const isModalTarget = new URLSearchParams(window.location.search).get('_target') === 'modal';
|
|
const url = form.action.replace(/\?.*$/, ""); // Remove any existing query params like _target
|
|
|
|
fetch(url, {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: {
|
|
'X-CSRFToken': formData.get('csrfmiddlewaretoken'),
|
|
'Accept': 'application/json',
|
|
},
|
|
})
|
|
.then(response => response.json()) // Always expect JSON for HTMX success/error
|
|
.then(data => {
|
|
scheduleBtn.disabled = false;
|
|
scheduleBtn.innerHTML = submitBtnText; // Reset to original text
|
|
|
|
if (data.success) {
|
|
successText.textContent = data.message;
|
|
successMessageDiv.style.display = 'block';
|
|
if (data.join_url) {
|
|
joinUrlDisplay.textContent = data.join_url;
|
|
joinUrlDisplay.href = data.join_url;
|
|
joinLinkSuccess.href = data.join_url;
|
|
meetingDetailsDiv.style.display = 'block'; // Keep meeting details shown
|
|
}
|
|
if (data.meeting_id) {
|
|
meetingIdDisplay.textContent = data.meeting_id;
|
|
}
|
|
|
|
if (isModalTarget && modalElement) {
|
|
const bsModal = bootstrap.Modal.getInstance(modalElement);
|
|
if (bsModal) bsModal.hide();
|
|
}
|
|
// Optionally, trigger an event on the parent page to update its list
|
|
if (window.parent && window.parent.dispatchEvent) {
|
|
window.parent.dispatchEvent(new CustomEvent('meetingUpdated', { detail: data }));
|
|
} else {
|
|
// Fallback: reload the page if it's not in an iframe or parent dispatch is not available
|
|
// window.location.reload();
|
|
}
|
|
|
|
} else {
|
|
errorText.textContent = data.error || '{% trans "An unknown error occurred." %}';
|
|
errorMessageDiv.style.display = 'block';
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
scheduleBtn.disabled = false;
|
|
scheduleBtn.innerHTML = submitBtnText;
|
|
errorText.textContent = '{% trans "An error occurred while processing your request." %}';
|
|
errorMessageDiv.style.display = 'block';
|
|
});
|
|
});
|
|
|
|
// Repopulate if initial_data was passed (for rescheduling)
|
|
{% if initial_data %}
|
|
document.getElementById('id_topic').value = '{{ initial_data.topic }}';
|
|
document.getElementById('id_start_time').value = '{{ initial_data.start_time }}';
|
|
document.getElementById('id_duration').value = '{{ initial_data.duration }}';
|
|
{% endif %}
|
|
});
|
|
</script>
|
|
{% endblock %}
|