huge update
This commit is contained in:
1 parent
8072284990
commit
f2c72885a6
123 files changed
+25119
-4984
No files matched your search
@@ -0,0 +1,384 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<script>
|
||||
// Force cache clear for JavaScript files
|
||||
if (window.location.href.indexOf('cache=clear') === -1) {
|
||||
// Only run once to avoid redirect loop
|
||||
const allScripts = document.querySelectorAll('script[src]');
|
||||
for (const script of allScripts) {
|
||||
if (script.src.indexOf('static/js/') !== -1) {
|
||||
const originalSrc = script.src;
|
||||
script.src = originalSrc + '?v=' + new Date().getTime();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||
<meta http-equiv="Pragma" content="no-cache">
|
||||
<meta http-equiv="Expires" content="0">
|
||||
<title>{% block title %}Student Management System{% endblock %}</title>
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Font Awesome -->
|
||||
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
||||
|
||||
<!-- Base CSS -->
|
||||
<link rel="stylesheet" href="{% static 'css/base.css' %}">
|
||||
<!-- Custom Dashboard CSS -->
|
||||
<link href="{% static 'css/dashboard.css' %}" rel="stylesheet">
|
||||
<!-- Custom CSS -->
|
||||
<link href="{% static 'css/custom.css' %}" rel="stylesheet">
|
||||
|
||||
<!-- Responsive Styles -->
|
||||
<style>
|
||||
/* Base responsive styles */
|
||||
html {
|
||||
font-size: 16px;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
width: 100%;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
|
||||
/* Responsive typography */
|
||||
@media (max-width: 768px) {
|
||||
html {
|
||||
font-size: 14px;
|
||||
}
|
||||
h1 { font-size: 1.8rem; }
|
||||
h2 { font-size: 1.5rem; }
|
||||
h3 { font-size: 1.3rem; }
|
||||
h4 { font-size: 1.1rem; }
|
||||
h5 { font-size: 1rem; }
|
||||
h6 { font-size: 0.9rem; }
|
||||
}
|
||||
|
||||
/* Responsive containers and spacing */
|
||||
@media (max-width: 768px) {
|
||||
.container, .container-fluid {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
.row {
|
||||
margin-left: -10px;
|
||||
margin-right: -10px;
|
||||
}
|
||||
.col-md-6, .col-lg-3 {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.card {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.table-responsive {
|
||||
overflow-x: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
.welcome-section h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.summary-card .card-body {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Small screen optimizations */
|
||||
@media (max-width: 576px) {
|
||||
html {
|
||||
font-size: 13px;
|
||||
}
|
||||
.container-fluid {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.col-md-6, .col-lg-3 {
|
||||
padding-left: 5px;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.row {
|
||||
margin-left: -5px;
|
||||
margin-right: -5px;
|
||||
}
|
||||
.card {
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
.btn {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.form-control {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.table th, .table td {
|
||||
padding: 0.5rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
.modal-dialog {
|
||||
margin: 0.5rem;
|
||||
}
|
||||
.toast {
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive navigation */
|
||||
@media (max-width: 768px) {
|
||||
.navbar-nav {
|
||||
padding: 1rem 0;
|
||||
}
|
||||
.navbar-toggler {
|
||||
padding: 0.25rem 0.5rem;
|
||||
}
|
||||
.dropdown-menu {
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive forms */
|
||||
@media (max-width: 576px) {
|
||||
.form-group {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.form-label {
|
||||
font-size: 0.875rem;
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
.form-control {
|
||||
height: calc(1.5em + 0.5rem + 2px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive images and media */
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Profile picture responsive styles */
|
||||
.profile-picture-container {
|
||||
position: relative;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
background-color: #f5f5f5;
|
||||
border: 2px solid #3F51B5;
|
||||
margin-right: 1rem;
|
||||
flex-shrink: 0;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
.profile-picture {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* Profile picture sizes */
|
||||
.profile-picture-container.profile-lg {
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.profile-picture-container.profile-md {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
.profile-picture-container.profile-sm {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
/* Mobile optimizations for profile pictures */
|
||||
@media (max-width: 576px) {
|
||||
.profile-picture-container {
|
||||
border-width: 1.5px;
|
||||
}
|
||||
.profile-picture-container.profile-lg {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
.profile-picture-container.profile-md {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
}
|
||||
.profile-picture-container.profile-sm {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive modals */
|
||||
@media (max-width: 576px) {
|
||||
.modal-dialog {
|
||||
margin: 0;
|
||||
max-width: none;
|
||||
height: 100%;
|
||||
}
|
||||
.modal-content {
|
||||
border-radius: 0;
|
||||
min-height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Touch device optimizations */
|
||||
@media (hover: none) {
|
||||
.btn, .nav-link, .dropdown-item {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
.form-control, .form-select {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% block extrahead %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
{% if messages %}
|
||||
<div class="position-fixed top-0 end-0 p-3" style="z-index: 11">
|
||||
{% for message in messages %}
|
||||
<div class="toast show" role="alert" aria-live="assertive" aria-atomic="true">
|
||||
<div class="toast-header {% if message.tags == 'error' %}bg-danger text-white{% elif message.tags == 'success' %}bg-success text-white{% else %}bg-info text-white{% endif %}">
|
||||
<strong class="me-auto">{% if message.tags == 'error' %}Error{% elif message.tags == 'success' %}Success{% else %}Info{% endif %}</strong>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block content %}{% endblock %}
|
||||
|
||||
<!-- Bootstrap Bundle with Popper -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></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>
|
||||
|
||||
<!-- Custom Dashboard Components - No type="module" -->
|
||||
<script src="{% static 'js/rating.js' %}?v={% now 'U' %}"></script>
|
||||
<script src="{% static 'js/tabs.js' %}?v={% now 'U' %}"></script>
|
||||
<script src="{% static 'js/bootstrap-init.js' %}?v={% now 'U' %}"></script>
|
||||
<script src="{% static 'js/notifications.js' %}?v={% now 'U' %}"></script>
|
||||
<script src="{% static 'js/form-validation.js' %}?v={% now 'U' %}"></script>
|
||||
<!-- Navigation JS -->
|
||||
<script src="{% static 'js/navigation.js' %}?v={% now 'U' %}"></script>
|
||||
<!-- Main Dashboard JS - Must come after all supporting scripts -->
|
||||
<script src="{% static 'js/dashboard.js' %}?v={% now 'U' %}"></script>
|
||||
|
||||
<!-- Common Modal Functions -->
|
||||
<script>
|
||||
function openLeaveModal() {
|
||||
var modal = document.getElementById('customLeaveModal');
|
||||
modal.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeLeaveModal() {
|
||||
var modal = document.getElementById('customLeaveModal');
|
||||
modal.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function openProfileModal() {
|
||||
var modal = document.getElementById('profileModal');
|
||||
modal.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeProfileModal() {
|
||||
var modal = document.getElementById('profileModal');
|
||||
modal.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
function openPasswordModal() {
|
||||
var modal = document.getElementById('passwordModal');
|
||||
modal.style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closePasswordModal() {
|
||||
var modal = document.getElementById('passwordModal');
|
||||
modal.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
|
||||
// Handle Escape key for all modals
|
||||
document.addEventListener('keydown', function(event) {
|
||||
if (event.key === 'Escape') {
|
||||
var modals = document.querySelectorAll('[id$="Modal"]');
|
||||
modals.forEach(function(modal) {
|
||||
if (modal.style.display === 'block') {
|
||||
// Call the appropriate close function
|
||||
var modalId = modal.id;
|
||||
var closeFunction = window['close' + modalId.charAt(0).toUpperCase() + modalId.slice(1)];
|
||||
if (typeof closeFunction === 'function') {
|
||||
closeFunction();
|
||||
} else {
|
||||
// Fallback to basic close
|
||||
modal.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Handle clicking outside modal to close
|
||||
document.addEventListener('click', function(event) {
|
||||
var modals = document.querySelectorAll('[id$="Modal"]');
|
||||
modals.forEach(function(modal) {
|
||||
if (event.target === modal) {
|
||||
// Call the appropriate close function
|
||||
var modalId = modal.id;
|
||||
var closeFunction = window['close' + modalId.charAt(0).toUpperCase() + modalId.slice(1)];
|
||||
if (typeof closeFunction === 'function') {
|
||||
closeFunction();
|
||||
} else {
|
||||
// Fallback to basic close
|
||||
modal.style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-hide toasts
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var toasts = document.querySelectorAll('.toast');
|
||||
toasts.forEach(function(toast) {
|
||||
setTimeout(function() {
|
||||
toast.style.display = 'none';
|
||||
}, 5000); // Hide after 5 seconds
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% block extra_js %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,256 @@
|
||||
<!-- Bottom Navigation -->
|
||||
<div class="bottom-nav">
|
||||
<div class="nav-container">
|
||||
<a href="#" class="nav-item active" data-section="dashboard">
|
||||
<i class="fas fa-home"></i>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
{% if user.groups.all.0.name == 'Teacher' %}
|
||||
<a href="#subjectsSection" class="nav-item" data-section="subjects" onclick="showSection('subjectsSection'); return false;">
|
||||
<i class="fas fa-graduation-cap"></i>
|
||||
<span>Subjects</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="schedule">
|
||||
<i class="fas fa-clock"></i>
|
||||
<span>Schedule</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="attendance">
|
||||
<i class="fas fa-user-check"></i>
|
||||
<span>Attendance</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="leave">
|
||||
<i class="fas fa-calendar-times"></i>
|
||||
<span>Leaves</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="notice">
|
||||
<i class="fas fa-bullhorn"></i>
|
||||
<span>Notices</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="feedback">
|
||||
<i class="fas fa-star"></i>
|
||||
<span>Feedback</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="profile">
|
||||
<i class="fas fa-id-card"></i>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
{% elif user.groups.all.0.name == 'Admission Officer' %}
|
||||
<a href="#" class="nav-item" data-section="students" onclick="showSection('studentsSection'); return false;">
|
||||
<i class="fas fa-users"></i>
|
||||
<span>Students</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="courses" onclick="showSection('coursesSection'); return false;">
|
||||
<i class="fas fa-graduation-cap"></i>
|
||||
<span>Courses</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="batches" onclick="showSection('batchesSection'); return false;">
|
||||
<i class="fas fa-layer-group"></i>
|
||||
<span>Batches</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="courseTracking" onclick="showSection('courseTrackingSection'); return false;">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
<span>Tracking</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="leave">
|
||||
<i class="fas fa-calendar-times"></i>
|
||||
<span>Leaves</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="notice" onclick="showSection('noticeSection'); return false;">
|
||||
<i class="fas fa-bullhorn"></i>
|
||||
<span>Notices</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="profile">
|
||||
<i class="fas fa-id-card"></i>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
{% elif user.groups.all.0.name == 'HOD' %}
|
||||
<a href="#" class="nav-item" data-section="students" onclick="showSection('studentsSection'); return false;">
|
||||
<i class="fas fa-users"></i>
|
||||
<span>Students</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="staff" onclick="showSection('staffSection'); return false;">
|
||||
<i class="fas fa-chalkboard-teacher"></i>
|
||||
<span>Staff</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="subjects" onclick="showSection('subjectsSection'); return false;">
|
||||
<i class="fas fa-book"></i>
|
||||
<span>Subjects</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="routine" onclick="showSection('routineSection'); return false;">
|
||||
<i class="fas fa-calendar-week"></i>
|
||||
<span>Routine</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="progress" onclick="showSection('progressSection'); return false;">
|
||||
<i class="fas fa-chart-line"></i>
|
||||
<span>Progress</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="meetings" onclick="showSection('meetingsSection'); return false;">
|
||||
<i class="fas fa-calendar-check"></i>
|
||||
<span>Meetings</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="notice" onclick="showSection('noticeSection'); return false;">
|
||||
<i class="fas fa-bullhorn"></i>
|
||||
<span>Notices</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="profile" onclick="showSection('profileSection'); return false;">
|
||||
<i class="fas fa-id-card"></i>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="#" class="nav-item" data-section="subjects">
|
||||
<i class="fas fa-graduation-cap"></i>
|
||||
<span>Subjects</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="routine">
|
||||
<i class="fas fa-calendar-week"></i>
|
||||
<span>Routine</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="attendance">
|
||||
<i class="fas fa-user-check"></i>
|
||||
<span>Attendance</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="leave">
|
||||
<i class="fas fa-calendar-times"></i>
|
||||
<span>Leaves</span>
|
||||
</a>
|
||||
{% if user.groups.all.0.name == 'Parent' %}
|
||||
<a href="#" class="nav-item" data-section="meetings" onclick="showSection('meetingsSection'); return false;">
|
||||
<i class="fas fa-calendar-check"></i>
|
||||
<span>Meetings</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="#" class="nav-item" data-section="feedback">
|
||||
<i class="fas fa-star"></i>
|
||||
<span>Feedback</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="notice">
|
||||
<i class="fas fa-bullhorn"></i>
|
||||
<span>Notices</span>
|
||||
</a>
|
||||
<a href="#" class="nav-item" data-section="profile">
|
||||
<i class="fas fa-id-card"></i>
|
||||
<span>Profile</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="#" class="nav-item" onclick="document.getElementById('logoutForm').submit(); return false;">
|
||||
<i class="fas fa-sign-out-alt"></i>
|
||||
<span>Logout</span>
|
||||
</a>
|
||||
<form id="logoutForm" method="post" action="{% url 'logout' %}" style="display: none;">
|
||||
{% csrf_token %}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Styles -->
|
||||
<style>
|
||||
.bottom-nav {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: white;
|
||||
box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
|
||||
z-index: 1000;
|
||||
overflow-x: auto; /* Allow horizontal scrolling if needed */
|
||||
padding-bottom: 28px; /* Increased space for copyright */
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
padding: 10px 0 5px 0;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
flex-wrap: nowrap; /* Prevent wrapping to ensure all items are visible */
|
||||
min-width: max-content; /* Ensure container is at least as wide as all items */
|
||||
}
|
||||
|
||||
.nav-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #666;
|
||||
text-decoration: none;
|
||||
font-size: 0.9rem;
|
||||
transition: color 0.3s ease;
|
||||
margin: 0 8px; /* Add margin between items */
|
||||
white-space: nowrap; /* Prevent text wrapping */
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
color: #666;
|
||||
background: none;
|
||||
border: none;
|
||||
font-size: 0.9rem;
|
||||
transition: color 0.3s ease;
|
||||
cursor: pointer;
|
||||
margin: 0 8px;
|
||||
padding: 0;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.nav-item i, .nav-btn i {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.nav-item.active, .nav-btn.active {
|
||||
color: #3F51B5;
|
||||
}
|
||||
|
||||
.nav-item:hover, .nav-btn:hover {
|
||||
color: #3F51B5;
|
||||
}
|
||||
|
||||
.nav-copyright {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 5px 0;
|
||||
font-size: 0.85rem;
|
||||
color: #555;
|
||||
background-color: #f0f0f0;
|
||||
border-top: 1px solid #ddd;
|
||||
line-height: 18px;
|
||||
box-shadow: 0 -1px 2px rgba(0,0,0,0.05);
|
||||
z-index: 1001; /* Higher than the bottom nav */
|
||||
}
|
||||
|
||||
.nav-copyright a {
|
||||
color: #3F51B5;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.nav-container {
|
||||
padding: 8px 0;
|
||||
justify-content: flex-start; /* Left align items when scrolling */
|
||||
}
|
||||
|
||||
.nav-item, .nav-btn {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.nav-item i, .nav-btn i {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.nav-copyright {
|
||||
font-size: 0.75rem;
|
||||
padding: 4px 0;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Copyright Notice -->
|
||||
<div class="nav-copyright">
|
||||
© {% now 'Y' %} <a href="https://github.com/S4NKALP">SANKALP</a>. All rights reserved.
|
||||
</div>
|
||||
@@ -0,0 +1,142 @@
|
||||
{% load static %}
|
||||
|
||||
<!-- Profile Modal -->
|
||||
<div id="profileModal" 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) closeProfileModal();">
|
||||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 500px; 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;">Update Profile Picture</h5>
|
||||
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeProfileModal()">×</button>
|
||||
</div>
|
||||
<div style="padding: 20px;">
|
||||
<form action="{% url 'update_profile' %}" method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div style="text-align: center; margin-bottom: 20px;">
|
||||
{% if user.image %}
|
||||
<div class="profile-picture-container profile-lg mx-auto">
|
||||
<img src="{{ user.image.url }}" alt="{{ user.name }}" class="profile-picture">
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="profile-picture-container profile-lg mx-auto">
|
||||
<img src="{% static 'img/user.png' %}" alt="Default User" class="profile-picture">
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label style="display: block; margin-bottom: 8px; font-weight: 500;">Select New Profile Picture</label>
|
||||
<input type="file" name="profile_image" required style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;">
|
||||
</div>
|
||||
<div style="display: flex; justify-content: space-between;">
|
||||
<button type="button" onclick="closeProfileModal()" style="background-color: #9E9E9E; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer;">Cancel</button>
|
||||
<button type="submit" style="background-color: #3F51B5; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer;">Update Picture</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Password Change Modal -->
|
||||
<div id="passwordModal" 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) closePasswordModal();">
|
||||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 500px; 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;">Change Password</h5>
|
||||
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closePasswordModal()">×</button>
|
||||
</div>
|
||||
<div style="padding: 20px;">
|
||||
<form action="{% url 'change_password' %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="current_password" style="display: block; margin-bottom: 8px; font-weight: 500;">Current Password</label>
|
||||
<input type="password" id="current_password" name="current_password" required style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="new_password" style="display: block; margin-bottom: 8px; font-weight: 500;">New Password</label>
|
||||
<input type="password" id="new_password" name="new_password" required style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="confirm_password" style="display: block; margin-bottom: 8px; font-weight: 500;">Confirm New Password</label>
|
||||
<input type="password" id="confirm_password" name="confirm_password" required style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;">
|
||||
</div>
|
||||
<button type="submit" style="background-color: #3F51B5; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; width: 100%;">Change Password</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Leave Request Modal -->
|
||||
<div id="customLeaveModal" 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) closeLeaveModal();">
|
||||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 500px; 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;">Request Leave</h5>
|
||||
<button id="closeCustomModal" style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeLeaveModal()">×</button>
|
||||
</div>
|
||||
<form action="{% if user.is_teacher %}{% url 'request_staff_leave' %}{% else %}{% url 'request_leave' %}{% endif %}" method="post">
|
||||
{% csrf_token %}
|
||||
<div style="padding: 20px;">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="startDate" style="display: block; margin-bottom: 8px; font-weight: 500;">Start Date</label>
|
||||
<input type="date" id="startDate" name="start_date" style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;" required>
|
||||
</div>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="endDate" style="display: block; margin-bottom: 8px; font-weight: 500;">End Date</label>
|
||||
<input type="date" id="endDate" name="end_date" style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;" required>
|
||||
</div>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="customLeaveMessage" style="display: block; margin-bottom: 8px; font-weight: 500;">Reason</label>
|
||||
<textarea id="customLeaveMessage" name="message" rows="3" style="width: 100%; padding: 10px; border: 1px solid #BDBDBD; border-radius: 4px; box-sizing: border-box;" required></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div style="padding: 15px; border-top: 1px solid #EEEEEE; text-align: right; display: flex; flex-wrap: wrap; justify-content: flex-end;">
|
||||
<button type="button" id="cancelCustomModal" style="background-color: #9E9E9E; color: white; border: none; padding: 8px 16px; border-radius: 4px; margin-right: 10px; margin-bottom: 10px; cursor: pointer; font-size: 14px;" onclick="closeLeaveModal()">Cancel</button>
|
||||
<button type="submit" style="background-color: #3F51B5; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-size: 14px; margin-bottom: 10px;">Submit Request</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Confirmation Modal -->
|
||||
<div id="confirmationModal" 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) closeConfirmationModal();">
|
||||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 400px; 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: 12px; border-top-left-radius: 8px; border-top-right-radius: 8px; display: flex; justify-content: space-between; align-items: center; position: sticky; top: 0; z-index: 1;">
|
||||
<h5 style="margin: 0; font-size: 18px;">Confirm Deletion</h5>
|
||||
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeConfirmationModal()">×</button>
|
||||
</div>
|
||||
<div style="padding: 15px;">
|
||||
<p style="margin: 0 0 15px 0;">Are you sure you want to delete this file? This action cannot be undone.</p>
|
||||
</div>
|
||||
<div style="padding: 12px; border-top: 1px solid #EEEEEE; text-align: right; position: sticky; bottom: 0; background-color: white; border-bottom-left-radius: 8px; border-bottom-right-radius: 8px;">
|
||||
<button type="button" style="background-color: #9E9E9E; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 14px; margin-right: 8px;" onclick="closeConfirmationModal()">Cancel</button>
|
||||
<button type="button" style="background-color: #3F51B5; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 14px;" id="confirmDeleteBtn">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Modal -->
|
||||
<div id="messageModal" style="display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0,0,0,0.5); z-index: 10001;" onclick="if(event.target === this) closeMessageModal();">
|
||||
<div style="position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); width: 90%; max-width: 400px; 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: 12px; border-top-left-radius: 8px; border-top-right-radius: 8px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<h5 id="messageModalTitle" style="margin: 0; font-size: 18px;">Message</h5>
|
||||
<button style="background: none; border: none; color: white; font-size: 24px; cursor: pointer; line-height: 24px;" onclick="closeMessageModal()">×</button>
|
||||
</div>
|
||||
<div style="padding: 15px;">
|
||||
<p id="messageModalContent" style="margin: 0 0 15px 0;"></p>
|
||||
</div>
|
||||
<div style="padding: 12px; border-top: 1px solid #EEEEEE; text-align: right;">
|
||||
<button type="button" style="background-color: #3F51B5; color: white; border: none; padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 14px;" onclick="closeMessageModal()">OK</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Utility function for displaying message modals
|
||||
function showMessageModal(title, message) {
|
||||
document.getElementById('messageModalTitle').textContent = title;
|
||||
document.getElementById('messageModalContent').textContent = message;
|
||||
document.getElementById('messageModal').style.display = 'block';
|
||||
document.body.style.overflow = 'hidden';
|
||||
}
|
||||
|
||||
function closeMessageModal() {
|
||||
document.getElementById('messageModal').style.display = 'none';
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,247 @@
|
||||
{% load static %}
|
||||
|
||||
<!-- Welcome Section -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<div class="welcome-card">
|
||||
<div class="welcome-content">
|
||||
<div class="user-info">
|
||||
<div class="profile-image">
|
||||
{% if user.image %}
|
||||
<img src="{{ user.image.url }}" alt="{{ user.name }}" class="profile-picture">
|
||||
{% else %}
|
||||
<img src="{% static 'img/user.png' %}" alt="Default User" class="profile-picture">
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="user-details">
|
||||
<h2>Welcome, {{ user.name }}!</h2>
|
||||
<div class="user-meta">
|
||||
<span class="user-role">
|
||||
{% if user.groups.all.0.name == "HOD" %}
|
||||
<i class="fas fa-user-shield"></i> Head of Department
|
||||
{% elif user.designation %}
|
||||
<i class="fas fa-user-tie"></i> {{ user.designation }}
|
||||
{% elif user.groups.all.0.name == "Parent" %}
|
||||
<i class="fas fa-user-friends"></i> Parent
|
||||
{% elif user.groups.all.0.name == "Student" %}
|
||||
<i class="fas fa-user-graduate"></i> Student
|
||||
{% else %}
|
||||
<i class="fas fa-user"></i> User
|
||||
{% endif %}
|
||||
</span>
|
||||
<span class="user-id">
|
||||
<i class="fas fa-id-card"></i> ID: {{ user.id }}
|
||||
</span>
|
||||
{% if user.phone %}
|
||||
<span class="user-phone">
|
||||
<i class="fas fa-phone"></i> {{ user.phone }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if user.email %}
|
||||
<span class="user-email">
|
||||
<i class="fas fa-envelope"></i> {{ user.email }}
|
||||
</span>
|
||||
{% endif %}
|
||||
{% if user.department %}
|
||||
<span class="user-department">
|
||||
<i class="fas fa-building"></i> {{ user.department }}
|
||||
</span>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="user-actions">
|
||||
<button class="action-btn" onclick="openProfileModal()">
|
||||
<i class="fas fa-user-edit"></i>
|
||||
<span>Edit Profile</span>
|
||||
</button>
|
||||
<button class="action-btn" onclick="openPasswordModal()">
|
||||
<i class="fas fa-key"></i>
|
||||
<span>Change Password</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.welcome-card {
|
||||
background: linear-gradient(135deg, #4e54c8, #8f94fb);
|
||||
border-radius: 15px;
|
||||
padding: clamp(1rem, 3vw, 1.5rem);
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
|
||||
margin-bottom: 1.5rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.welcome-content {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: clamp(0.75rem, 2vw, 1rem);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: clamp(1rem, 2.5vw, 1.5rem);
|
||||
flex: 1;
|
||||
min-width: 280px;
|
||||
}
|
||||
|
||||
.profile-image {
|
||||
width: clamp(60px, 10vw, 80px);
|
||||
height: clamp(60px, 10vw, 80px);
|
||||
border-radius: 50%;
|
||||
border: 3px solid rgba(255, 255, 255, 0.3);
|
||||
overflow: hidden;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.profile-picture {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
.user-details h2 {
|
||||
color: white;
|
||||
margin: 0 0 0.5rem 0;
|
||||
font-size: clamp(1.25rem, 3vw, 1.75rem);
|
||||
font-weight: 600;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
gap: clamp(0.5rem, 1.5vw, 1rem);
|
||||
}
|
||||
|
||||
.user-meta span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: clamp(0.8rem, 2vw, 0.9rem);
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 20px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.user-meta i {
|
||||
font-size: clamp(0.8rem, 2vw, 0.9rem);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
display: flex;
|
||||
gap: clamp(0.5rem, 1.5vw, 0.75rem);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: clamp(0.4rem, 1vw, 0.5rem) clamp(0.75rem, 2vw, 1rem);
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
border-radius: 8px;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
font-size: clamp(0.8rem, 2vw, 0.9rem);
|
||||
transition: all 0.3s ease;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.action-btn:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.welcome-content {
|
||||
gap: 1.25rem;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.welcome-content {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
min-width: auto;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.welcome-card {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.user-meta span {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.user-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
@media (hover: none) {
|
||||
.action-btn:hover {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in new issue
Block a user