Files
Student-Management-System-I…/templates/admin/dashboard.html
T
2025-04-22 16:31:37 +05:45

1596 lines
69 KiB
HTML

{% extends "admin/base_site.html" %}
{% load static %}
{% load app_filters %}
{% block extrahead %}
{{ block.super }}
<meta name="csrf-token" content="{{ csrf_token }}">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, user-scalable=yes">
<!-- Font Awesome -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet" />
<!-- JavaScript Dependencies -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" defer></script>
<!-- Firebase SDK -->
<script src="https://www.gstatic.com/firebasejs/9.22.0/firebase-app-compat.js"></script>
<script src="https://www.gstatic.com/firebasejs/9.22.0/firebase-messaging-compat.js"></script>
<!-- Firebase Configuration -->
<script src="{% static 'js/firebase-config.js' %}"></script>
<!-- Firebase Initialization -->
<script src="{% static 'js/firebase-init.js' %}"></script>
<!-- Admin Dashboard JS -->
<script src="{% static 'js/admin_dashboard.js' %}" defer></script>
<script>
// Initialize Firebase and request notification permission when the page loads
document.addEventListener('DOMContentLoaded', function() {
// Call getDeviceToken to initialize Firebase and request notification permission
if (typeof getDeviceToken === 'function') {
getDeviceToken().catch(error => {
console.error('Error initializing Firebase:', error);
});
}
});
// Add CSRF token to all AJAX requests
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
// Set up CSRF token for AJAX requests
const csrftoken = getCookie('csrftoken');
// Add CSRF token to all AJAX requests
$(document).ready(function() {
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
});
// Update all form submissions to include CSRF token
document.addEventListener('DOMContentLoaded', function() {
// Add CSRF token to fetch requests
window.fetch = new Proxy(window.fetch, {
apply: function(fetch, that, args) {
if (args.length > 0 && typeof args[0] === 'object' && args[0].method !== 'GET') {
if (args[0].headers) {
args[0].headers['X-CSRFToken'] = csrftoken;
} else {
args[0].headers = { 'X-CSRFToken': csrftoken };
}
}
return fetch.apply(that, args);
}
});
});
</script>
{% endblock %}
{% block extrastyle %}
{{ block.super }}
<style>
:root {
--primary: #0D6EFD;
--primary-light: #E7F1FF;
--primary-dark: #0B5ED7;
--secondary: #6C757D;
--success: #198754;
--info: #0DCAF0;
--warning: #FFC107;
--danger: #DC3545;
--light: #F8F9FA;
--dark: #212529;
--gray: #6C757D;
--card-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--card-hover-shadow: 0 8px 15px rgba(0, 0, 0, 0.15);
--transition: all 0.3s ease;
}
body {
background-color: #f5f7fa;
color: var(--dark);
}
.content-card {
background: white;
border-radius: 12px;
box-shadow: var(--card-shadow);
padding: 24px;
margin-bottom: 24px;
transition: var(--transition);
border: none;
}
.content-card:hover {
box-shadow: var(--card-hover-shadow);
transform: translateY(-2px);
}
.welcome-section {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
color: white;
padding: 32px;
border-radius: 12px;
margin-bottom: 32px;
box-shadow: var(--card-shadow);
}
.summary-card {
background: white;
border-radius: 12px;
box-shadow: var(--card-shadow);
transition: var(--transition);
border: none;
height: 100%;
}
.summary-card:hover {
transform: translateY(-4px);
box-shadow: var(--card-hover-shadow);
}
.summary-card .card-header {
background: none;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding: 16px;
border-radius: 12px 12px 0 0;
}
.summary-card .card-body {
padding: 24px;
}
.stat-number {
font-size: 2.5rem;
font-weight: 700;
color: var(--primary);
margin-bottom: 8px;
}
.stat-label {
color: var(--secondary);
font-size: 0.9rem;
font-weight: 500;
}
.status-badge {
padding: 4px 10px;
border-radius: 16px;
font-size: 0.8125rem;
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 4px;
line-height: 1.4;
}
.status-badge:hover {
transform: scale(1.05);
}
.btn {
border-radius: 6px;
padding: 6px 12px;
font-size: 0.875rem;
font-weight: 500;
transition: var(--transition);
border: none;
display: inline-flex;
align-items: center;
gap: 6px;
line-height: 1.5;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.btn i {
font-size: 0.875rem;
}
.btn:hover {
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.btn-sm {
padding: 4px 8px;
font-size: 0.8125rem;
}
.btn-sm i {
font-size: 0.8125rem;
}
.btn-schedule {
background-color: var(--primary);
color: white;
padding: 8px 16px;
}
.btn-schedule:hover {
background-color: var(--primary-dark);
color: white;
}
.btn-action {
padding: 4px 8px;
font-size: 0.8125rem;
margin: 0 2px;
}
.badge.bg-info {
background-color: #0DCAF0 !important;
color: white;
}
.badge.bg-success {
background-color: #198754 !important;
color: white;
}
.badge.bg-warning {
background-color: #FFC107 !important;
color: #000;
}
.badge.bg-danger {
background-color: #DC3545 !important;
color: white;
}
.badge.bg-secondary {
background-color: #6C757D !important;
color: white;
}
.meeting-type {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
border-radius: 16px;
font-size: 0.8125rem;
background-color: #ECEFF1;
color: #455A64;
}
.meeting-type.online {
background-color: #0DCAF0;
color: white;
}
.meeting-type i {
font-size: 0.8125rem;
}
.action-buttons {
display: flex;
gap: 4px;
flex-wrap: wrap;
}
.meeting-link {
color: var(--primary);
text-decoration: none;
display: inline-flex;
align-items: center;
gap: 4px;
}
.meeting-link:hover {
text-decoration: underline;
}
.table td {
padding: 12px;
vertical-align: middle;
}
.table th {
padding: 12px;
font-weight: 600;
color: #455A64;
background-color: #F5F7FA;
}
@media (max-width: 1200px) {
.welcome-section {
padding: 28px;
}
.content-card {
padding: 20px;
}
.stat-number {
font-size: 2.2rem;
}
}
@media (max-width: 992px) {
.welcome-section {
padding: 24px;
}
.content-card {
padding: 16px;
}
}
@media (max-width: 768px) {
.welcome-section {
padding: 20px;
margin-bottom: 24px;
}
.welcome-section h2 {
font-size: 1.5rem;
}
.summary-card .card-body {
padding: 16px;
}
.stat-number {
font-size: 2rem;
}
.action-buttons {
flex-direction: column;
gap: 6px;
}
.btn-action {
width: 100%;
}
}
@media (max-width: 576px) {
.welcome-section {
padding: 16px;
margin-bottom: 20px;
}
.welcome-section h2 {
font-size: 1.3rem;
}
.content-card {
padding: 12px;
}
.stat-number {
font-size: 1.8rem;
}
}
@media (hover: none) {
.summary-card:hover,
.content-card:hover,
.btn:hover {
transform: none;
}
}
@media (prefers-contrast: high) {
.summary-card,
.content-card {
border: 2px solid currentColor;
}
}
@media (prefers-reduced-motion: reduce) {
.summary-card,
.content-card,
.btn,
.status-badge,
.rating-stars i {
transition: none;
}
}
/* Meeting Section Scroll */
.meetings-container {
max-height: 400px;
overflow-y: auto;
margin: -12px;
padding: 12px;
}
.meetings-table {
position: relative;
margin-bottom: 0;
}
.meetings-table thead {
position: sticky;
top: 0;
background-color: white;
z-index: 1;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
/* Bright Button Colors */
.btn-primary {
background-color: #0D6EFD;
border-color: #0D6EFD;
color: white;
}
.btn-success {
background-color: #198754;
border-color: #198754;
color: white;
}
.btn-info {
background-color: #0DCAF0;
border-color: #0DCAF0;
color: white;
}
.btn-warning {
background-color: #FFC107;
border-color: #FFC107;
color: #000;
}
.btn-danger {
background-color: #DC3545;
border-color: #DC3545;
color: white;
}
.btn-secondary {
background-color: #6C757D;
border-color: #6C757D;
color: white;
}
/* Button Hover States */
.btn-primary:hover {
background-color: #0B5ED7;
border-color: #0A58CA;
}
.btn-success:hover {
background-color: #157347;
border-color: #146C43;
}
.btn-info:hover {
background-color: #31D2F2;
border-color: #25CFF2;
}
.btn-warning:hover {
background-color: #FFCA2C;
border-color: #FFC720;
}
.btn-danger:hover {
background-color: #BB2D3B;
border-color: #B02A37;
}
.btn-secondary:hover {
background-color: #5C636A;
border-color: #565E64;
}
/* Meeting Type Badge */
.meeting-type.online {
background-color: #0DCAF0;
color: white;
}
.meeting-type.in-person {
background-color: #6C757D;
color: white;
}
/* Status Badges */
.status-badge.completed {
background-color: #198754;
color: white;
}
.status-badge.cancelled {
background-color: #DC3545;
color: white;
}
.status-badge.rescheduled {
background-color: #FFC107;
color: #000;
}
/* Scrollbar Styling */
.meetings-container::-webkit-scrollbar {
width: 6px;
}
.meetings-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.meetings-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 3px;
}
.meetings-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
/* Scrollable Container Styles */
.scroll-container {
max-height: 400px;
overflow-y: auto;
margin: -12px;
padding: 12px;
position: relative;
}
.scroll-container::-webkit-scrollbar {
width: 6px;
}
.scroll-container::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 3px;
}
.scroll-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 3px;
}
.scroll-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
/* Card Heights */
.stats-card {
height: 300px;
display: flex;
flex-direction: column;
}
.stats-card .card-header {
flex-shrink: 0;
}
.stats-card .card-body {
flex-grow: 1;
overflow-y: auto;
padding: 1rem;
}
.content-card {
height: 100%;
display: flex;
flex-direction: column;
}
.content-card .card-header {
flex-shrink: 0;
padding: 1rem;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.content-card .card-body {
flex-grow: 1;
overflow-y: auto;
padding: 1rem;
}
/* Table Header Sticky */
.sticky-header {
position: sticky;
top: 0;
background-color: white;
z-index: 1;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
/* Meeting Action Buttons */
.meeting-actions {
display: flex;
gap: 4px;
flex-wrap: wrap;
align-items: center;
}
.btn-action {
padding: 4px 8px;
font-size: 0.75rem;
border-radius: 4px;
display: inline-flex;
align-items: center;
gap: 4px;
font-weight: 500;
min-width: 28px;
justify-content: center;
border: none;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
}
.btn-action:hover {
transform: translateY(-1px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
}
.btn-action i {
font-size: 0.75rem;
}
.btn-action.btn-complete {
background-color: #198754;
color: white;
}
.btn-action.btn-reschedule {
background-color: #FFC107;
color: #000;
}
.btn-action.btn-cancel {
background-color: #DC3545;
color: white;
}
.btn-action.btn-notes {
background-color: #0DCAF0;
color: white;
}
.btn-action.btn-agenda {
background-color: #0D6EFD;
color: white;
}
.btn-action.btn-reason {
background-color: #6C757D;
color: white;
}
/* Meeting Status Badges */
.meeting-status {
padding: 4px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 4px;
min-width: 80px;
justify-content: center;
}
.meeting-status i {
font-size: 0.75rem;
}
.meeting-status.scheduled {
background-color: #E7F1FF;
color: #0D6EFD;
}
.meeting-status.completed {
background-color: #E8F5E9;
color: #198754;
}
.meeting-status.cancelled {
background-color: #FFEBEE;
color: #DC3545;
}
.meeting-status.rescheduled {
background-color: #FFF3E0;
color: #F57C00;
}
/* Meeting Type Badge */
.meeting-type {
padding: 4px 8px;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 500;
display: inline-flex;
align-items: center;
gap: 4px;
min-width: 80px;
justify-content: center;
}
.meeting-type.online {
background-color: #E1F5FE;
color: #0277BD;
}
.meeting-type.in-person {
background-color: #ECEFF1;
color: #455A64;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.meeting-actions {
flex-direction: row;
justify-content: flex-start;
margin-top: 8px;
}
}
</style>
{% endblock %}
{% block branding %}
<h1 id="site-name">
<a href="{% url 'admin:index' %}">
<img src="{% static site_logo %}" alt="{{ site_header }}" class="brand-image" style="height: 30px;">
{{ site_header }}
</a>
</h1>
{% endblock %}
{% block content %}
<div class="container-fluid py-4">
<!-- Welcome Section -->
<div class="row mb-4">
<div class="col-12">
<div class="content-card welcome-section">
<div class="d-flex justify-content-between align-items-center flex-wrap">
<div class="flex-grow-1">
<h2 class="mb-1">Welcome, Admin!</h2>
<p class="mb-0">Student Management Dashboard</p>
</div>
</div>
</div>
</div>
</div>
<!-- Quick Stats Row -->
<div class="row mb-4">
<!-- Student Stats -->
<div class="col-xl-3 col-md-6 mb-3">
<div class="summary-card stats-card">
<div class="card-header">
<h5 class="card-title mb-0 small"><i class="fas fa-users text-primary me-2"></i>Students</h5>
</div>
<div class="card-body scroll-container">
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="d-block text-muted small">Total Students</span>
<h3>{{ total_students }}</h3>
</div>
<div class="text-end">
<span class="d-block text-muted small">Active</span>
<h4 class="text-success">{{ active_students }}</h4>
</div>
</div>
<div class="mt-3">
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Male Students</small>
<span class="badge bg-info p-2">{{ male_students }}</span>
</div>
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Female Students</small>
<span class="badge bg-warning p-2">{{ female_students }}</span>
</div>
<div class="d-flex justify-content-between">
<small class="mb-0">Inactive</small>
<span class="badge bg-danger p-2">{{ inactive_students }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Staff Stats -->
<div class="col-xl-3 col-md-6 mb-3">
<div class="summary-card stats-card">
<div class="card-header">
<h5 class="card-title mb-0 small"><i class="fas fa-chalkboard-teacher text-info me-2"></i>Staff</h5>
</div>
<div class="card-body scroll-container">
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="d-block text-muted small">Total Staff</span>
<h3>{{ total_staff }}</h3>
</div>
<div class="text-end">
<span class="d-block text-muted small">Active</span>
<h4 class="text-success">{{ active_staff }}</h4>
</div>
</div>
<div class="mt-3">
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Teachers</small>
<span class="badge bg-info p-2">{{ total_teachers }}</span>
</div>
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Non-Teaching</small>
<span class="badge bg-warning p-2">{{ non_teaching_staff }}</span>
</div>
<div class="d-flex justify-content-between">
<small class="mb-0">Inactive</small>
<span class="badge bg-danger p-2">{{ inactive_staff }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Parent Stats -->
<div class="col-xl-3 col-md-6 mb-3">
<div class="summary-card stats-card">
<div class="card-header">
<h5 class="card-title mb-0 small"><i class="fas fa-user-friends text-warning me-2"></i>Parents</h5>
</div>
<div class="card-body scroll-container">
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="d-block text-muted small">Total Parents</span>
<h3>{{ total_parents }}</h3>
</div>
<div class="text-end">
<span class="d-block text-muted small">Active</span>
<h4 class="text-success">{{ active_parents }}</h4>
</div>
</div>
<div class="mt-3">
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Parents with Students</small>
<span class="badge bg-info p-2">{{ parents_with_students }}</span>
</div>
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Parents with Multiple Students</small>
<span class="badge bg-warning p-2">{{ parents_with_multiple_students }}</span>
</div>
<div class="d-flex justify-content-between">
<small class="mb-0">Inactive</small>
<span class="badge bg-danger p-2">{{ inactive_parents }}</span>
</div>
</div>
</div>
</div>
</div>
<!-- Course Stats -->
<div class="col-xl-3 col-md-6 mb-3">
<div class="summary-card stats-card">
<div class="card-header">
<h5 class="card-title mb-0 small"><i class="fas fa-book text-success me-2"></i>Courses</h5>
</div>
<div class="card-body scroll-container">
<div class="d-flex justify-content-between align-items-center">
<div>
<span class="d-block text-muted small">Total Courses</span>
<h3>{{ total_courses }}</h3>
</div>
<div class="text-end">
<span class="d-block text-muted small">Active</span>
<h4 class="text-success">{{ active_courses }}</h4>
</div>
</div>
<div class="mt-3">
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Total Subjects</small>
<span class="badge bg-info p-2">{{ total_subjects }}</span>
</div>
<div class="d-flex justify-content-between mb-2">
<small class="mb-0">Total Batches</small>
<span class="badge bg-warning p-2">{{ total_batches }}</span>
</div>
<div class="d-flex justify-content-between">
<small class="mb-0">Inactive</small>
<span class="badge bg-danger p-2">{{ inactive_courses }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Teacher Ratings -->
<div class="row mb-4">
<div class="col-12">
<div class="content-card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-star text-warning me-2"></i>Top Rated Teachers
</h5>
</div>
<div class="card-body scroll-container">
<div class="table-responsive">
<table class="table table-hover">
<thead class="sticky-header">
<tr>
<th>Teacher</th>
<th>Student Rating</th>
<th>Parent Rating</th>
<th>Total Feedbacks</th>
</tr>
</thead>
<tbody>
{% for teacher in teacher_ratings %}
<tr>
<td>
<div class="d-flex align-items-center">
{% if teacher.image %}
<img src="{{ teacher.image.url }}" alt="{{ teacher.name }}" class="rounded-circle me-2" style="width: 40px; height: 40px; object-fit: cover;">
{% else %}
<div class="rounded-circle bg-light d-flex align-items-center justify-content-center me-2" style="width: 40px; height: 40px;">
<i class="fas fa-user-tie text-secondary"></i>
</div>
{% endif %}
<div>
<h6 class="mb-0">{{ teacher.name }}</h6>
<small class="text-muted">{{ teacher.designation }}</small>
</div>
</div>
</td>
<td>
<div class="d-flex align-items-center">
<span class="me-2">{{ teacher.avg_student_rating|floatformat:1 }}</span>
<div class="rating-stars">
{% for i in "12345"|make_list %}
{% if forloop.counter <= teacher.avg_student_rating %}
<i class="fas fa-star text-warning"></i>
{% else %}
<i class="far fa-star text-warning"></i>
{% endif %}
{% endfor %}
</div>
</div>
</td>
<td>
<div class="d-flex align-items-center">
<span class="me-2">{{ teacher.avg_parent_rating|floatformat:1 }}</span>
<div class="rating-stars">
{% for i in "12345"|make_list %}
{% if forloop.counter <= teacher.avg_parent_rating %}
<i class="fas fa-star text-warning"></i>
{% else %}
<i class="far fa-star text-warning"></i>
{% endif %}
{% endfor %}
</div>
</div>
</td>
<td>
<span class="badge bg-info">{{ teacher.total_feedbacks }}</span>
</td>
</tr>
{% empty %}
<tr>
<td colspan="4" class="text-center">
<small class="text-muted">No teacher ratings available</small>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Recent Activities -->
<div class="row mb-4">
<!-- Recent Notices -->
<div class="col-12 mb-4">
<div class="content-card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-bullhorn text-primary me-2"></i>Recent Notices
</h5>
<button type="button" class="btn btn-primary btn-sm" onclick="openAddNoticeModal()">
<i class="fas fa-plus me-2"></i>Add Notice
</button>
</div>
</div>
<div class="card-body scroll-container">
{% for notice in recent_notices %}
<div class="d-flex align-items-start mb-3 pb-3 border-bottom">
<div class="flex-shrink-0 me-3">
{% if notice.image %}
<img src="{{ notice.image.url }}" alt="{{ notice.title }}" class="rounded" style="width: 60px; height: 60px; object-fit: cover;">
{% else %}
<div class="rounded bg-light d-flex align-items-center justify-content-center" style="width: 60px; height: 60px;">
<i class="fas fa-bullhorn text-primary"></i>
</div>
{% endif %}
</div>
<div class="flex-grow-1">
<small class="mb-0 d-block fw-medium">{{ notice.title }}</small>
<small class="text-muted">{{ notice.message|truncatechars:50 }}</small>
<small class="d-block text-muted">{{ notice.created_at|timesince }} ago</small>
</div>
</div>
{% empty %}
<div class="text-center">
<small class="text-muted">No recent notices</small>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Leave Requests -->
<div class="row mb-4">
<!-- Staff Leave Requests -->
<div class="col-xl-6 mb-4">
<div class="content-card">
<h5 class="mb-3">
<i class="fas fa-user-tie text-info me-2"></i>Staff Leave Requests
</h5>
<div class="activity-scroll" id="staff-leaves-container">
{% for leave in staff_leaves %}
<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|date:"M d, Y" }}</small>
<small class="text-muted d-block">To: {{ leave.end_date|date:"M d, Y" }}</small>
<small class="text-muted d-block">{{ leave.message|truncatechars:50 }}</small>
<div class="mt-2">
<form method="post" action="{% url 'approve_staff_leave' leave.id %}" class="d-inline">
{% csrf_token %}
<button type="submit" class="btn btn-success btn-sm">
<i class="fas fa-check me-1"></i>Approve
</button>
</form>
<form method="post" action="{% url 'reject_staff_leave' leave.id %}" class="d-inline ms-2">
{% csrf_token %}
<button type="submit" class="btn btn-danger btn-sm">
<i class="fas fa-times me-1"></i>Reject
</button>
</form>
</div>
</div>
</div>
{% empty %}
<div class="text-center">
<small class="text-muted">No pending staff leave requests</small>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Student Leave Requests -->
<div class="col-xl-6 mb-4">
<div class="content-card">
<h5 class="mb-3">
<i class="fas fa-user-graduate text-warning me-2"></i>Student Leave Requests
</h5>
<div class="activity-scroll" id="student-leaves-container">
{% for leave in student_leaves %}
<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|date:"M d, Y" }}</small>
<small class="text-muted d-block">To: {{ leave.end_date|date:"M d, Y" }}</small>
<small class="text-muted d-block">{{ leave.message|truncatechars:50 }}</small>
<div class="mt-2">
<form method="post" action="{% url 'approve_student_leave' leave.id %}" class="d-inline">
{% csrf_token %}
<button type="submit" class="btn btn-success btn-sm">
<i class="fas fa-check me-1"></i>Approve
</button>
</form>
<form method="post" action="{% url 'reject_student_leave' leave.id %}" class="d-inline ms-2">
{% csrf_token %}
<button type="submit" class="btn btn-danger btn-sm">
<i class="fas fa-times me-1"></i>Reject
</button>
</form>
</div>
</div>
</div>
{% empty %}
<div class="text-center">
<small class="text-muted">No pending student leave requests</small>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
<!-- Recent Feedback and Meetings Row -->
<div class="row mb-4">
<!-- Recent Institute Feedback -->
<div class="col-xl-6 mb-4">
<div class="content-card">
<div class="card-header">
<h5 class="mb-0">
<i class="fas fa-comments text-success me-2"></i>Recent Institute Feedback
</h5>
</div>
<div class="card-body scroll-container">
{% for feedback in recent_feedback %}
<div class="d-flex align-items-center mb-2 pb-2 border-bottom">
<div class="flex-shrink-0 me-3">
{% if not feedback.is_anonymous %}
{% if feedback.student %}
{% if feedback.student.image %}
<img src="{{ feedback.student.image.url }}" alt="{{ feedback.student.name }}" class="rounded-circle" style="width: 40px; height: 40px; object-fit: cover;">
{% else %}
<div class="rounded-circle bg-light d-flex align-items-center justify-content: center" style="width: 40px; height: 40px;">
<i class="fas fa-user-graduate text-secondary"></i>
</div>
{% endif %}
{% elif feedback.staff %}
{% if feedback.staff.image %}
<img src="{{ feedback.staff.image.url }}" alt="{{ feedback.staff.name }}" class="rounded-circle" style="width: 40px; height: 40px; object-fit: cover;">
{% else %}
<div class="rounded-circle bg-light d-flex align-items-center justify-content: center" style="width: 40px; height: 40px;">
<i class="fas fa-user-tie text-secondary"></i>
</div>
{% endif %}
{% elif feedback.parent %}
{% if feedback.parent.image %}
<img src="{{ feedback.parent.image.url }}" alt="{{ feedback.parent.name }}" class="rounded-circle" style="width: 40px; height: 40px; object-fit: cover;">
{% else %}
<div class="rounded-circle bg-light d-flex align-items-center justify-content: center" style="width: 40px; height: 40px;">
<i class="fas fa-user-friends text-secondary"></i>
</div>
{% endif %}
{% endif %}
{% else %}
<div class="rounded-circle bg-light d-flex align-items-center justify-content: center" style="width: 40px; height: 40px;">
<i class="fas fa-user-secret text-secondary"></i>
</div>
{% endif %}
</div>
<div class="flex-grow-1">
{% if not feedback.is_anonymous %}
{% if feedback.student %}
<small class="mb-0 d-block fw-medium">{{ feedback.student.name }} (Student)</small>
<small class="text-muted d-block">
{{ feedback.student.course.name }} -
{% if feedback.student.course.duration_type == 'Semester' %}
Semester {{ feedback.student.current_period }}
{% else %}
Year {{ feedback.student.current_period }}
{% endif %}
</small>
{% elif feedback.staff %}
<small class="mb-0 d-block fw-medium">{{ feedback.staff.name }} ({{ feedback.staff.designation }})</small>
{% elif feedback.parent %}
<small class="mb-0 d-block fw-medium">{{ feedback.parent.name }} (Parent)</small>
{% with student=feedback.parent.students.first %}
{% if student %}
<small class="text-muted d-block">
Parent of {{ student.name }} -
{{ student.course.name }}
{% if student.course.duration_type == 'Semester' %}
(Semester {{ student.current_period }})
{% else %}
(Year {{ student.current_period }})
{% endif %}
</small>
{% endif %}
{% endwith %}
{% endif %}
{% else %}
<small class="mb-0 d-block fw-medium">Anonymous</small>
{% endif %}
<div class="d-flex align-items-center mt-1">
<span class="badge bg-info me-2">{{ feedback.get_feedback_type_display }}</span>
<div class="rating-stars">
{% for i in "12345"|make_list %}
<i class="{% if forloop.counter <= feedback.rating %}fas{% else %}far{% endif %} fa-star text-warning"></i>
{% endfor %}
</div>
</div>
{% if feedback.feedback_text %}
<small class="d-block text-muted mt-1">{{ feedback.feedback_text|truncatechars:100 }}</small>
{% endif %}
<small class="d-block text-muted mt-1">{{ feedback.created_at|timesince }} ago</small>
</div>
</div>
{% empty %}
<div class="text-center">
<small class="text-muted">No recent institute feedback</small>
</div>
{% endfor %}
</div>
</div>
</div>
<!-- Parent-Teacher Meetings -->
<div class="col-xl-6 mb-4">
<div class="content-card">
<div class="card-header">
<div class="d-flex justify-content-between align-items-center">
<h5 class="mb-0">
<i class="fas fa-calendar-check text-primary me-2"></i>Parent-Teacher Meetings
</h5>
<button type="button" class="btn btn-primary btn-sm" onclick="openScheduleMeetingModal()">
<i class="fas fa-plus me-2"></i>Schedule Meeting
</button>
</div>
</div>
<div class="card-body scroll-container">
<div class="table-responsive">
<table class="table table-hover">
<thead class="sticky-header">
<tr>
<th>Date</th>
<th>Time</th>
<th>Duration</th>
<th>Type</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for meeting in meetings %}
<tr>
<td>{{ meeting.meeting_date|date:"M d, Y" }}</td>
<td>{{ meeting.meeting_time|time:"h:i A" }}</td>
<td>{{ meeting.duration }} minutes</td>
<td>
{% if meeting.is_online %}
<span class="meeting-type online">
<i class="fas fa-video"></i>Online
{% if meeting.meeting_link %}
<a href="{{ meeting.meeting_link }}" target="_blank" class="ms-1">
<i class="fas fa-external-link-alt"></i>
{% endif %}
</span>
{% else %}
<span class="meeting-type in-person">
<i class="fas fa-user-friends"></i>In-person
</span>
{% endif %}
</td>
<td>
<span class="meeting-status {{ meeting.status }}">
{% if meeting.status == 'scheduled' %}
<i class="fas fa-calendar-check"></i>Scheduled
{% elif meeting.status == 'completed' %}
<i class="fas fa-check-circle"></i>Completed
{% elif meeting.status == 'cancelled' %}
<i class="fas fa-times-circle"></i>Cancelled
{% else %}
<i class="fas fa-calendar-alt"></i>Rescheduled
{% endif %}
</span>
</td>
<td>
<div class="meeting-actions">
{% if meeting.status == 'scheduled' %}
<button class="btn-action btn-complete" onclick="completeMeeting({{ meeting.id }})" title="Complete">
<i class="fas fa-check"></i>
</button>
<button class="btn-action btn-reschedule" onclick="rescheduleMeeting({{ meeting.id }})" title="Reschedule">
<i class="fas fa-calendar-alt"></i>
</button>
<button class="btn-action btn-cancel" onclick="cancelMeeting({{ meeting.id }})" title="Cancel">
<i class="fas fa-times"></i>
</button>
{% endif %}
{% if meeting.notes or meeting.status == 'completed' %}
<button class="btn-action btn-notes" onclick="viewMeetingNotes({{ meeting.id }})" title="View Notes">
<i class="fas fa-sticky-note"></i>
</button>
{% endif %}
{% if meeting.agenda %}
<button class="btn-action btn-agenda" onclick="viewMeetingAgenda({{ meeting.id }})" title="View Agenda">
<i class="fas fa-clipboard-list"></i>
</button>
{% endif %}
{% if meeting.status == 'cancelled' and meeting.cancellation_reason %}
<button class="btn-action btn-reason" onclick="viewCancellationReason({{ meeting.id }})" title="View Reason">
<i class="fas fa-question-circle"></i>
</button>
{% endif %}
</div>
</td>
</tr>
{% empty %}
<tr>
<td colspan="6" class="text-center">
<small class="text-muted">No meetings scheduled</small>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Schedule Meeting Modal -->
<div id="scheduleMeetingModal" 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) closeScheduleMeetingModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Schedule New Meeting</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeScheduleMeetingModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="scheduleMeetingError" class="alert alert-danger" style="display: none;"></div>
<div id="scheduleMeetingLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Scheduling meeting...</p>
</div>
<form id="scheduleMeetingForm" onsubmit="return false;">
{% csrf_token %}
<div class="mb-3">
<label for="meetingDate" class="form-label">Date</label>
<input type="date" class="form-control" id="meetingDate" name="meeting_date" required min="{{ today|date:'Y-m-d' }}">
<div class="invalid-feedback">Please select a valid date</div>
</div>
<div class="mb-3">
<label for="meetingTime" class="form-label">Time</label>
<input type="time" class="form-control" id="meetingTime" name="meeting_time" required>
<div class="invalid-feedback">Please select a valid time</div>
</div>
<div class="mb-3">
<label for="meetingDuration" class="form-label">Duration (minutes)</label>
<input type="number" class="form-control" id="meetingDuration" name="duration" min="15" max="120" value="30" required>
<div class="invalid-feedback">Duration must be between 15 and 120 minutes</div>
</div>
<div class="mb-3">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="isOnline" name="is_online">
<label class="form-check-label" for="isOnline">Online Meeting</label>
</div>
</div>
<div class="mb-3" id="meetingLinkContainer" style="display: none;">
<label for="meetingLink" class="form-label">Meeting Link</label>
<input type="url" class="form-control" id="meetingLink" name="meeting_link" placeholder="https://meet.google.com/...">
<div class="invalid-feedback">Please enter a valid meeting link</div>
</div>
<div class="mb-3">
<label for="scheduleMeetingAgenda" class="form-label">Agenda</label>
<textarea class="form-control" id="scheduleMeetingAgenda" name="agenda" rows="3" placeholder="Brief description of what you'd like to discuss"></textarea>
</div>
<div class="d-flex justify-content-end gap-2">
<button type="button" class="btn" style="background-color: #9E9E9E; color: white;" onclick="closeScheduleMeetingModal()">Cancel</button>
<button type="button" class="btn" style="background-color: #3F51B5; color: white;" onclick="submitMeetingForm()">Schedule Meeting</button>
</div>
</form>
</div>
</div>
</div>
<!-- Meeting Notes Modal -->
<div id="viewNotesModal" 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) closeNotesModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Meeting Notes</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeNotesModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="notesError" class="alert alert-danger" style="display: none;"></div>
<div id="notesLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Loading notes...</p>
</div>
<div id="meetingNotesContent" style="display: none;">
<p id="viewMeetingNotesText" style="margin: 0; white-space: pre-wrap;"></p>
</div>
</div>
</div>
</div>
<!-- Meeting Agenda Modal -->
<div id="viewAgendaModal" 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) closeAgendaModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Meeting Agenda</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeAgendaModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="agendaError" class="alert alert-danger" style="display: none;"></div>
<div id="agendaLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Loading agenda...</p>
</div>
<div id="meetingAgendaContent" style="display: none;">
<p id="viewMeetingAgendaText" style="margin: 0; white-space: pre-wrap;"></p>
</div>
</div>
</div>
</div>
<!-- Cancel Meeting Modal -->
<div id="cancelMeetingModal" 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) closeCancelModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Cancel Meeting</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeCancelModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="cancelError" class="alert alert-danger" style="display: none;"></div>
<div id="cancelLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Cancelling meeting...</p>
</div>
<form id="cancelMeetingForm" onsubmit="return false;">
{% csrf_token %}
<input type="hidden" id="cancelMeetingId" name="meeting_id">
<div class="mb-3">
<label for="cancellationReason" class="form-label">Reason for Cancellation</label>
<textarea class="form-control" id="cancellationReason" name="reason" rows="3" required></textarea>
<div class="invalid-feedback">Please provide a reason for cancellation</div>
</div>
<div class="d-flex justify-content-end gap-2">
<button type="button" class="btn" style="background-color: #9E9E9E; color: white;" onclick="closeCancelModal()">Close</button>
<button type="button" class="btn" style="background-color: #F44336; color: white;" onclick="submitCancelForm()">Cancel Meeting</button>
</div>
</form>
</div>
</div>
</div>
<!-- Reschedule Meeting Modal -->
<div id="rescheduleMeetingModal" 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) closeRescheduleModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Reschedule Meeting</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeRescheduleModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="rescheduleError" class="alert alert-danger" style="display: none;"></div>
<div id="rescheduleLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Rescheduling meeting...</p>
</div>
<form id="rescheduleMeetingForm" onsubmit="return false;">
{% csrf_token %}
<input type="hidden" id="rescheduleMeetingId" name="meeting_id">
<div class="mb-3">
<label for="rescheduleDate" class="form-label">New Date</label>
<input type="date" class="form-control" id="rescheduleDate" name="meeting_date" required>
<div class="invalid-feedback">Please select a valid date</div>
</div>
<div class="mb-3">
<label for="rescheduleTime" class="form-label">New Time</label>
<input type="time" class="form-control" id="rescheduleTime" name="meeting_time" required>
<div class="invalid-feedback">Please select a valid time</div>
</div>
<div class="d-flex justify-content-end gap-2">
<button type="button" class="btn" style="background-color: #9E9E9E; color: white;" onclick="closeRescheduleModal()">Close</button>
<button type="button" class="btn" style="background-color: #3F51B5; color: white;" onclick="submitRescheduleForm()">Reschedule Meeting</button>
</div>
</form>
</div>
</div>
</div>
<!-- Complete Meeting Modal -->
<div id="completeMeetingModal" 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) closeCompleteModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Complete Meeting</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeCompleteModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="completeError" class="alert alert-danger" style="display: none;"></div>
<div id="completeLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Completing meeting...</p>
</div>
<form id="completeMeetingForm" onsubmit="return false;">
{% csrf_token %}
<input type="hidden" id="completeMeetingId" name="meeting_id">
<div class="mb-3">
<label for="completeMeetingNotes" class="form-label">Meeting Notes</label>
<textarea class="form-control" id="completeMeetingNotes" name="notes" rows="3" placeholder="Enter any notes or summary from the meeting"></textarea>
</div>
<div class="d-flex justify-content-end gap-2">
<button type="button" class="btn" style="background-color: #9E9E9E; color: white;" onclick="closeCompleteModal()">Close</button>
<button type="button" class="btn" style="background-color: #4CAF50; color: white;" onclick="submitCompleteForm()">Complete Meeting</button>
</div>
</form>
</div>
</div>
</div>
<!-- Cancellation Reason Modal -->
<div id="viewReasonModal" 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) closeReasonModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Cancellation Reason</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeReasonModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="reasonError" class="alert alert-danger" style="display: none;"></div>
<div id="reasonLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Loading reason...</p>
</div>
<div id="meetingReasonContent" style="display: none;">
<p id="viewMeetingReasonText" style="margin: 0; white-space: pre-wrap;"></p>
</div>
</div>
</div>
</div>
</div>
<!-- Add Notice Modal -->
<div id="addNoticeModal" 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) closeAddNoticeModal();">
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 600px; background-color: white; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.2);">
<div style="background-color: #3F51B5; color: white; padding: 15px; 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: 18px;">Add New Notice</h5>
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeAddNoticeModal()">&times;</button>
</div>
<div style="padding: 20px;">
<div id="addNoticeError" class="alert alert-danger" style="display: none;"></div>
<div id="addNoticeLoading" class="text-center" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Adding notice...</p>
</div>
<form id="addNoticeForm" onsubmit="return false;">
{% csrf_token %}
<div class="mb-3">
<label for="noticeTitle" class="form-label">Title</label>
<input type="text" class="form-control" id="noticeTitle" name="title" required>
<div class="invalid-feedback">Please enter a title</div>
</div>
<div class="mb-3">
<label for="noticeMessage" class="form-label">Message</label>
<textarea class="form-control" id="noticeMessage" name="message" rows="3" required></textarea>
<div class="invalid-feedback">Please enter a message</div>
</div>
<div class="mb-3">
<label for="noticeImage" class="form-label">Image (Optional)</label>
<input type="file" class="form-control" id="noticeImage" name="image" accept="image/*">
</div>
<div class="d-flex justify-content-end gap-2">
<button type="button" class="btn" style="background-color: #9E9E9E; color: white;" onclick="closeAddNoticeModal()">Cancel</button>
<button type="button" class="btn" style="background-color: #3F51B5; color: white;" onclick="submitNoticeForm()">Post Notice</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}