367 lines
15 KiB
HTML
367 lines
15 KiB
HTML
{% load static %}
|
|
|
|
<!-- Add Routine Modal -->
|
|
<div id="addRoutineModal" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); z-index: 10000;" onclick="if(event.target === this) closeAddRoutineModal();">
|
|
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background: white; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
<div style="background-color: #6366f1; color: white; padding: 1rem 1.5rem; border-top-left-radius: 8px; border-top-right-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
|
|
<h5 style="margin: 0; font-size: 1.125rem; font-weight: 500;">Add Class Routine</h5>
|
|
<button style="background: none; border: none; color: white; font-size: 1.5rem; cursor: pointer; line-height: 1; padding: 0.25rem;" onclick="closeAddRoutineModal()">×</button>
|
|
</div>
|
|
<form id="addRoutineForm">
|
|
{% csrf_token %}
|
|
<div style="padding: 1.5rem;">
|
|
<div style="margin-bottom: 1.5rem;">
|
|
<label for="periodSelect" style="display: block; margin-bottom: 0.5rem; font-weight: 500; color: #374151;">{% if course.duration_type == 'Semester' %}Semester{% else %}Year{% endif %}</label>
|
|
<select id="periodSelect" name="period_select" style="width: 100%; padding: 0.625rem; border: 1px solid #d1d5db; border-radius: 6px; background-color: white; font-size: 0.875rem;" required>
|
|
<option value="">Select {% if course.duration_type == 'Semester' %}Semester{% else %}Year{% endif %}</option>
|
|
<!-- Options will be populated dynamically via JavaScript -->
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Subject list container - subjects will be added here dynamically -->
|
|
<div id="subjectsContainer" style="margin-bottom: 1.5rem; max-height: 400px; overflow-y: auto;"></div>
|
|
|
|
<input type="hidden" id="periodOrYear" name="period_or_year">
|
|
</div>
|
|
<div style="padding: 1rem 1.5rem; border-top: 1px solid #e5e7eb; background-color: #f9fafb; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; display: flex; justify-content: flex-end; gap: 0.75rem;">
|
|
<button type="button" style="padding: 0.5rem 1rem; border: 1px solid #d1d5db; background-color: white; color: #374151; border-radius: 6px; font-size: 0.875rem; font-weight: 500;" onclick="closeAddRoutineModal()">Cancel</button>
|
|
<button type="button" style="padding: 0.5rem 1rem; background-color: #6366f1; color: white; border: none; border-radius: 6px; font-size: 0.875rem; font-weight: 500;" onclick="submitAddRoutineForm()">Save</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Store all subject data for use in the form
|
|
const allSubjects = [
|
|
{% for subject in subjects %}
|
|
{
|
|
id: {{ subject.id }},
|
|
name: "{{ subject.name }}",
|
|
period: "{{ subject.period_or_year }}"
|
|
},
|
|
{% endfor %}
|
|
];
|
|
|
|
function openAddRoutineModal() {
|
|
const modal = document.getElementById('addRoutineModal');
|
|
if (modal) {
|
|
// Reset form
|
|
document.getElementById('addRoutineForm').reset();
|
|
document.getElementById('subjectsContainer').innerHTML = '';
|
|
|
|
// Populate period dropdown dynamically
|
|
const periodSelect = document.getElementById('periodSelect');
|
|
const periodLabel = {% if course.duration_type == 'Semester' %}'Semester'{% else %}'Year'{% endif %};
|
|
|
|
// Try to get the course data from the page
|
|
const courseElement = document.querySelector('#routineSection');
|
|
const courseId = courseElement?.getAttribute('data-course-id') ||
|
|
window.location.pathname.match(/\/hod\/(\d+)/)?.at(1);
|
|
|
|
// Default to 3 periods if we can't determine
|
|
let totalPeriods = 3;
|
|
|
|
{% if course.total_periods %}
|
|
totalPeriods = {{ course.total_periods }};
|
|
{% endif %}
|
|
|
|
// Clear all options
|
|
periodSelect.innerHTML = '';
|
|
|
|
// Add placeholder option
|
|
periodSelect.innerHTML = `<option value="">Select ${periodLabel}</option>`;
|
|
|
|
// Add options based on total periods
|
|
for (let i = 1; i <= totalPeriods; i++) {
|
|
periodSelect.innerHTML += `<option value="${i}">${periodLabel} ${i}</option>`;
|
|
}
|
|
|
|
// Setup period selection change listener
|
|
periodSelect.onchange = function() {
|
|
const selectedPeriod = this.value;
|
|
document.getElementById('periodOrYear').value = selectedPeriod;
|
|
|
|
// Clear existing subjects
|
|
const subjectsContainer = document.getElementById('subjectsContainer');
|
|
subjectsContainer.innerHTML = '';
|
|
|
|
if (selectedPeriod) {
|
|
// Filter subjects for the selected period
|
|
const periodSubjects = allSubjects.filter(subject => subject.period === selectedPeriod);
|
|
|
|
if (periodSubjects.length === 0) {
|
|
subjectsContainer.innerHTML = '<p style="text-align: center; padding: 1rem; color: #6b7280;">No subjects found for this period.</p>';
|
|
return;
|
|
}
|
|
|
|
// Create a form section for each subject
|
|
periodSubjects.forEach(subject => {
|
|
const subjectDiv = document.createElement('div');
|
|
subjectDiv.className = 'subject-item';
|
|
subjectDiv.style.padding = '1rem';
|
|
subjectDiv.style.marginBottom = '1rem';
|
|
subjectDiv.style.border = '1px solid #e5e7eb';
|
|
subjectDiv.style.borderRadius = '6px';
|
|
subjectDiv.style.backgroundColor = 'white';
|
|
|
|
// Create subject header
|
|
const subjectHeader = document.createElement('h4');
|
|
subjectHeader.textContent = subject.name;
|
|
subjectHeader.style.margin = '0 0 1rem 0';
|
|
subjectHeader.style.fontSize = '0.875rem';
|
|
subjectHeader.style.fontWeight = '600';
|
|
subjectHeader.style.color = '#374151';
|
|
subjectDiv.appendChild(subjectHeader);
|
|
|
|
// Add hidden input for subject ID
|
|
const subjectIdInput = document.createElement('input');
|
|
subjectIdInput.type = 'hidden';
|
|
subjectIdInput.name = `subject_id_${subject.id}`;
|
|
subjectIdInput.value = subject.id;
|
|
subjectDiv.appendChild(subjectIdInput);
|
|
|
|
// Create form grid
|
|
const formGrid = document.createElement('div');
|
|
formGrid.style.display = 'grid';
|
|
formGrid.style.gridTemplateColumns = 'repeat(auto-fit, minmax(150px, 1fr))';
|
|
formGrid.style.gap = '1rem';
|
|
formGrid.style.alignItems = 'end';
|
|
|
|
// Create teacher dropdown
|
|
const teacherDiv = document.createElement('div');
|
|
|
|
const teacherLabel = document.createElement('label');
|
|
teacherLabel.textContent = 'Teacher';
|
|
teacherLabel.style.display = 'block';
|
|
teacherLabel.style.marginBottom = '0.5rem';
|
|
teacherLabel.style.fontSize = '0.875rem';
|
|
teacherLabel.style.fontWeight = '500';
|
|
teacherLabel.style.color = '#374151';
|
|
teacherDiv.appendChild(teacherLabel);
|
|
|
|
const teacherSelect = document.createElement('select');
|
|
teacherSelect.name = `teacher_id_${subject.id}`;
|
|
teacherSelect.style.width = '100%';
|
|
teacherSelect.style.padding = '0.625rem';
|
|
teacherSelect.style.border = '1px solid #d1d5db';
|
|
teacherSelect.style.borderRadius = '6px';
|
|
teacherSelect.style.backgroundColor = 'white';
|
|
teacherSelect.style.fontSize = '0.875rem';
|
|
teacherSelect.required = true;
|
|
|
|
// Add default option
|
|
const defaultOption = document.createElement('option');
|
|
defaultOption.value = '';
|
|
defaultOption.textContent = 'Select Teacher';
|
|
teacherSelect.appendChild(defaultOption);
|
|
|
|
// Add teacher options
|
|
{% for teacher in staff %}
|
|
const teacherOption_{{ teacher.id }} = document.createElement('option');
|
|
teacherOption_{{ teacher.id }}.value = '{{ teacher.id }}';
|
|
teacherOption_{{ teacher.id }}.textContent = '{{ teacher.name }}';
|
|
teacherSelect.appendChild(teacherOption_{{ teacher.id }});
|
|
{% endfor %}
|
|
|
|
teacherDiv.appendChild(teacherSelect);
|
|
formGrid.appendChild(teacherDiv);
|
|
|
|
// Start time
|
|
const startTimeDiv = document.createElement('div');
|
|
|
|
const startTimeLabel = document.createElement('label');
|
|
startTimeLabel.textContent = 'Start Time';
|
|
startTimeLabel.style.display = 'block';
|
|
startTimeLabel.style.marginBottom = '0.5rem';
|
|
startTimeLabel.style.fontSize = '0.875rem';
|
|
startTimeLabel.style.fontWeight = '500';
|
|
startTimeLabel.style.color = '#374151';
|
|
startTimeDiv.appendChild(startTimeLabel);
|
|
|
|
const startTimeInput = document.createElement('input');
|
|
startTimeInput.type = 'time';
|
|
startTimeInput.name = `start_time_${subject.id}`;
|
|
startTimeInput.style.width = '100%';
|
|
startTimeInput.style.padding = '0.625rem';
|
|
startTimeInput.style.border = '1px solid #d1d5db';
|
|
startTimeInput.style.borderRadius = '6px';
|
|
startTimeInput.style.backgroundColor = 'white';
|
|
startTimeInput.style.fontSize = '0.875rem';
|
|
startTimeInput.required = true;
|
|
startTimeDiv.appendChild(startTimeInput);
|
|
|
|
formGrid.appendChild(startTimeDiv);
|
|
|
|
// End time
|
|
const endTimeDiv = document.createElement('div');
|
|
|
|
const endTimeLabel = document.createElement('label');
|
|
endTimeLabel.textContent = 'End Time';
|
|
endTimeLabel.style.display = 'block';
|
|
endTimeLabel.style.marginBottom = '0.5rem';
|
|
endTimeLabel.style.fontSize = '0.875rem';
|
|
endTimeLabel.style.fontWeight = '500';
|
|
endTimeLabel.style.color = '#374151';
|
|
endTimeDiv.appendChild(endTimeLabel);
|
|
|
|
const endTimeInput = document.createElement('input');
|
|
endTimeInput.type = 'time';
|
|
endTimeInput.name = `end_time_${subject.id}`;
|
|
endTimeInput.style.width = '100%';
|
|
endTimeInput.style.padding = '0.625rem';
|
|
endTimeInput.style.border = '1px solid #d1d5db';
|
|
endTimeInput.style.borderRadius = '6px';
|
|
endTimeInput.style.backgroundColor = 'white';
|
|
endTimeInput.style.fontSize = '0.875rem';
|
|
endTimeInput.required = true;
|
|
endTimeDiv.appendChild(endTimeInput);
|
|
|
|
formGrid.appendChild(endTimeDiv);
|
|
|
|
// Add the form grid to the subject div
|
|
subjectDiv.appendChild(formGrid);
|
|
|
|
// Add the subject div to the container
|
|
subjectsContainer.appendChild(subjectDiv);
|
|
});
|
|
}
|
|
};
|
|
|
|
// Show modal
|
|
modal.style.display = 'block';
|
|
document.body.style.overflow = 'hidden';
|
|
}
|
|
}
|
|
|
|
function closeAddRoutineModal() {
|
|
const modal = document.getElementById('addRoutineModal');
|
|
if (modal) {
|
|
modal.style.display = 'none';
|
|
document.body.style.overflow = '';
|
|
}
|
|
}
|
|
|
|
// Make functions available globally
|
|
if (typeof window !== 'undefined') {
|
|
window.openAddRoutineModal = openAddRoutineModal;
|
|
window.closeAddRoutineModal = closeAddRoutineModal;
|
|
}
|
|
|
|
// Add form submission function
|
|
function submitAddRoutineForm() {
|
|
const form = document.getElementById('addRoutineForm');
|
|
if (!form) {
|
|
console.error('Add routine form not found');
|
|
return;
|
|
}
|
|
|
|
// Get selected period
|
|
const periodSelect = document.getElementById('periodSelect');
|
|
const selectedPeriod = periodSelect.value;
|
|
|
|
if (!selectedPeriod) {
|
|
alert('Please select a period');
|
|
return;
|
|
}
|
|
|
|
// Get selected subjects
|
|
const subjectItems = document.querySelectorAll('.subject-item');
|
|
if (subjectItems.length === 0) {
|
|
alert('No subjects available for this period');
|
|
return;
|
|
}
|
|
|
|
// Check if any item has incomplete data
|
|
let hasIncompleteData = false;
|
|
subjectItems.forEach(item => {
|
|
const teacherSelect = item.querySelector('select');
|
|
const startTime = item.querySelector('input[type="time"][name^="start_time_"]');
|
|
const endTime = item.querySelector('input[type="time"][name^="end_time_"]');
|
|
|
|
if (!teacherSelect.value || !startTime.value || !endTime.value) {
|
|
hasIncompleteData = true;
|
|
}
|
|
});
|
|
|
|
if (hasIncompleteData) {
|
|
alert('Please fill in all required fields for each subject');
|
|
return;
|
|
}
|
|
|
|
// Prepare requests to be sent
|
|
const requests = [];
|
|
|
|
// Common data
|
|
const courseId = document.querySelector('#routineSection')?.getAttribute('data-course-id') ||
|
|
window.location.pathname.match(/\/hod\/(\d+)/)?.at(1);
|
|
|
|
if (!courseId) {
|
|
alert('Course ID not found');
|
|
return;
|
|
}
|
|
|
|
// Create a request for each subject
|
|
subjectItems.forEach(item => {
|
|
const subjectId = item.querySelector('input[type="hidden"]').value;
|
|
const teacherId = item.querySelector('select').value;
|
|
const startTime = item.querySelector('input[name^="start_time_"]').value;
|
|
const endTime = item.querySelector('input[name^="end_time_"]').value;
|
|
|
|
const formData = new FormData();
|
|
formData.append('course_id', courseId);
|
|
formData.append('subject_id', subjectId);
|
|
formData.append('teacher_id', teacherId);
|
|
formData.append('start_time', startTime);
|
|
formData.append('end_time', endTime);
|
|
formData.append('period_or_year', selectedPeriod);
|
|
|
|
requests.push(
|
|
fetch('/app/api/hod/routines/', {
|
|
method: 'POST',
|
|
body: formData,
|
|
headers: {
|
|
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
|
|
}
|
|
})
|
|
);
|
|
});
|
|
|
|
// Send all requests and handle responses
|
|
Promise.all(requests.map(p => p.catch(e => e)))
|
|
.then(responses => {
|
|
const allSuccessful = responses.every(res => !(res instanceof Error) && res.ok);
|
|
|
|
if (allSuccessful) {
|
|
if (typeof window.showMessageModal === 'function') {
|
|
window.showMessageModal('Success', 'All routines added successfully');
|
|
} else if (typeof window.showToast === 'function') {
|
|
window.showToast('success', 'All routines added successfully');
|
|
} else {
|
|
alert('All routines added successfully');
|
|
}
|
|
closeAddRoutineModal();
|
|
setTimeout(() => {
|
|
window.location.reload();
|
|
}, 1000);
|
|
} else {
|
|
if (typeof window.showMessageModal === 'function') {
|
|
window.showMessageModal('Error', 'Some routines could not be added');
|
|
} else if (typeof window.showToast === 'function') {
|
|
window.showToast('error', 'Some routines could not be added');
|
|
} else {
|
|
alert('Some routines could not be added');
|
|
}
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error adding routines:', error);
|
|
alert('Failed to add routines: ' + error.message);
|
|
});
|
|
}
|
|
|
|
// Make submission function globally available
|
|
if (typeof window !== 'undefined') {
|
|
window.submitAddRoutineForm = submitAddRoutineForm;
|
|
}
|
|
</script> |