Files
Student-Management-System-I…/static/js/admin_dashboard.js
T
2025-04-15 04:20:26 +05:45

964 lines
34 KiB
JavaScript

// Function to update leave requests
function updateLeaveRequests() {
// Fetch staff leave requests
fetch('/app/get-staff-leaves/')
.then(response => response.json())
.then(data => {
const staffLeavesContainer = document.querySelector('#staff-leaves-container');
if (data.staff_leaves.length === 0) {
staffLeavesContainer.innerHTML = `
<div class="text-center">
<small class="text-muted">No pending staff leave requests</small>
</div>
`;
return;
}
let staffLeavesHtml = '';
data.staff_leaves.forEach(leave => {
staffLeavesHtml += `
<div class="d-flex align-items-center mb-3 pb-3 border-bottom">
<div class="flex-shrink-0 me-3">
<div class="rounded bg-light d-flex align-items-center justify-content-center" style="width: 60px; height: 60px;">
<i class="fas fa-calendar-times text-info"></i>
</div>
</div>
<div class="flex-grow-1">
<small class="mb-0 d-block fw-medium">${leave.staff_name}</small>
<small class="text-muted">From: ${leave.start_date}</small>
<small class="text-muted d-block">To: ${leave.end_date}</small>
<small class="text-muted d-block">${leave.message}</small>
<div class="mt-2">
<form method="post" action="/app/approve-staff-leave/${leave.id}/" class="d-inline">
<input type="hidden" name="csrfmiddlewaretoken" value="${document.querySelector('[name=csrfmiddlewaretoken]').value}">
<button type="submit" class="btn btn-success btn-sm">
<i class="fas fa-check me-1"></i>Approve
</button>
</form>
<form method="post" action="/app/reject-staff-leave/${leave.id}/" class="d-inline ms-2">
<input type="hidden" name="csrfmiddlewaretoken" value="${document.querySelector('[name=csrfmiddlewaretoken]').value}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="fas fa-times me-1"></i>Reject
</button>
</form>
</div>
</div>
</div>
`;
});
staffLeavesContainer.innerHTML = staffLeavesHtml;
});
// Fetch student leave requests
fetch('/app/get-student-leaves/')
.then(response => response.json())
.then(data => {
const studentLeavesContainer = document.querySelector('#student-leaves-container');
if (data.student_leaves.length === 0) {
studentLeavesContainer.innerHTML = `
<div class="text-center">
<small class="text-muted">No pending student leave requests</small>
</div>
`;
return;
}
let studentLeavesHtml = '';
data.student_leaves.forEach(leave => {
studentLeavesHtml += `
<div class="d-flex align-items-center mb-3 pb-3 border-bottom">
<div class="flex-shrink-0 me-3">
<div class="rounded bg-light d-flex align-items-center justify-content-center" style="width: 60px; height: 60px;">
<i class="fas fa-calendar-times text-warning"></i>
</div>
</div>
<div class="flex-grow-1">
<small class="mb-0 d-block fw-medium">${leave.student_name}</small>
<small class="text-muted">From: ${leave.start_date}</small>
<small class="text-muted d-block">To: ${leave.end_date}</small>
<small class="text-muted d-block">${leave.message}</small>
<div class="mt-2">
<form method="post" action="/app/approve-student-leave/${leave.id}/" class="d-inline">
<input type="hidden" name="csrfmiddlewaretoken" value="${document.querySelector('[name=csrfmiddlewaretoken]').value}">
<button type="submit" class="btn btn-success btn-sm">
<i class="fas fa-check me-1"></i>Approve
</button>
</form>
<form method="post" action="/app/reject-student-leave/${leave.id}/" class="d-inline ms-2">
<input type="hidden" name="csrfmiddlewaretoken" value="${document.querySelector('[name=csrfmiddlewaretoken]').value}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="fas fa-times me-1"></i>Reject
</button>
</form>
</div>
</div>
</div>
`;
});
studentLeavesContainer.innerHTML = studentLeavesHtml;
});
}
// Meeting-related functions
function viewMeetingNotes(meetingId) {
const modal = document.getElementById('viewNotesModal');
const errorDiv = document.getElementById('notesError');
const loadingDiv = document.getElementById('notesLoading');
const contentDiv = document.getElementById('meetingNotesContent');
const notesText = document.getElementById('viewMeetingNotesText');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'block';
contentDiv.style.display = 'none';
notesText.textContent = '';
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleNotesEscapeKey);
// Fetch notes
fetch(`/app/api/meetings/${meetingId}/notes/`, {
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Response was not JSON");
}
return response.json();
})
.then(data => {
if (data.success) {
notesText.textContent = data.notes || 'No notes available';
loadingDiv.style.display = 'none';
contentDiv.style.display = 'block';
} else {
throw new Error(data.error || 'Failed to fetch notes');
}
})
.catch(error => {
console.error('Error:', error);
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
loadingDiv.style.display = 'none';
});
}
function closeNotesModal() {
const modal = document.getElementById('viewNotesModal');
const errorDiv = document.getElementById('notesError');
const loadingDiv = document.getElementById('notesLoading');
const contentDiv = document.getElementById('meetingNotesContent');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
contentDiv.style.display = 'none';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleNotesEscapeKey);
}
function handleNotesEscapeKey(event) {
if (event.key === 'Escape') {
closeNotesModal();
}
}
// Make all meeting-related functions globally available
window.viewMeetingAgenda = function(meetingId) {
const modal = document.getElementById('viewAgendaModal');
const errorDiv = document.getElementById('agendaError');
const loadingDiv = document.getElementById('agendaLoading');
const contentDiv = document.getElementById('meetingAgendaContent');
const agendaText = document.getElementById('viewMeetingAgendaText');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'block';
contentDiv.style.display = 'none';
agendaText.textContent = '';
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleAgendaEscapeKey);
// Fetch agenda
fetch(`/app/api/meetings/${meetingId}/agenda/`, {
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
})
.then(response => {
if (!response.ok) {
throw new Error(`Network response was not ok: ${response.status} ${response.statusText}`);
}
return response.json();
})
.then(data => {
console.log('Received agenda data:', data);
loadingDiv.style.display = 'none';
if (data.success && data.agenda) {
agendaText.textContent = data.agenda;
contentDiv.style.display = 'block';
} else {
errorDiv.textContent = 'No agenda available for this meeting';
errorDiv.style.display = 'block';
}
})
.catch(error => {
console.error('Error fetching agenda:', error);
loadingDiv.style.display = 'none';
errorDiv.textContent = error.message || 'Failed to fetch agenda';
errorDiv.style.display = 'block';
});
};
window.closeAgendaModal = function() {
const modal = document.getElementById('viewAgendaModal');
const errorDiv = document.getElementById('agendaError');
const loadingDiv = document.getElementById('agendaLoading');
const contentDiv = document.getElementById('meetingAgendaContent');
const agendaText = document.getElementById('viewMeetingAgendaText');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
contentDiv.style.display = 'none';
agendaText.textContent = '';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleAgendaEscapeKey);
};
window.handleAgendaEscapeKey = function(event) {
if (event.key === 'Escape') {
closeAgendaModal();
}
};
window.viewMeetingNotes = function(meetingId) {
const modal = document.getElementById('viewNotesModal');
const errorDiv = document.getElementById('notesError');
const loadingDiv = document.getElementById('notesLoading');
const contentDiv = document.getElementById('meetingNotesContent');
const notesText = document.getElementById('viewMeetingNotesText');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'block';
contentDiv.style.display = 'none';
notesText.textContent = '';
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleNotesEscapeKey);
// Fetch notes
fetch(`/app/api/meetings/${meetingId}/notes/`, {
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Response was not JSON");
}
return response.json();
})
.then(data => {
if (data.success) {
notesText.textContent = data.notes || 'No notes available';
loadingDiv.style.display = 'none';
contentDiv.style.display = 'block';
} else {
throw new Error(data.error || 'Failed to fetch notes');
}
})
.catch(error => {
console.error('Error:', error);
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
loadingDiv.style.display = 'none';
});
};
window.closeNotesModal = function() {
const modal = document.getElementById('viewNotesModal');
const errorDiv = document.getElementById('notesError');
const loadingDiv = document.getElementById('notesLoading');
const contentDiv = document.getElementById('meetingNotesContent');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
contentDiv.style.display = 'none';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleNotesEscapeKey);
};
window.handleNotesEscapeKey = function(event) {
if (event.key === 'Escape') {
closeNotesModal();
}
};
window.cancelMeeting = function(meetingId) {
const modal = document.getElementById('cancelMeetingModal');
const form = document.getElementById('cancelMeetingForm');
const errorDiv = document.getElementById('cancelError');
const loadingDiv = document.getElementById('cancelLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Set meeting ID
document.getElementById('cancelMeetingId').value = meetingId;
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleCancelEscapeKey);
};
window.closeCancelModal = function() {
const modal = document.getElementById('cancelMeetingModal');
const form = document.getElementById('cancelMeetingForm');
const errorDiv = document.getElementById('cancelError');
const loadingDiv = document.getElementById('cancelLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleCancelEscapeKey);
};
window.handleCancelEscapeKey = function(event) {
if (event.key === 'Escape') {
closeCancelModal();
}
};
window.submitCancelForm = function() {
const form = document.getElementById('cancelMeetingForm');
const errorDiv = document.getElementById('cancelError');
const loadingDiv = document.getElementById('cancelLoading');
const submitBtn = form.querySelector('button[type="button"]');
const reason = document.getElementById('cancellationReason');
// Validate form
if (!reason.value.trim()) {
reason.classList.add('is-invalid');
return;
}
// Show loading state
loadingDiv.style.display = 'block';
errorDiv.style.display = 'none';
submitBtn.disabled = true;
const meetingId = document.getElementById('cancelMeetingId').value;
fetch(`/app/api/meetings/${meetingId}/cancel/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({ reason: reason.value })
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Response was not JSON");
}
return response.json();
})
.then(data => {
if (data.success) {
closeCancelModal();
window.location.reload();
} else {
throw new Error(data.error || 'Failed to cancel meeting');
}
})
.catch(error => {
console.error('Error:', error);
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
})
.finally(() => {
loadingDiv.style.display = 'none';
submitBtn.disabled = false;
});
};
window.rescheduleMeeting = function(meetingId) {
const modal = document.getElementById('rescheduleMeetingModal');
const form = document.getElementById('rescheduleMeetingForm');
const errorDiv = document.getElementById('rescheduleError');
const loadingDiv = document.getElementById('rescheduleLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Set meeting ID and minimum date
document.getElementById('rescheduleMeetingId').value = meetingId;
const today = new Date().toISOString().split('T')[0];
document.getElementById('rescheduleDate').min = today;
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleRescheduleEscapeKey);
};
window.closeRescheduleModal = function() {
const modal = document.getElementById('rescheduleMeetingModal');
const form = document.getElementById('rescheduleMeetingForm');
const errorDiv = document.getElementById('rescheduleError');
const loadingDiv = document.getElementById('rescheduleLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleRescheduleEscapeKey);
};
window.handleRescheduleEscapeKey = function(event) {
if (event.key === 'Escape') {
closeRescheduleModal();
}
};
window.submitRescheduleForm = function() {
const form = document.getElementById('rescheduleMeetingForm');
const errorDiv = document.getElementById('rescheduleError');
const loadingDiv = document.getElementById('rescheduleLoading');
const submitBtn = form.querySelector('button[type="button"]');
const date = document.getElementById('rescheduleDate');
const time = document.getElementById('rescheduleTime');
// Validate form
let isValid = true;
if (!date.value) {
date.classList.add('is-invalid');
isValid = false;
}
if (!time.value) {
time.classList.add('is-invalid');
isValid = false;
}
if (!isValid) return;
// Show loading state
loadingDiv.style.display = 'block';
errorDiv.style.display = 'none';
submitBtn.disabled = true;
const meetingId = document.getElementById('rescheduleMeetingId').value;
fetch(`/app/api/meetings/${meetingId}/reschedule/`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify({
meeting_date: date.value,
meeting_time: time.value
})
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Response was not JSON");
}
return response.json();
})
.then(data => {
if (data.success) {
closeRescheduleModal();
window.location.reload();
} else {
throw new Error(data.error || 'Failed to reschedule meeting');
}
})
.catch(error => {
console.error('Error:', error);
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
})
.finally(() => {
loadingDiv.style.display = 'none';
submitBtn.disabled = false;
});
};
// Schedule Meeting Modal Functions
window.openScheduleMeetingModal = function() {
const modal = document.getElementById('scheduleMeetingModal');
const form = document.getElementById('scheduleMeetingForm');
const errorDiv = document.getElementById('scheduleMeetingError');
const loadingDiv = document.getElementById('scheduleMeetingLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Set minimum date to today
const today = new Date().toISOString().split('T')[0];
document.getElementById('meetingDate').min = today;
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleEscapeKey);
};
window.closeScheduleMeetingModal = function() {
const modal = document.getElementById('scheduleMeetingModal');
const form = document.getElementById('scheduleMeetingForm');
const errorDiv = document.getElementById('scheduleMeetingError');
const loadingDiv = document.getElementById('scheduleMeetingLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleEscapeKey);
};
// Function to handle Escape key press
window.handleEscapeKey = function(event) {
if (event.key === 'Escape') {
closeScheduleMeetingModal();
}
};
// Toggle meeting link field based on online meeting checkbox
document.addEventListener('DOMContentLoaded', function() {
const isOnlineCheckbox = document.getElementById('isOnline');
if (isOnlineCheckbox) {
isOnlineCheckbox.addEventListener('change', function() {
const linkContainer = document.getElementById('meetingLinkContainer');
const linkInput = document.getElementById('meetingLink');
if (this.checked) {
linkContainer.style.display = 'block';
linkInput.required = true;
} else {
linkContainer.style.display = 'none';
linkInput.required = false;
}
});
}
// Initialize all tooltips
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl);
});
// Initialize all popovers
var popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'));
var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
return new bootstrap.Popover(popoverTriggerEl);
});
// Update leave requests every 30 seconds
setInterval(updateLeaveRequests, 30000);
// Initial update
updateLeaveRequests();
});
// Function to validate form
window.validateMeetingForm = function() {
const form = document.getElementById('scheduleMeetingForm');
const date = document.getElementById('meetingDate');
const time = document.getElementById('meetingTime');
const duration = document.getElementById('meetingDuration');
const isOnline = document.getElementById('isOnline');
const link = document.getElementById('meetingLink');
let isValid = true;
// Reset validation states
form.classList.remove('was-validated');
// Validate date
if (!date.value) {
date.classList.add('is-invalid');
isValid = false;
} else {
date.classList.remove('is-invalid');
}
// Validate time
if (!time.value) {
time.classList.add('is-invalid');
isValid = false;
} else {
time.classList.remove('is-invalid');
}
// Validate duration
if (!duration.value || duration.value < 15 || duration.value > 120) {
duration.classList.add('is-invalid');
isValid = false;
} else {
duration.classList.remove('is-invalid');
}
// Validate meeting link if online meeting
if (isOnline.checked && !link.value) {
link.classList.add('is-invalid');
isValid = false;
} else {
link.classList.remove('is-invalid');
}
return isValid;
};
// Function to submit the meeting form
window.submitMeetingForm = function() {
if (!validateMeetingForm()) {
return;
}
const form = document.getElementById('scheduleMeetingForm');
const errorDiv = document.getElementById('scheduleMeetingError');
const loadingDiv = document.getElementById('scheduleMeetingLoading');
const submitBtn = form.querySelector('button[type="button"]');
// Show loading state
loadingDiv.style.display = 'block';
errorDiv.style.display = 'none';
submitBtn.disabled = true;
const formData = new FormData(form);
const data = {
meeting_date: formData.get('meeting_date'),
meeting_time: formData.get('meeting_time'),
duration: parseInt(formData.get('duration')),
is_online: document.getElementById('isOnline').checked,
meeting_link: formData.get('meeting_link'),
agenda: document.getElementById('scheduleMeetingAgenda').value
};
fetch('/app/api/meetings/add/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify(data)
})
.then(response => {
if (!response.ok) {
return response.json().then(data => {
throw new Error(data.error || 'Failed to schedule meeting');
});
}
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
throw new TypeError("Response was not JSON");
}
return response.json();
})
.then(data => {
if (data.success) {
closeScheduleMeetingModal();
// Show success message
const successDiv = document.createElement('div');
successDiv.className = 'alert alert-success alert-dismissible fade show';
successDiv.innerHTML = `
<strong>Success!</strong> Meeting scheduled successfully.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
`;
document.querySelector('.content-card').insertAdjacentElement('afterbegin', successDiv);
// Reload after a short delay
setTimeout(() => {
window.location.reload();
}, 1500);
} else {
throw new Error(data.error || 'Failed to schedule meeting');
}
})
.catch(error => {
console.error('Error scheduling meeting:', error);
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
})
.finally(() => {
loadingDiv.style.display = 'none';
submitBtn.disabled = false;
});
};
window.completeMeeting = function(meetingId) {
const modal = document.getElementById('completeMeetingModal');
const form = document.getElementById('completeMeetingForm');
const errorDiv = document.getElementById('completeError');
const loadingDiv = document.getElementById('completeLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Set meeting ID
document.getElementById('completeMeetingId').value = meetingId;
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleCompleteEscapeKey);
};
window.closeCompleteModal = function() {
const modal = document.getElementById('completeMeetingModal');
const form = document.getElementById('completeMeetingForm');
const errorDiv = document.getElementById('completeError');
const loadingDiv = document.getElementById('completeLoading');
// Reset form and error states
form.reset();
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleCompleteEscapeKey);
};
window.handleCompleteEscapeKey = function(event) {
if (event.key === 'Escape') {
closeCompleteModal();
}
};
window.viewCancellationReason = function(meetingId) {
const modal = document.getElementById('viewReasonModal');
const errorDiv = document.getElementById('reasonError');
const loadingDiv = document.getElementById('reasonLoading');
const contentDiv = document.getElementById('meetingReasonContent');
const reasonText = document.getElementById('viewMeetingReasonText');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'block';
contentDiv.style.display = 'none';
reasonText.textContent = '';
// Show modal
modal.style.display = 'block';
document.body.style.overflow = 'hidden';
// Add keyboard event listener for Escape key
document.addEventListener('keydown', handleReasonEscapeKey);
// Fetch cancellation reason
fetch(`/app/api/meetings/${meetingId}/cancellation-reason/`, {
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if (data.success && data.reason) {
reasonText.textContent = data.reason;
loadingDiv.style.display = 'none';
contentDiv.style.display = 'block';
} else {
throw new Error(data.error || 'No cancellation reason available');
}
})
.catch(error => {
console.error('Error:', error);
errorDiv.textContent = error.message;
errorDiv.style.display = 'block';
loadingDiv.style.display = 'none';
});
};
window.closeReasonModal = function() {
const modal = document.getElementById('viewReasonModal');
const errorDiv = document.getElementById('reasonError');
const loadingDiv = document.getElementById('reasonLoading');
const contentDiv = document.getElementById('meetingReasonContent');
const reasonText = document.getElementById('viewMeetingReasonText');
// Reset states
errorDiv.style.display = 'none';
loadingDiv.style.display = 'none';
contentDiv.style.display = 'none';
reasonText.textContent = '';
// Hide modal
modal.style.display = 'none';
document.body.style.overflow = '';
// Remove keyboard event listener
document.removeEventListener('keydown', handleReasonEscapeKey);
};
window.handleReasonEscapeKey = function(event) {
if (event.key === 'Escape') {
closeReasonModal();
}
};
// Notice Modal Functions
window.openAddNoticeModal = function() {
document.getElementById('addNoticeModal').style.display = 'block';
document.addEventListener('keydown', handleNoticeEscapeKey);
}
window.closeAddNoticeModal = function() {
document.getElementById('addNoticeModal').style.display = 'none';
document.removeEventListener('keydown', handleNoticeEscapeKey);
// Reset form
document.getElementById('addNoticeForm').reset();
// Hide error and loading states
document.getElementById('addNoticeError').style.display = 'none';
document.getElementById('addNoticeLoading').style.display = 'none';
}
window.handleNoticeEscapeKey = function(event) {
if (event.key === 'Escape') {
closeAddNoticeModal();
}
}
window.submitNoticeForm = function() {
const form = document.getElementById('addNoticeForm');
const formData = new FormData(form);
// Show loading state
document.getElementById('addNoticeLoading').style.display = 'block';
document.getElementById('addNoticeError').style.display = 'none';
fetch('/app/add-notice/', {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Close modal and refresh page to show new notice
closeAddNoticeModal();
window.location.reload();
} else {
// Show error message
document.getElementById('addNoticeError').textContent = data.error || 'Failed to add notice';
document.getElementById('addNoticeError').style.display = 'block';
}
})
.catch(error => {
document.getElementById('addNoticeError').textContent = 'An error occurred while adding the notice';
document.getElementById('addNoticeError').style.display = 'block';
})
.finally(() => {
document.getElementById('addNoticeLoading').style.display = 'none';
});
}