Initial commit
6
.htaccess
Normal file
@@ -0,0 +1,6 @@
|
||||
# Redirect everything to /src while allowing direct access to it
|
||||
RewriteEngine On
|
||||
# Skip if already under /src
|
||||
RewriteCond %{REQUEST_URI} !^/src/
|
||||
# Redirect all to /src preserving the path
|
||||
RewriteRule ^(.*)$ /src/$1 [L]
|
||||
15
Dockerfile
Normal file
@@ -0,0 +1,15 @@
|
||||
FROM php:8.2-apache
|
||||
|
||||
RUN apt-get update && apt-get install -y \
|
||||
libpng-dev libjpeg62-turbo-dev libfreetype6-dev \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install gd mysqli pdo pdo_mysql \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy app into web root (index.php is in src/)
|
||||
COPY src/ /var/www/html/
|
||||
|
||||
# Enable useful Apache module and set permissions
|
||||
RUN a2enmod rewrite && chown -R www-data:www-data /var/www/html
|
||||
|
||||
EXPOSE 80
|
||||
20
account.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"generated_at": "2025-12-18T16:06:30.346Z",
|
||||
"users": [
|
||||
{
|
||||
"id": 1,
|
||||
"username": "johnlloydsumawang26",
|
||||
"email": "johnlloydsumawang@gmail.com",
|
||||
"role": "admin",
|
||||
"password_hash": "$2y$10$cH0FJuPLd467oX0q01ZADu6v2lh0kmfNob0HOyO5tuRstcdXBbIuS",
|
||||
"password": "jolo26"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"username": "SPayDigong",
|
||||
"email": "redgie@simc.gov.ph",
|
||||
"role": "admin",
|
||||
"password_hash": "$2y$10$r02pNIERlJKRmrT6haCP8.YLpEAAEM0hTYRQnWpJ7ktZ6E6GRjQNq"
|
||||
}
|
||||
]
|
||||
}
|
||||
33
docker-compose.yml
Normal file
@@ -0,0 +1,33 @@
|
||||
version: "3.9"
|
||||
services:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
container_name: attendance_app
|
||||
ports:
|
||||
- "9090:80"
|
||||
environment:
|
||||
DB_HOST: db
|
||||
DB_USER: root
|
||||
DB_PASS: ""
|
||||
DB_NAME: attendance_system
|
||||
volumes:
|
||||
- ./src:/var/www/html
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
db:
|
||||
image: mariadb:10.6
|
||||
container_name: attendance_db
|
||||
environment:
|
||||
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: "yes"
|
||||
MARIADB_DATABASE: attendance_system
|
||||
volumes:
|
||||
- db_data:/var/lib/mysql
|
||||
- ./docker/migrate.sql:/docker-entrypoint-initdb.d/migrate.sql:ro
|
||||
ports:
|
||||
- "3306:3306"
|
||||
|
||||
volumes:
|
||||
db_data:
|
||||
207
docker/migrate.sql
Normal file
@@ -0,0 +1,207 @@
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
DROP TABLE IF EXISTS `attendance_logs`;
|
||||
DROP TABLE IF EXISTS `attendance`;
|
||||
DROP TABLE IF EXISTS `attendance_records`;
|
||||
DROP TABLE IF EXISTS `activities`;
|
||||
DROP TABLE IF EXISTS `students`;
|
||||
DROP TABLE IF EXISTS `courses`;
|
||||
DROP TABLE IF EXISTS `departments`;
|
||||
DROP TABLE IF EXISTS `schools`;
|
||||
DROP TABLE IF EXISTS `genders`;
|
||||
DROP TABLE IF EXISTS `system_settings`;
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
|
||||
CREATE TABLE `users` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) NOT NULL,
|
||||
`password` varchar(255) NOT NULL,
|
||||
`role` enum('admin','staff') NOT NULL DEFAULT 'staff',
|
||||
`full_name` varchar(120) NOT NULL,
|
||||
`email` varchar(120) DEFAULT NULL,
|
||||
`status` tinyint NOT NULL DEFAULT 1,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_username` (`username`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `system_settings` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`setting_key` varchar(80) NOT NULL,
|
||||
`setting_value` text NULL,
|
||||
`description` text NULL,
|
||||
`updated_by` int DEFAULT NULL,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_setting_key` (`setting_key`),
|
||||
CONSTRAINT `fk_settings_user` FOREIGN KEY (`updated_by`) REFERENCES `users` (`id`) ON DELETE SET NULL
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `schools` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(10) NOT NULL,
|
||||
`name` varchar(150) NOT NULL,
|
||||
`address` text NULL,
|
||||
`contact_number` varchar(30) NULL,
|
||||
`email` varchar(120) NULL,
|
||||
`status` tinyint NOT NULL DEFAULT 1,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_school_code` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `genders` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(1) NOT NULL,
|
||||
`name` varchar(20) NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_gender_code` (`code`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `departments` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(10) NOT NULL,
|
||||
`name` varchar(150) NOT NULL,
|
||||
`description` text NULL,
|
||||
`school_id` int NOT NULL,
|
||||
`status` tinyint NOT NULL DEFAULT 1,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_department_code` (`code`),
|
||||
CONSTRAINT `fk_departments_school` FOREIGN KEY (`school_id`) REFERENCES `schools` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `courses` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(15) NOT NULL,
|
||||
`name` varchar(150) NOT NULL,
|
||||
`department_id` int NOT NULL,
|
||||
`description` text NULL,
|
||||
`status` tinyint NOT NULL DEFAULT 1,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_course_code` (`code`),
|
||||
CONSTRAINT `fk_courses_department` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `students` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`student_id` varchar(30) NOT NULL,
|
||||
`full_name` varchar(150) NOT NULL,
|
||||
`gender_id` int NOT NULL,
|
||||
`year_level` int NOT NULL DEFAULT 1,
|
||||
`course_id` int NOT NULL,
|
||||
`department_id` int NOT NULL,
|
||||
`school_id` int NOT NULL,
|
||||
`email` varchar(150) NULL,
|
||||
`contact_number` varchar(30) NULL,
|
||||
`address` text NULL,
|
||||
`qr_code` varchar(255) NOT NULL,
|
||||
`status` tinyint NOT NULL DEFAULT 1,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_student_id` (`student_id`),
|
||||
UNIQUE KEY `uniq_qr_code` (`qr_code`),
|
||||
CONSTRAINT `fk_students_gender` FOREIGN KEY (`gender_id`) REFERENCES `genders` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_students_course` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_students_department` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_students_school` FOREIGN KEY (`school_id`) REFERENCES `schools` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `activities` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(150) NOT NULL,
|
||||
`date` date NOT NULL,
|
||||
`time_in` time NULL,
|
||||
`time_out` time NULL,
|
||||
`location` varchar(255) NULL,
|
||||
`description` text NULL,
|
||||
`required_students` enum('all','specific_course','specific_department') NOT NULL DEFAULT 'all',
|
||||
`course_id` int DEFAULT NULL,
|
||||
`department_id` int DEFAULT NULL,
|
||||
`status` tinyint NOT NULL DEFAULT 1,
|
||||
`created_by` int NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_activities_course` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_activities_department` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE SET NULL,
|
||||
CONSTRAINT `fk_activities_user` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `attendance` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`student_id` int NOT NULL,
|
||||
`activity_id` int NOT NULL,
|
||||
`time_in` datetime DEFAULT NULL,
|
||||
`time_out` datetime DEFAULT NULL,
|
||||
`status` enum('present','late','absent','excused') NOT NULL DEFAULT 'present',
|
||||
`notes` text NULL,
|
||||
`recorded_by` int NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uniq_student_activity` (`student_id`,`activity_id`),
|
||||
CONSTRAINT `fk_attendance_student` FOREIGN KEY (`student_id`) REFERENCES `students` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_attendance_activity` FOREIGN KEY (`activity_id`) REFERENCES `activities` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_attendance_user` FOREIGN KEY (`recorded_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `attendance_logs` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`attendance_id` int NOT NULL,
|
||||
`action` enum('time_in','time_out','status_change','manual_entry') NOT NULL,
|
||||
`old_value` varchar(255) NULL,
|
||||
`new_value` varchar(255) NULL,
|
||||
`changed_by` int NOT NULL,
|
||||
`notes` text NULL,
|
||||
`changed_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_logs_attendance` FOREIGN KEY (`attendance_id`) REFERENCES `attendance` (`id`) ON DELETE CASCADE,
|
||||
CONSTRAINT `fk_logs_user` FOREIGN KEY (`changed_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
CREATE TABLE `attendance_records` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`student_id` int NOT NULL,
|
||||
`course_id` int NOT NULL,
|
||||
`status` enum('present','late','absent') NOT NULL DEFAULT 'present',
|
||||
`date_recorded` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
`created_by` int NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
CONSTRAINT `fk_records_student` FOREIGN KEY (`student_id`) REFERENCES `students` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_records_course` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE RESTRICT,
|
||||
CONSTRAINT `fk_records_user` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
INSERT INTO `users` (`username`, `password`, `role`, `full_name`, `email`, `status`)
|
||||
VALUES ('admin', '$2y$12$Z0SOoRGlhfq65/a0eNlHL.pnO7qhYWJoUlZKDmnp7SwNttCkY07hC', 'admin', 'System Administrator', 'admin@example.com', 1);
|
||||
|
||||
INSERT INTO `genders` (`code`, `name`) VALUES
|
||||
('M', 'Male'),
|
||||
('F', 'Female'),
|
||||
('O', 'Other');
|
||||
|
||||
INSERT INTO `schools` (`code`, `name`, `address`, `contact_number`, `email`) VALUES
|
||||
('ACAD', 'Academy of Innovation', '123 University Ave, Solano', '+63 900 000 0000', 'info@academy.edu.ph');
|
||||
|
||||
INSERT INTO `departments` (`code`, `name`, `description`, `school_id`) VALUES
|
||||
('CASE', 'College of Arts & Sciences', 'General education and sciences', 1),
|
||||
('CBA', 'College of Business & Accountancy', 'Business programs', 1);
|
||||
|
||||
INSERT INTO `courses` (`code`, `name`, `department_id`, `description`) VALUES
|
||||
('BSIT', 'BS Information Technology', 1, 'Technology track'),
|
||||
('BSBA', 'BS Business Administration', 2, 'Business track');
|
||||
|
||||
INSERT INTO `system_settings` (`setting_key`, `setting_value`, `description`, `updated_by`) VALUES
|
||||
('app.name', 'QR Attendance System', 'System display name', 1),
|
||||
('attendance.cutoff_minutes', '15', 'Minutes before absent marked late', 1),
|
||||
('qr.prefix', 'STU', 'Prefix for generated QR tokens', 1);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
21
prompt.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"idea": "QR Code Attendance Management System for schools",
|
||||
"table-quantity": 11,
|
||||
"tables": [
|
||||
"activities",
|
||||
"attendance",
|
||||
"attendance_logs",
|
||||
"attendance_records",
|
||||
"courses",
|
||||
"departments",
|
||||
"genders",
|
||||
"schools",
|
||||
"students",
|
||||
"system_settings",
|
||||
"users"
|
||||
],
|
||||
"prompt": "Build a complete QR-based attendance platform for academic institutions. Include admin dashboards for managing students, courses, departments, activities, and system users; QR code generation/printing for each student; QR + manual attendance capture with per-activity participant restrictions; audit trails, exports, printable reports, and configurable system settings. Stack: PHP (Apache) backend with MariaDB, Bootstrap 5 + jQuery frontend, REST-like PHP endpoints for scanning/manual entry, and clean responsive UI.",
|
||||
"architecture": "MariaDB (DB), PHP (backend), jQuery (JS), Bootstrap 5 (UI), phpqrcode (QR generation)",
|
||||
"docker-compose.yml": "Single docker-compose with MariaDB, phpMyAdmin, and PHP-Apache web container on one bridge network. Provide basic env vars (DB host, user, pass), persist volumes for db/web, and mount the SQL seed/init scripts.",
|
||||
"code-style": "Keep implementations straightforward and readable; prefer simple PHP includes, prepared statements, and Bootstrap components without heavy abstractions."
|
||||
}
|
||||
26
src-backup/.htaccess.txt
Normal file
@@ -0,0 +1,26 @@
|
||||
RewriteEngine On
|
||||
|
||||
# Redirect trailing slashes
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule ^(.*)/$ /$1 [L,R=301]
|
||||
|
||||
# Protect sensitive directories
|
||||
RewriteRule ^includes/ - [F,L]
|
||||
RewriteRule ^config/ - [F,L]
|
||||
RewriteRule ^sql/ - [F,L]
|
||||
|
||||
# Prevent access to .htaccess
|
||||
<Files .htaccess>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
</Files>
|
||||
|
||||
# Set default index file
|
||||
DirectoryIndex index.php
|
||||
|
||||
# Security headers
|
||||
<IfModule mod_headers.c>
|
||||
Header set X-Content-Type-Options "nosniff"
|
||||
Header set X-Frame-Options "SAMEORIGIN"
|
||||
Header set X-XSS-Protection "1; mode=block"
|
||||
</IfModule>
|
||||
267
src-backup/admin/add_activity.php
Normal file
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Add New Activity";
|
||||
|
||||
// Initialize variables
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Validate required fields
|
||||
$required_fields = ['name', 'date', 'time_in', 'time_out', 'location', 'required_students'];
|
||||
$valid = true;
|
||||
|
||||
foreach ($required_fields as $field) {
|
||||
if (empty($_POST[$field])) {
|
||||
$message = "Please fill all required fields!";
|
||||
$message_type = 'danger';
|
||||
$valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
$activity_data = [
|
||||
'name' => escape($conn, $_POST['name']),
|
||||
'date' => $_POST['date'],
|
||||
'time_in' => $_POST['time_in'],
|
||||
'time_out' => $_POST['time_out'],
|
||||
'description' => escape($conn, $_POST['description']),
|
||||
'location' => escape($conn, $_POST['location']),
|
||||
'required_students' => $_POST['required_students'],
|
||||
'course_id' => $_POST['course_id'] ? intval($_POST['course_id']) : null,
|
||||
'department_id' => $_POST['department_id'] ? intval($_POST['department_id']) : null,
|
||||
'created_by' => $_SESSION['user_id']
|
||||
];
|
||||
|
||||
// Validate time
|
||||
if (strtotime($activity_data['time_out']) <= strtotime($activity_data['time_in'])) {
|
||||
$message = 'Time Out must be later than Time In!';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
$sql = "INSERT INTO activities (
|
||||
name, date, time_in, time_out, description, location,
|
||||
required_students, course_id, department_id, created_by,
|
||||
created_at, updated_at, status
|
||||
) VALUES (
|
||||
'{$activity_data['name']}',
|
||||
'{$activity_data['date']}',
|
||||
'{$activity_data['time_in']}',
|
||||
'{$activity_data['time_out']}',
|
||||
'{$activity_data['description']}',
|
||||
'{$activity_data['location']}',
|
||||
'{$activity_data['required_students']}',
|
||||
" . ($activity_data['course_id'] ? $activity_data['course_id'] : 'NULL') . ",
|
||||
" . ($activity_data['department_id'] ? $activity_data['department_id'] : 'NULL') . ",
|
||||
{$activity_data['created_by']},
|
||||
NOW(),
|
||||
NOW(),
|
||||
1
|
||||
)";
|
||||
|
||||
if (query($conn, $sql)) {
|
||||
$_SESSION['message'] = 'Activity added successfully!';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header('Location: manage_activities.php');
|
||||
exit();
|
||||
} else {
|
||||
$message = 'Error adding activity: ' . mysqli_error($conn);
|
||||
$message_type = 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get dropdown data
|
||||
$courses = [];
|
||||
$departments = [];
|
||||
|
||||
// Courses
|
||||
$result = query($conn, "SELECT * FROM courses WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$courses[] = $row;
|
||||
}
|
||||
|
||||
// Departments
|
||||
$result = query($conn, "SELECT * FROM departments WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$departments[] = $row;
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">Add New Activity</h1>
|
||||
<p class="text-muted">Schedule a new activity, event, or class.</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_activities.php" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Activities
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show">
|
||||
<?php echo $message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Add Activity Form -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-calendar-plus me-2"></i> Activity Details
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="" id="addActivityForm">
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Activity Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="name" required
|
||||
placeholder="e.g., JPCS Week, Morning Class, Seminar"
|
||||
value="<?php echo $_POST['name'] ?? ''; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Date <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control" name="date" required
|
||||
min="<?php echo date('Y-m-d'); ?>"
|
||||
value="<?php echo $_POST['date'] ?? date('Y-m-d'); ?>">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">Time In <span class="text-danger">*</span></label>
|
||||
<input type="time" class="form-control" name="time_in" required
|
||||
value="<?php echo $_POST['time_in'] ?? '08:00'; ?>">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">Time Out <span class="text-danger">*</span></label>
|
||||
<input type="time" class="form-control" name="time_out" required
|
||||
value="<?php echo $_POST['time_out'] ?? '17:00'; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Location <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="location" required
|
||||
placeholder="e.g., AVR1, Room 101, Gymnasium"
|
||||
value="<?php echo $_POST['location'] ?? ''; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea class="form-control" name="description" rows="3"
|
||||
placeholder="Brief description of the activity..."><?php echo $_POST['description'] ?? ''; ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Participants <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="required_students" required id="participantType" onchange="toggleParticipantSelection()">
|
||||
<option value="">Select Participant Type</option>
|
||||
<option value="all" <?php echo ($_POST['required_students'] ?? '') == 'all' ? 'selected' : ''; ?>>All Students</option>
|
||||
<option value="specific_course" <?php echo ($_POST['required_students'] ?? '') == 'specific_course' ? 'selected' : ''; ?>>Specific Course</option>
|
||||
<option value="specific_department" <?php echo ($_POST['required_students'] ?? '') == 'specific_department' ? 'selected' : ''; ?>>Specific Department</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3" id="courseSelection" style="display: none;">
|
||||
<label class="form-label">Select Course</label>
|
||||
<select class="form-select" name="course_id" id="courseSelect">
|
||||
<option value="">Select Course</option>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<option value="<?php echo $course['id']; ?>"
|
||||
<?php echo ($_POST['course_id'] ?? '') == $course['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $course['code']; ?> - <?php echo $course['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3" id="departmentSelection" style="display: none;">
|
||||
<label class="form-label">Select Department</label>
|
||||
<select class="form-select" name="department_id" id="departmentSelect">
|
||||
<option value="">Select Department</option>
|
||||
<?php foreach ($departments as $department): ?>
|
||||
<option value="<?php echo $department['id']; ?>"
|
||||
<?php echo ($_POST['department_id'] ?? '') == $department['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $department['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save me-1"></i> Schedule Activity
|
||||
</button>
|
||||
<a href="manage_activities.php" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
function toggleParticipantSelection() {
|
||||
const participantType = document.getElementById("participantType").value;
|
||||
const courseSelection = document.getElementById("courseSelection");
|
||||
const departmentSelection = document.getElementById("departmentSelection");
|
||||
|
||||
if (participantType === "specific_course") {
|
||||
courseSelection.style.display = "block";
|
||||
departmentSelection.style.display = "none";
|
||||
document.getElementById("courseSelect").required = true;
|
||||
document.getElementById("departmentSelect").required = false;
|
||||
} else if (participantType === "specific_department") {
|
||||
courseSelection.style.display = "none";
|
||||
departmentSelection.style.display = "block";
|
||||
document.getElementById("courseSelect").required = false;
|
||||
document.getElementById("departmentSelect").required = true;
|
||||
} else {
|
||||
courseSelection.style.display = "none";
|
||||
departmentSelection.style.display = "none";
|
||||
document.getElementById("courseSelect").required = false;
|
||||
document.getElementById("departmentSelect").required = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set minimum date for activity date (today or later)
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
document.querySelector("input[name=\'date\']").min = today;
|
||||
|
||||
// Initialize participant selection
|
||||
toggleParticipantSelection();
|
||||
|
||||
// Time validation
|
||||
document.getElementById("addActivityForm").addEventListener("submit", function(e) {
|
||||
const timeIn = document.querySelector("input[name=\'time_in\']").value;
|
||||
const timeOut = document.querySelector("input[name=\'time_out\']").value;
|
||||
|
||||
if (timeIn && timeOut && timeOut <= timeIn) {
|
||||
e.preventDefault();
|
||||
alert("Time Out must be later than Time In!");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
434
src-backup/admin/add_student.php
Normal file
@@ -0,0 +1,434 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Add New Student";
|
||||
|
||||
// Initialize variables
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
// Get dropdown data
|
||||
$genders = [];
|
||||
$courses = [];
|
||||
$departments = [];
|
||||
$schools = [];
|
||||
|
||||
// Genders
|
||||
$result = mysqli_query($conn, "SELECT * FROM genders ORDER BY id");
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$genders[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Courses
|
||||
$result = mysqli_query($conn, "SELECT * FROM courses WHERE status = 1 ORDER BY code");
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$courses[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Departments
|
||||
$result = mysqli_query($conn, "SELECT * FROM departments WHERE status = 1 ORDER BY code");
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$departments[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Schools
|
||||
$result = mysqli_query($conn, "SELECT * FROM schools WHERE status = 1 ORDER BY code");
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$schools[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
|
||||
// Get form data
|
||||
$student_id = trim($_POST['student_id'] ?? '');
|
||||
$full_name = trim($_POST['full_name'] ?? '');
|
||||
$gender_id = intval($_POST['gender_id'] ?? 0);
|
||||
$year_level = intval($_POST['year_level'] ?? 0);
|
||||
$course_id = intval($_POST['course_id'] ?? 0);
|
||||
$department_id = intval($_POST['department_id'] ?? 0);
|
||||
$school_id = intval($_POST['school_id'] ?? 0);
|
||||
$birth_date = !empty($_POST['birth_date']) ? $_POST['birth_date'] : NULL;
|
||||
$contact_number = trim($_POST['contact_number'] ?? '');
|
||||
$email = trim($_POST['email'] ?? '');
|
||||
$address = trim($_POST['address'] ?? '');
|
||||
|
||||
|
||||
// Debug: Check required fields
|
||||
if (empty($student_id) || empty($full_name) || $gender_id == 0 || $year_level == 0 ||
|
||||
$course_id == 0 || $department_id == 0 || $school_id == 0) {
|
||||
$message = 'Please fill in all required fields.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
|
||||
// Validate email format if provided
|
||||
elseif (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$message = 'Please enter a valid email address.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
|
||||
// Check for duplicate student ID
|
||||
else {
|
||||
$check_sql = "SELECT id FROM students WHERE student_id = ?";
|
||||
$stmt = mysqli_prepare($conn, $check_sql);
|
||||
if ($stmt) {
|
||||
mysqli_stmt_bind_param($stmt, 's', $student_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_store_result($stmt);
|
||||
|
||||
if (mysqli_stmt_num_rows($stmt) > 0) {
|
||||
$message = 'Student ID already exists. Please use a different Student ID.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
// If no errors, insert student
|
||||
if (empty($message)) {
|
||||
// Generate QR code
|
||||
$qr_code = 'STU_' . $student_id . '_' . uniqid();
|
||||
|
||||
$sql = "INSERT INTO students (
|
||||
student_id, qr_code, full_name, gender_id, year_level,
|
||||
course_id, department_id, school_id, birth_date,
|
||||
contact_number, email, address, created_at, updated_at, status
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, NOW(), NOW(), 1)";
|
||||
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
if ($stmt) {
|
||||
// Escape data
|
||||
$student_id = mysqli_real_escape_string($conn, $student_id);
|
||||
$full_name = mysqli_real_escape_string($conn, $full_name);
|
||||
$contact_number = mysqli_real_escape_string($conn, $contact_number);
|
||||
$email = mysqli_real_escape_string($conn, $email);
|
||||
$address = mysqli_real_escape_string($conn, $address);
|
||||
|
||||
// Bind parameters based on birth_date
|
||||
if ($birth_date === NULL) {
|
||||
mysqli_stmt_bind_param($stmt, 'sssiiiiissss',
|
||||
$student_id, $qr_code, $full_name, $gender_id, $year_level,
|
||||
$course_id, $department_id, $school_id, null,
|
||||
$contact_number, $email, $address
|
||||
);
|
||||
} else {
|
||||
mysqli_stmt_bind_param($stmt, 'sssiiiiissss',
|
||||
$student_id, $qr_code, $full_name, $gender_id, $year_level,
|
||||
$course_id, $department_id, $school_id, $birth_date,
|
||||
$contact_number, $email, $address
|
||||
);
|
||||
}
|
||||
|
||||
if (mysqli_stmt_execute($stmt)) {
|
||||
$new_student_id = mysqli_insert_id($conn);
|
||||
|
||||
// Redirect to view the newly added student
|
||||
$_SESSION['flash_message'] = 'Student added successfully!';
|
||||
$_SESSION['flash_type'] = 'success';
|
||||
header("Location: view_student.php?id=$new_student_id");
|
||||
exit();
|
||||
} else {
|
||||
$message = 'Error adding student: ' . mysqli_error($conn);
|
||||
$message_type = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
} else {
|
||||
$message = 'Error preparing statement: ' . mysqli_error($conn);
|
||||
$message_type = 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">
|
||||
<i class="bi bi-person-plus me-2"></i> Add New Student
|
||||
</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="dashboard.php">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="manage_students.php">Manage Students</a></li>
|
||||
<li class="breadcrumb-item active">Add Student</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_students.php" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Students
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show mb-4" role="alert">
|
||||
<i class="bi bi-<?php echo $message_type == 'success' ? 'check-circle' : 'exclamation-triangle'; ?> me-2"></i>
|
||||
<?php echo $message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<!-- Add Form Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-person-lines-fill me-2"></i> Student Information
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="" id="addStudentForm">
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Student ID <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="student_id" required
|
||||
placeholder="e.g., 23-0217" maxlength="50"
|
||||
value="<?php echo isset($_POST['student_id']) ? htmlspecialchars($_POST['student_id']) : ''; ?>">
|
||||
<div class="form-text">Unique student identification number</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Full Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="full_name" required
|
||||
placeholder="John Lloyd Sumawang" maxlength="100"
|
||||
value="<?php echo isset($_POST['full_name']) ? htmlspecialchars($_POST['full_name']) : ''; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Gender <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="gender_id" required>
|
||||
<option value="">Select Gender</option>
|
||||
<?php foreach ($genders as $gender): ?>
|
||||
<option value="<?php echo $gender['id']; ?>"
|
||||
<?php echo (isset($_POST['gender_id']) && $_POST['gender_id'] == $gender['id']) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($gender['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Year Level <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="year_level" required>
|
||||
<option value="">Select Year Level</option>
|
||||
<?php for ($i = 1; $i <= 4; $i++): ?>
|
||||
<option value="<?php echo $i; ?>"
|
||||
<?php echo (isset($_POST['year_level']) && $_POST['year_level'] == $i) ? 'selected' : ''; ?>>
|
||||
Year <?php echo $i; ?>
|
||||
</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">School <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="school_id" required>
|
||||
<option value="">Select School</option>
|
||||
<?php foreach ($schools as $school): ?>
|
||||
<option value="<?php echo $school['id']; ?>"
|
||||
<?php echo (isset($_POST['school_id']) && $_POST['school_id'] == $school['id']) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($school['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Department <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="department_id" required>
|
||||
<option value="">Select Department</option>
|
||||
<?php foreach ($departments as $department): ?>
|
||||
<option value="<?php echo $department['id']; ?>"
|
||||
<?php echo (isset($_POST['department_id']) && $_POST['department_id'] == $department['id']) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($department['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Course <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="course_id" required>
|
||||
<option value="">Select Course</option>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<option value="<?php echo $course['id']; ?>"
|
||||
<?php echo (isset($_POST['course_id']) && $_POST['course_id'] == $course['id']) ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($course['code']); ?> - <?php echo htmlspecialchars($course['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Birth Date</label>
|
||||
<input type="date" class="form-control" name="birth_date"
|
||||
max="<?php echo date('Y-m-d'); ?>"
|
||||
value="<?php echo isset($_POST['birth_date']) ? htmlspecialchars($_POST['birth_date']) : ''; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Email Address</label>
|
||||
<input type="email" class="form-control" name="email"
|
||||
placeholder="student@example.com" maxlength="100"
|
||||
value="<?php echo isset($_POST['email']) ? htmlspecialchars($_POST['email']) : ''; ?>">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Contact Number</label>
|
||||
<input type="tel" class="form-control" name="contact_number"
|
||||
placeholder="0912-345-6789"
|
||||
value="<?php echo isset($_POST['contact_number']) ? htmlspecialchars($_POST['contact_number']) : ''; ?>">
|
||||
<div class="form-text">Format: 0912-345-6789 or 09123456789</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mb-3">
|
||||
<label class="form-label">Address</label>
|
||||
<textarea class="form-control" name="address" rows="3"
|
||||
placeholder="Complete address" maxlength="255"><?php echo isset($_POST['address']) ? htmlspecialchars($_POST['address']) : ''; ?></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<a href="manage_students.php" class="btn btn-secondary">
|
||||
<i class="bi bi-x-circle me-2"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary" name="add_student">
|
||||
<i class="bi bi-save me-2"></i> Save Student
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<!-- Guidelines Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-info-circle me-2"></i> Guidelines
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<ul class="list-group list-group-flush">
|
||||
<li class="list-group-item">
|
||||
<i class="bi bi-asterisk text-danger me-2"></i>
|
||||
Fields marked with <span class="text-danger">*</span> are required
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="bi bi-card-checklist me-2"></i>
|
||||
Student ID must be unique
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="bi bi-calendar me-2"></i>
|
||||
Birth date cannot be in the future
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="bi bi-envelope me-2"></i>
|
||||
Email must be valid format (optional)
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="bi bi-telephone me-2"></i>
|
||||
Contact number should include area code
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<i class="bi bi-qr-code me-2"></i>
|
||||
QR code will be automatically generated
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions Card -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-warning text-dark">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-lightning me-2"></i> Quick Actions
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="manage_students.php" class="btn btn-outline-primary">
|
||||
<i class="bi bi-people me-2"></i> View All Students
|
||||
</a>
|
||||
<a href="import_students.php" class="btn btn-outline-success">
|
||||
<i class="bi bi-upload me-2"></i> Import Students
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// SIMPLE JavaScript without complex validation
|
||||
$page_scripts = '
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Simple form submission
|
||||
$("#addStudentForm").submit(function(e) {
|
||||
// Simple validation - just check if required fields are filled
|
||||
let valid = true;
|
||||
|
||||
// Check required fields
|
||||
const requiredFields = [
|
||||
"student_id", "full_name", "gender_id",
|
||||
"year_level", "school_id", "department_id", "course_id"
|
||||
];
|
||||
|
||||
requiredFields.forEach(field => {
|
||||
const element = $("[name=\'" + field + "\']");
|
||||
const value = element.val().trim();
|
||||
|
||||
if (!value || value === "" || value === "0") {
|
||||
valid = false;
|
||||
element.addClass("is-invalid");
|
||||
element.after(\'<div class="invalid-feedback">This field is required.</div>\');
|
||||
} else {
|
||||
element.removeClass("is-invalid");
|
||||
element.next(".invalid-feedback").remove();
|
||||
}
|
||||
});
|
||||
|
||||
if (!valid) {
|
||||
e.preventDefault();
|
||||
alert("Please fill in all required fields marked with *");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
$(this).find("button[type=\'submit\']").prop("disabled", true).html(\'<i class="bi bi-hourglass-split me-2"></i> Saving...\');
|
||||
return true;
|
||||
});
|
||||
|
||||
// Remove error classes on input
|
||||
$("input, select, textarea").on("input change", function() {
|
||||
$(this).removeClass("is-invalid");
|
||||
$(this).next(".invalid-feedback").remove();
|
||||
});
|
||||
|
||||
// Auto-focus first field
|
||||
$("input[name=\'student_id\']").focus();
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
363
src-backup/admin/attendance.php
Normal file
@@ -0,0 +1,363 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin/teacher
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true ||
|
||||
($_SESSION['role'] !== 'admin' && $_SESSION['role'] !== 'teacher')) {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "QR Code Scanner";
|
||||
|
||||
// Get active activities for today
|
||||
$activities = [];
|
||||
$sql = "SELECT * FROM activities WHERE status = 1 AND date = CURDATE() ORDER BY time_in ASC";
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$activities[] = $row;
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<div class="d-flex justify-content-between flex-wrap flex-md-nowrap align-items-center pt-3 pb-2 mb-3 border-bottom">
|
||||
<h1 class="h2">QR Code Scanner</h1>
|
||||
<div class="btn-toolbar mb-2 mb-md-0">
|
||||
<div class="btn-group me-2">
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="switchCamera()">
|
||||
<i class="bi bi-camera-video"></i> Switch Camera
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary" onclick="toggleScanner()">
|
||||
<i class="bi bi-power"></i> Toggle Scanner
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Scanner</h6>
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<!-- Scanner Container -->
|
||||
<div id="qr-reader" style="width: 100%; max-width: 500px; margin: 0 auto;"></div>
|
||||
|
||||
<!-- Scan Result -->
|
||||
<div id="scan-result" class="mt-4"></div>
|
||||
|
||||
<!-- Manual Entry Form -->
|
||||
<div class="mt-4">
|
||||
<h6 class="text-muted mb-3">Or enter student ID manually:</h6>
|
||||
<form id="manual-entry-form" class="row g-3">
|
||||
<div class="col-md-8">
|
||||
<input type="text" class="form-control" id="student_id"
|
||||
placeholder="Enter Student ID" required>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<button type="submit" class="btn btn-primary w-100">
|
||||
<i class="bi bi-check-circle"></i> Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Today's Activities</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php if (empty($activities)): ?>
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-info-circle"></i> No activities scheduled for today.
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="list-group">
|
||||
<?php foreach ($activities as $activity): ?>
|
||||
<div class="list-group-item">
|
||||
<h6 class="mb-1"><?php echo $activity['name']; ?></h6>
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-clock"></i>
|
||||
<?php echo date('h:i A', strtotime($activity['time_in'])); ?> -
|
||||
<?php echo date('h:i A', strtotime($activity['time_out'])); ?>
|
||||
</small><br>
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-geo-alt"></i> <?php echo $activity['location']; ?>
|
||||
</small>
|
||||
<div class="mt-2">
|
||||
<span class="badge bg-<?php echo time() >= strtotime($activity['time_in']) && time() <= strtotime($activity['time_out']) ? 'success' : 'secondary'; ?>">
|
||||
<?php echo time() >= strtotime($activity['time_in']) && time() <= strtotime($activity['time_out']) ? 'Active Now' : 'Scheduled'; ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card shadow">
|
||||
<div class="card-header py-3">
|
||||
<h6 class="m-0 font-weight-bold text-primary">Quick Stats</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php
|
||||
$sql = "SELECT COUNT(*) as total FROM attendance WHERE DATE(created_at) = CURDATE()";
|
||||
$result = query($conn, $sql);
|
||||
$today_attendance = mysqli_fetch_assoc($result)['total'];
|
||||
|
||||
$sql = "SELECT COUNT(*) as total FROM students WHERE status = 1";
|
||||
$result = query($conn, $sql);
|
||||
$total_students = mysqli_fetch_assoc($result)['total'];
|
||||
?>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Today's Attendance:</span>
|
||||
<strong><?php echo $today_attendance; ?></strong>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between mb-2">
|
||||
<span>Total Students:</span>
|
||||
<strong><?php echo $total_students; ?></strong>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height: 10px;">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
style="width: <?php echo $total_students > 0 ? ($today_attendance / $total_students * 100) : 0; ?>%">
|
||||
</div>
|
||||
</div>
|
||||
<small class="text-muted">
|
||||
<?php echo number_format($total_students > 0 ? ($today_attendance / $total_students * 100) : 0, 1); ?>% attendance rate today
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script src="https://unpkg.com/html5-qrcode"></script>
|
||||
<script>
|
||||
let html5QrCode;
|
||||
let isScanning = false;
|
||||
let cameraId = null;
|
||||
|
||||
// Initialize scanner
|
||||
function initScanner() {
|
||||
html5QrCode = new Html5Qrcode("qr-reader");
|
||||
}
|
||||
|
||||
// Start scanner
|
||||
async function startScanner() {
|
||||
if (isScanning) return;
|
||||
|
||||
const devices = await Html5Qrcode.getCameras();
|
||||
if (devices && devices.length > 0) {
|
||||
const facingMode = cameraId ? { exact: cameraId } : { facingMode: "environment" };
|
||||
const config = { fps: 10, qrbox: { width: 250, height: 250 } };
|
||||
|
||||
try {
|
||||
await html5QrCode.start(facingMode, config, onScanSuccess, onScanError);
|
||||
isScanning = true;
|
||||
document.getElementById("scan-result").innerHTML = \'<div class="alert alert-info"><i class="bi bi-info-circle"></i> Scanner started. Point camera at QR code.</div>\';
|
||||
} catch (error) {
|
||||
console.error("Scanner start error:", error);
|
||||
document.getElementById("scan-result").innerHTML = \'<div class="alert alert-danger"><i class="bi bi-exclamation-triangle"></i> Failed to start camera: \' + error + \'</div>\';
|
||||
}
|
||||
} else {
|
||||
document.getElementById("scan-result").innerHTML = \'<div class="alert alert-warning"><i class="bi bi-camera-video-off"></i> No camera found.</div>\';
|
||||
}
|
||||
}
|
||||
|
||||
// Stop scanner
|
||||
function stopScanner() {
|
||||
if (!isScanning) return;
|
||||
|
||||
html5QrCode.stop().then(() => {
|
||||
isScanning = false;
|
||||
document.getElementById("scan-result").innerHTML = \'<div class="alert alert-secondary"><i class="bi bi-info-circle"></i> Scanner stopped.</div>\';
|
||||
}).catch(error => {
|
||||
console.error("Scanner stop error:", error);
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle scanner
|
||||
function toggleScanner() {
|
||||
if (isScanning) {
|
||||
stopScanner();
|
||||
} else {
|
||||
startScanner();
|
||||
}
|
||||
}
|
||||
|
||||
// Switch camera
|
||||
async function switchCamera() {
|
||||
const devices = await Html5Qrcode.getCameras();
|
||||
if (devices.length > 1) {
|
||||
stopScanner();
|
||||
// Switch to next camera
|
||||
const currentIndex = devices.findIndex(device => device.id === cameraId);
|
||||
const nextIndex = (currentIndex + 1) % devices.length;
|
||||
cameraId = devices[nextIndex].id;
|
||||
startScanner();
|
||||
}
|
||||
}
|
||||
|
||||
// Scan success callback
|
||||
function onScanSuccess(decodedText, decodedResult) {
|
||||
// Show scanning indicator
|
||||
document.getElementById("scan-result").innerHTML = \'<div class="alert alert-info"><div class="spinner-border spinner-border-sm me-2"></div>Processing QR code...</div>\';
|
||||
|
||||
// Send to server
|
||||
fetch(\'../api/scan_qr.php\', {
|
||||
method: \'POST\',
|
||||
headers: {
|
||||
\'Content-Type\': \'application/json\',
|
||||
},
|
||||
body: JSON.stringify({ qr_code: decodedText })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
document.getElementById("scan-result").innerHTML = `
|
||||
<div class="alert alert-success">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<h5 class="mb-1">✓ Attendance Recorded!</h5>
|
||||
<p class="mb-1"><strong>Student:</strong> \${data.data.student_name}</p>
|
||||
<p class="mb-1"><strong>Activity:</strong> \${data.data.activity_name}</p>
|
||||
<p class="mb-1"><strong>Time:</strong> \${data.data.time}</p>
|
||||
<p class="mb-0"><strong>Status:</strong> <span class="badge bg-success">\${data.data.status}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Play success sound
|
||||
playSound(\'success\');
|
||||
|
||||
} else {
|
||||
document.getElementById("scan-result").innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
\${data.message}
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Play error sound
|
||||
playSound(\'error\');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById("scan-result").innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
Network error: \${error}
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
}
|
||||
|
||||
// Scan error callback
|
||||
function onScanError(error) {
|
||||
// Don\'t show all errors to user
|
||||
console.warn("QR Scan Error:", error);
|
||||
}
|
||||
|
||||
// Manual entry form
|
||||
document.getElementById("manual-entry-form").addEventListener("submit", function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const studentId = document.getElementById("student_id").value.trim();
|
||||
if (!studentId) return;
|
||||
|
||||
// Show processing indicator
|
||||
document.getElementById("scan-result").innerHTML = \'<div class="alert alert-info"><div class="spinner-border spinner-border-sm me-2"></div>Processing manual entry...</div>\';
|
||||
|
||||
// Send to server
|
||||
fetch(\'../api/manual_entry.php\', {
|
||||
method: \'POST\',
|
||||
headers: {
|
||||
\'Content-Type\': \'application/json\',
|
||||
},
|
||||
body: JSON.stringify({ student_id: studentId })
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
document.getElementById("scan-result").innerHTML = `
|
||||
<div class="alert alert-success">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<h5 class="mb-1">✓ Manual Entry Recorded!</h5>
|
||||
<p class="mb-1"><strong>Student:</strong> \${data.data.student_name}</p>
|
||||
<p class="mb-1"><strong>Activity:</strong> \${data.data.activity_name}</p>
|
||||
<p class="mb-0"><strong>Time:</strong> \${data.data.time}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Clear input
|
||||
document.getElementById("student_id").value = \'\';
|
||||
playSound(\'success\');
|
||||
|
||||
} else {
|
||||
document.getElementById("scan-result").innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
\${data.message}
|
||||
</div>
|
||||
`;
|
||||
playSound(\'error\');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
document.getElementById("scan-result").innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
Network error: \${error}
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
});
|
||||
|
||||
// Play sound
|
||||
function playSound(type) {
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const oscillator = audioContext.createOscillator();
|
||||
const gainNode = audioContext.createGain();
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(audioContext.destination);
|
||||
|
||||
if (type === \'success\') {
|
||||
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime);
|
||||
oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime + 0.1);
|
||||
oscillator.frequency.setValueAtTime(783.99, audioContext.currentTime + 0.2);
|
||||
} else {
|
||||
oscillator.frequency.setValueAtTime(200, audioContext.currentTime);
|
||||
}
|
||||
|
||||
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
|
||||
|
||||
oscillator.start();
|
||||
oscillator.stop(audioContext.currentTime + 0.3);
|
||||
}
|
||||
|
||||
// Initialize scanner when page loads
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
initScanner();
|
||||
startScanner();
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
391
src-backup/admin/dashboard.php
Normal file
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Admin Dashboard";
|
||||
|
||||
// Get statistics
|
||||
$stats = [];
|
||||
|
||||
// Total Students
|
||||
$sql = "SELECT COUNT(*) as total FROM students WHERE status = 1";
|
||||
$result = query($conn, $sql);
|
||||
$stats['total_students'] = mysqli_fetch_assoc($result)['total'];
|
||||
|
||||
// Total Users
|
||||
$sql = "SELECT COUNT(*) as total FROM users WHERE status = 1";
|
||||
$result = query($conn, $sql);
|
||||
$stats['total_users'] = mysqli_fetch_assoc($result)['total'];
|
||||
|
||||
// Upcoming Activities
|
||||
$sql = "SELECT COUNT(*) as total FROM activities WHERE status = 1 AND date >= CURDATE()";
|
||||
$result = query($conn, $sql);
|
||||
$stats['upcoming_activities'] = mysqli_fetch_assoc($result)['total'];
|
||||
|
||||
// Today's Attendance
|
||||
$sql = "SELECT COUNT(*) as total FROM attendance WHERE DATE(created_at) = CURDATE()";
|
||||
$result = query($conn, $sql);
|
||||
$stats['today_attendance'] = mysqli_fetch_assoc($result)['total'];
|
||||
|
||||
// Get recent attendance
|
||||
$recent_attendance = [];
|
||||
$sql = "
|
||||
SELECT a.*, s.full_name, s.student_id, ac.name as activity_name
|
||||
FROM attendance a
|
||||
JOIN students s ON a.student_id = s.id
|
||||
JOIN activities ac ON a.activity_id = ac.id
|
||||
ORDER BY a.created_at DESC
|
||||
LIMIT 10
|
||||
";
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$recent_attendance[] = $row;
|
||||
}
|
||||
|
||||
// Get upcoming activities
|
||||
$upcoming_activities = [];
|
||||
$sql = "
|
||||
SELECT * FROM activities
|
||||
WHERE date >= CURDATE() AND status = 1
|
||||
ORDER BY date ASC, time_in ASC
|
||||
LIMIT 5
|
||||
";
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$upcoming_activities[] = $row;
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">Dashboard Overview</h1>
|
||||
<p class="text-muted">Welcome back, <?php echo $_SESSION['full_name']; ?>! Here's what's happening today.</p>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-primary" onclick="window.print()">
|
||||
<i class="bi bi-printer me-2"></i> Print Report
|
||||
</button>
|
||||
<a href="attendance.php" class="btn btn-success">
|
||||
<i class="bi bi-qr-code-scan me-2"></i> Scan QR
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-primary">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-primary mb-1">Total Students</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['total_students']; ?></div>
|
||||
<div class="text-muted">Active enrolled</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-people-fill text-primary" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-success">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-success mb-1">System Users</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['total_users']; ?></div>
|
||||
<div class="text-muted">Admin & Teachers</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-person-badge-fill text-success" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-info">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-info mb-1">Upcoming Activities</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['upcoming_activities']; ?></div>
|
||||
<div class="text-muted">Scheduled events</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-calendar-event-fill text-info" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-warning">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-warning mb-1">Today's Attendance</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['today_attendance']; ?></div>
|
||||
<div class="text-muted">Records today</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-clock-history text-warning" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main Content Row -->
|
||||
<div class="row">
|
||||
<!-- Recent Attendance -->
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-clock-history me-2"></i> Recent Attendance
|
||||
</h6>
|
||||
<a href="reports.php" class="btn btn-sm btn-primary">View All</a>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="recentAttendance">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Student</th>
|
||||
<th>Activity</th>
|
||||
<th>Time In</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($recent_attendance)): ?>
|
||||
<tr>
|
||||
<td colspan="4" class="text-center py-4">
|
||||
<i class="bi bi-inbox text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No attendance records yet</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($recent_attendance as $attendance): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar me-3">
|
||||
<div class="bg-primary rounded-circle p-2 text-white">
|
||||
<i class="bi bi-person"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<strong><?php echo $attendance['full_name']; ?></strong><br>
|
||||
<small class="text-muted"><?php echo $attendance['student_id']; ?></small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo $attendance['activity_name']; ?></div>
|
||||
<small class="text-muted"><?php echo date('M d, Y', strtotime($attendance['created_at'])); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
if ($attendance['time_in']) {
|
||||
echo '<span class="badge bg-light text-dark">';
|
||||
echo '<i class="bi bi-clock me-1"></i>';
|
||||
echo date('h:i A', strtotime($attendance['time_in']));
|
||||
echo '</span>';
|
||||
} else {
|
||||
echo '<span class="badge bg-secondary">Pending</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$status = $attendance['status'] ?? 'pending';
|
||||
$badge_class = 'secondary';
|
||||
$icon = 'clock';
|
||||
|
||||
switch($status) {
|
||||
case 'present':
|
||||
$badge_class = 'success';
|
||||
$icon = 'check-circle';
|
||||
break;
|
||||
case 'late':
|
||||
$badge_class = 'warning';
|
||||
$icon = 'clock-history';
|
||||
break;
|
||||
case 'absent':
|
||||
$badge_class = 'danger';
|
||||
$icon = 'x-circle';
|
||||
break;
|
||||
case 'excused':
|
||||
$badge_class = 'info';
|
||||
$icon = 'calendar-check';
|
||||
break;
|
||||
default:
|
||||
$badge_class = 'secondary';
|
||||
$icon = 'clock';
|
||||
}
|
||||
?>
|
||||
<span class="badge bg-<?php echo $badge_class; ?>">
|
||||
<i class="bi bi-<?php echo $icon; ?> me-1"></i>
|
||||
<?php echo ucfirst($status); ?>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upcoming Activities -->
|
||||
<div class="col-lg-4">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-calendar-event me-2"></i> Upcoming Activities
|
||||
</h6>
|
||||
<a href="manage_activities.php" class="btn btn-sm btn-primary">View All</a>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="list-group list-group-flush">
|
||||
<?php if (empty($upcoming_activities)): ?>
|
||||
<div class="text-center py-4">
|
||||
<i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No upcoming activities</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($upcoming_activities as $activity): ?>
|
||||
<div class="list-group-item border-0 px-4 py-3">
|
||||
<div class="d-flex align-items-start">
|
||||
<div class="flex-shrink-0">
|
||||
<div class="calendar-icon bg-primary text-white rounded text-center p-2" style="width: 60px;">
|
||||
<div class="fw-bold" style="font-size: 1.5rem;"><?php echo date('d', strtotime($activity['date'])); ?></div>
|
||||
<div class="small"><?php echo date('M', strtotime($activity['date'])); ?></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-grow-1 ms-3">
|
||||
<h6 class="mb-1 fw-bold"><?php echo $activity['name']; ?></h6>
|
||||
<small class="text-muted d-block">
|
||||
<i class="bi bi-clock"></i>
|
||||
<?php echo date('h:i A', strtotime($activity['time_in'])) . ' - ' . date('h:i A', strtotime($activity['time_out'])); ?>
|
||||
</small>
|
||||
<small class="text-muted d-block">
|
||||
<i class="bi bi-geo-alt"></i> <?php echo $activity['location']; ?>
|
||||
</small>
|
||||
<div class="mt-2">
|
||||
<?php
|
||||
$activity_date = strtotime($activity['date'] . ' ' . $activity['time_in']);
|
||||
$current_time = time();
|
||||
|
||||
if ($current_time >= $activity_date) {
|
||||
echo '<span class="badge bg-success">Active Now</span>';
|
||||
} else {
|
||||
$days_diff = floor(($activity_date - $current_time) / (60 * 60 * 24));
|
||||
if ($days_diff == 0) {
|
||||
echo '<span class="badge bg-warning">Today</span>';
|
||||
} elseif ($days_diff == 1) {
|
||||
echo '<span class="badge bg-info">Tomorrow</span>';
|
||||
} else {
|
||||
echo '<span class="badge bg-secondary">In ' . $days_diff . ' days</span>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Stats -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-bar-chart me-2"></i> Quick Stats
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<?php
|
||||
// Calculate attendance percentage
|
||||
$percentage = $stats['total_students'] > 0 ?
|
||||
round(($stats['today_attendance'] / $stats['total_students']) * 100, 1) : 0;
|
||||
|
||||
// Get today's date for display
|
||||
$today = date('l, F j, Y');
|
||||
?>
|
||||
<h5 class="text-center mb-3"><?php echo $today; ?></h5>
|
||||
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span>Attendance Rate</span>
|
||||
<strong><?php echo $percentage; ?>%</strong>
|
||||
</div>
|
||||
<div class="progress" style="height: 10px;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar"
|
||||
style="width: <?php echo $percentage; ?>%"
|
||||
aria-valuenow="<?php echo $percentage; ?>"
|
||||
aria-valuemin="0"
|
||||
aria-valuemax="100">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row text-center">
|
||||
<div class="col-6">
|
||||
<div class="p-3 border rounded">
|
||||
<div class="h4 mb-1"><?php echo $stats['today_attendance']; ?></div>
|
||||
<small class="text-muted">Scanned Today</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<div class="p-3 border rounded">
|
||||
<div class="h4 mb-1"><?php echo $stats['total_students'] - $stats['today_attendance']; ?></div>
|
||||
<small class="text-muted">Remaining</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$("#recentAttendance").DataTable({
|
||||
pageLength: 5,
|
||||
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, "All"]],
|
||||
order: [[2, "desc"]],
|
||||
language: {
|
||||
search: "_INPUT_",
|
||||
searchPlaceholder: "Search attendance..."
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
';
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
171
src-backup/admin/deactivate_student.php
Normal file
@@ -0,0 +1,171 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Deactivate Student";
|
||||
|
||||
// Get student ID
|
||||
$student_id = intval($_GET['id'] ?? 0);
|
||||
|
||||
if ($student_id <= 0) {
|
||||
$_SESSION['message'] = 'Invalid student ID!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_students.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$status = $_POST['status'] == 'active' ? 1 : 0;
|
||||
$reason = !empty($_POST['reason']) ? mysqli_real_escape_string($conn, $_POST['reason']) : 'No reason provided';
|
||||
|
||||
// Update student status
|
||||
$sql = "UPDATE students SET
|
||||
status = ?,
|
||||
updated_at = NOW()
|
||||
WHERE id = ?";
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'ii', $status, $student_id);
|
||||
|
||||
if (mysqli_stmt_execute($stmt)) {
|
||||
// Log the status change (optional - if you have logs table)
|
||||
$log_sql = "INSERT INTO student_status_log (student_id, status, reason, changed_by, changed_at)
|
||||
VALUES (?, ?, ?, ?, NOW())";
|
||||
$log_stmt = mysqli_prepare($conn, $log_sql);
|
||||
mysqli_stmt_bind_param($log_stmt, 'iisi', $student_id, $status, $reason, $_SESSION['user_id']);
|
||||
mysqli_stmt_execute($log_stmt);
|
||||
mysqli_stmt_close($log_stmt);
|
||||
|
||||
$action = $status == 1 ? 'activated' : 'deactivated';
|
||||
$_SESSION['message'] = "Student $action successfully!";
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header('Location: manage_students.php?msg=updated');
|
||||
exit();
|
||||
} else {
|
||||
$_SESSION['message'] = 'Error updating student status: ' . mysqli_error($conn);
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_students.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
// Get student data
|
||||
$sql = "SELECT * FROM students WHERE id = ?";
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $student_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
|
||||
if (!$result || mysqli_num_rows($result) == 0) {
|
||||
$_SESSION['message'] = 'Student not found!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_students.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$student = mysqli_fetch_assoc($result);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2"><?php echo $student['status'] == 1 ? 'Deactivate' : 'Activate'; ?> Student</h1>
|
||||
<p class="text-muted">Change student account status.</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_students.php" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Students
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mx-auto">
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-person me-2"></i>
|
||||
Student: <?php echo htmlspecialchars($student['full_name']); ?>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>Note:</strong> <?php echo $student['status'] == 1 ? 'Deactivating' : 'Activating'; ?> a student will <?php echo $student['status'] == 1 ? 'prevent' : 'allow'; ?> them from accessing the system.
|
||||
</div>
|
||||
|
||||
<form method="POST" action="">
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Current Status</label>
|
||||
<div class="form-control bg-light">
|
||||
<?php if ($student['status'] == 1): ?>
|
||||
<span class="badge bg-success">
|
||||
<i class="bi bi-check-circle me-1"></i> Active
|
||||
</span>
|
||||
<small class="text-muted ms-2">- Student can login and access system</small>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">
|
||||
<i class="bi bi-x-circle me-1"></i> Inactive
|
||||
</span>
|
||||
<small class="text-muted ms-2">- Student cannot login</small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Change Status To</label>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="radio" name="status"
|
||||
value="active" id="statusActive"
|
||||
<?php echo $student['status'] == 0 ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="statusActive">
|
||||
<span class="badge bg-success">Active</span>
|
||||
<small class="text-muted d-block mt-1">Student can login and use all features</small>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="status"
|
||||
value="inactive" id="statusInactive"
|
||||
<?php echo $student['status'] == 1 ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="statusInactive">
|
||||
<span class="badge bg-danger">Inactive</span>
|
||||
<small class="text-muted d-block mt-1">Student cannot login to the system</small>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Reason for Change <span class="text-muted">(Optional)</span></label>
|
||||
<textarea class="form-control" name="reason" rows="3"
|
||||
placeholder="Enter reason for status change..."></textarea>
|
||||
<small class="text-muted">This will be logged for audit purposes.</small>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save me-1"></i> Update Status
|
||||
</button>
|
||||
<a href="manage_students.php" class="btn btn-secondary">Cancel</a>
|
||||
<a href="delete_student.php?id=<?php echo $student['id']; ?>"
|
||||
class="btn btn-outline-danger float-end">
|
||||
<i class="bi bi-trash me-1"></i> Delete Instead
|
||||
</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
287
src-backup/admin/edit_activity.php
Normal file
@@ -0,0 +1,287 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Edit Activity";
|
||||
|
||||
// Get activity ID
|
||||
$activity_id = $_GET['id'] ?? 0;
|
||||
|
||||
if ($activity_id <= 0) {
|
||||
$_SESSION['message'] = 'Invalid activity ID!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_activities.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get activity data
|
||||
$sql = "SELECT * FROM activities WHERE id = $activity_id";
|
||||
$result = query($conn, $sql);
|
||||
if (!$result || mysqli_num_rows($result) == 0) {
|
||||
$_SESSION['message'] = 'Activity not found!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_activities.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$activity = mysqli_fetch_assoc($result);
|
||||
|
||||
// Initialize variables
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
// Validate required fields
|
||||
$required_fields = ['name', 'date', 'time_in', 'time_out', 'location', 'required_students'];
|
||||
$valid = true;
|
||||
|
||||
foreach ($required_fields as $field) {
|
||||
if (empty($_POST[$field])) {
|
||||
$message = "Please fill all required fields!";
|
||||
$message_type = 'danger';
|
||||
$valid = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
$activity_data = [
|
||||
'name' => escape($conn, $_POST['name']),
|
||||
'date' => $_POST['date'],
|
||||
'time_in' => $_POST['time_in'],
|
||||
'time_out' => $_POST['time_out'],
|
||||
'description' => escape($conn, $_POST['description']),
|
||||
'location' => escape($conn, $_POST['location']),
|
||||
'required_students' => $_POST['required_students'],
|
||||
'course_id' => $_POST['course_id'] ? intval($_POST['course_id']) : null,
|
||||
'department_id' => $_POST['department_id'] ? intval($_POST['department_id']) : null,
|
||||
'status' => isset($_POST['status']) ? 1 : 0
|
||||
];
|
||||
|
||||
// Validate time
|
||||
if (strtotime($activity_data['time_out']) <= strtotime($activity_data['time_in'])) {
|
||||
$message = 'Time Out must be later than Time In!';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
$sql = "UPDATE activities SET
|
||||
name = '{$activity_data['name']}',
|
||||
date = '{$activity_data['date']}',
|
||||
time_in = '{$activity_data['time_in']}',
|
||||
time_out = '{$activity_data['time_out']}',
|
||||
description = '{$activity_data['description']}',
|
||||
location = '{$activity_data['location']}',
|
||||
required_students = '{$activity_data['required_students']}',
|
||||
course_id = " . ($activity_data['course_id'] ? $activity_data['course_id'] : 'NULL') . ",
|
||||
department_id = " . ($activity_data['department_id'] ? $activity_data['department_id'] : 'NULL') . ",
|
||||
status = {$activity_data['status']},
|
||||
updated_at = NOW()
|
||||
WHERE id = $activity_id";
|
||||
|
||||
if (query($conn, $sql)) {
|
||||
$_SESSION['message'] = 'Activity updated successfully!';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header('Location: manage_activities.php');
|
||||
exit();
|
||||
} else {
|
||||
$message = 'Error updating activity: ' . mysqli_error($conn);
|
||||
$message_type = 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get dropdown data
|
||||
$courses = [];
|
||||
$departments = [];
|
||||
|
||||
// Courses
|
||||
$result = query($conn, "SELECT * FROM courses WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$courses[] = $row;
|
||||
}
|
||||
|
||||
// Departments
|
||||
$result = query($conn, "SELECT * FROM departments WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$departments[] = $row;
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">Edit Activity</h1>
|
||||
<p class="text-muted">Update activity details.</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_activities.php" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Activities
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show">
|
||||
<?php echo $message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Edit Activity Form -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0">
|
||||
<i class="bi bi-pencil me-2"></i> Edit Activity: <?php echo $activity['name']; ?>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="" id="editActivityForm">
|
||||
<input type="hidden" name="activity_id" value="<?php echo $activity['id']; ?>">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Activity Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="name" required
|
||||
value="<?php echo htmlspecialchars($activity['name']); ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Date <span class="text-danger">*</span></label>
|
||||
<input type="date" class="form-control" name="date" required
|
||||
value="<?php echo $activity['date']; ?>">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">Time In <span class="text-danger">*</span></label>
|
||||
<input type="time" class="form-control" name="time_in" required
|
||||
value="<?php echo $activity['time_in']; ?>">
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">Time Out <span class="text-danger">*</span></label>
|
||||
<input type="time" class="form-control" name="time_out" required
|
||||
value="<?php echo $activity['time_out']; ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Location <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="location" required
|
||||
value="<?php echo htmlspecialchars($activity['location']); ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea class="form-control" name="description" rows="3"><?php echo htmlspecialchars($activity['description']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12 mb-3">
|
||||
<label class="form-label">Participants <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="required_students" required id="participantType" onchange="toggleParticipantSelection()">
|
||||
<option value="all" <?php echo $activity['required_students'] == 'all' ? 'selected' : ''; ?>>All Students</option>
|
||||
<option value="specific_course" <?php echo $activity['required_students'] == 'specific_course' ? 'selected' : ''; ?>>Specific Course</option>
|
||||
<option value="specific_department" <?php echo $activity['required_students'] == 'specific_department' ? 'selected' : ''; ?>>Specific Department</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3" id="courseSelection" style="<?php echo $activity['required_students'] == 'specific_course' ? '' : 'display: none;'; ?>">
|
||||
<label class="form-label">Select Course</label>
|
||||
<select class="form-select" name="course_id" id="courseSelect">
|
||||
<option value="">Select Course</option>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<option value="<?php echo $course['id']; ?>"
|
||||
<?php echo $activity['course_id'] == $course['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $course['code']; ?> - <?php echo $course['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3" id="departmentSelection" style="<?php echo $activity['required_students'] == 'specific_department' ? '' : 'display: none;'; ?>">
|
||||
<label class="form-label">Select Department</label>
|
||||
<select class="form-select" name="department_id" id="departmentSelect">
|
||||
<option value="">Select Department</option>
|
||||
<?php foreach ($departments as $department): ?>
|
||||
<option value="<?php echo $department['id']; ?>"
|
||||
<?php echo $activity['department_id'] == $department['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $department['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch"
|
||||
name="status" id="statusSwitch" value="1"
|
||||
<?php echo $activity['status'] == 1 ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="statusSwitch">
|
||||
Active Activity
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-save me-1"></i> Update Activity
|
||||
</button>
|
||||
<a href="manage_activities.php" class="btn btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
function toggleParticipantSelection() {
|
||||
const participantType = document.getElementById("participantType").value;
|
||||
const courseSelection = document.getElementById("courseSelection");
|
||||
const departmentSelection = document.getElementById("departmentSelection");
|
||||
|
||||
if (participantType === "specific_course") {
|
||||
courseSelection.style.display = "block";
|
||||
departmentSelection.style.display = "none";
|
||||
document.getElementById("courseSelect").required = true;
|
||||
document.getElementById("departmentSelect").required = false;
|
||||
} else if (participantType === "specific_department") {
|
||||
courseSelection.style.display = "none";
|
||||
departmentSelection.style.display = "block";
|
||||
document.getElementById("courseSelect").required = false;
|
||||
document.getElementById("departmentSelect").required = true;
|
||||
} else {
|
||||
courseSelection.style.display = "none";
|
||||
departmentSelection.style.display = "none";
|
||||
document.getElementById("courseSelect").required = false;
|
||||
document.getElementById("departmentSelect").required = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Time validation
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// Initialize participant selection
|
||||
toggleParticipantSelection();
|
||||
|
||||
document.getElementById("editActivityForm").addEventListener("submit", function(e) {
|
||||
const timeIn = document.querySelector("input[name=\'time_in\']").value;
|
||||
const timeOut = document.querySelector("input[name=\'time_out\']").value;
|
||||
|
||||
if (timeIn && timeOut && timeOut <= timeIn) {
|
||||
e.preventDefault();
|
||||
alert("Time Out must be later than Time In!");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
577
src-backup/admin/edit_student.php
Normal file
@@ -0,0 +1,577 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Production: suppress display errors to avoid header issues
|
||||
ini_set('display_errors', 0);
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Edit Student";
|
||||
|
||||
// Initialize variables
|
||||
$student_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
// Get student data
|
||||
$student = null;
|
||||
if ($student_id > 0) {
|
||||
$sql = "SELECT s.*, g.name as gender_name, c.code as course_code, c.name as course_name,
|
||||
d.code as department_code, d.name as department_name,
|
||||
sc.code as school_code, sc.name as school_name
|
||||
FROM students s
|
||||
LEFT JOIN genders g ON s.gender_id = g.id
|
||||
LEFT JOIN courses c ON s.course_id = c.id
|
||||
LEFT JOIN departments d ON s.department_id = d.id
|
||||
LEFT JOIN schools sc ON s.school_id = sc.id
|
||||
WHERE s.id = ?";
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $student_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
|
||||
if ($result && mysqli_num_rows($result) > 0) {
|
||||
$student = mysqli_fetch_assoc($result);
|
||||
} else {
|
||||
$_SESSION['message'] = 'Student not found!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_students.php');
|
||||
exit();
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
} else {
|
||||
$_SESSION['message'] = 'Invalid student ID!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_students.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get dropdown data
|
||||
$genders = [];
|
||||
$courses = [];
|
||||
$departments = [];
|
||||
$schools = [];
|
||||
|
||||
// Genders
|
||||
$result = mysqli_query($conn, "SELECT * FROM genders ORDER BY id");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$genders[] = $row;
|
||||
}
|
||||
|
||||
// Courses
|
||||
$result = mysqli_query($conn, "SELECT * FROM courses WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$courses[] = $row;
|
||||
}
|
||||
|
||||
// Departments
|
||||
$result = mysqli_query($conn, "SELECT * FROM departments WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$departments[] = $row;
|
||||
}
|
||||
|
||||
// Schools
|
||||
$result = mysqli_query($conn, "SELECT * FROM schools WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$schools[] = $row;
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['update_student'])) {
|
||||
// Prefer POSTed id if present
|
||||
$student_id = isset($_POST['id']) ? intval($_POST['id']) : $student_id;
|
||||
|
||||
$student_data = [
|
||||
'student_id' => mysqli_real_escape_string($conn, trim($_POST['student_id'])),
|
||||
'full_name' => mysqli_real_escape_string($conn, trim($_POST['full_name'])),
|
||||
'gender_id' => intval($_POST['gender_id']),
|
||||
'year_level' => intval($_POST['year_level']),
|
||||
'course_id' => intval($_POST['course_id']),
|
||||
'department_id' => intval($_POST['department_id']),
|
||||
'school_id' => intval($_POST['school_id']),
|
||||
'birth_date' => (isset($_POST['birth_date']) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $_POST['birth_date']) && $_POST['birth_date'] !== '0000-00-00') ? mysqli_real_escape_string($conn, $_POST['birth_date']) : NULL,
|
||||
'contact_number' => mysqli_real_escape_string($conn, trim($_POST['contact_number'])),
|
||||
'email' => mysqli_real_escape_string($conn, trim($_POST['email'])),
|
||||
'address' => mysqli_real_escape_string($conn, trim($_POST['address'])),
|
||||
'status' => isset($_POST['status']) ? 1 : 0
|
||||
];
|
||||
|
||||
// Validate required fields
|
||||
$required_fields = ['student_id', 'full_name', 'gender_id', 'year_level', 'course_id', 'department_id', 'school_id'];
|
||||
$valid = true;
|
||||
|
||||
foreach ($required_fields as $field) {
|
||||
if (empty($student_data[$field])) {
|
||||
$valid = false;
|
||||
$message = "Missing required field: $field";
|
||||
$message_type = 'danger';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Validate email format if provided
|
||||
if ($valid && !empty($student_data['email']) && !filter_var($student_data['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
$valid = false;
|
||||
$message = 'Please enter a valid email address.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
|
||||
// Check for duplicate student ID (excluding current student)
|
||||
if ($valid) {
|
||||
$check_sql = "SELECT id FROM students WHERE student_id = ? AND id != ?";
|
||||
$stmt = mysqli_prepare($conn, $check_sql);
|
||||
mysqli_stmt_bind_param($stmt, 'si', $student_data['student_id'], $student_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
mysqli_stmt_store_result($stmt);
|
||||
|
||||
if (mysqli_stmt_num_rows($stmt) > 0) {
|
||||
$message = 'Student ID already exists. Please use a different Student ID.';
|
||||
$message_type = 'danger';
|
||||
$valid = false;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
// Build SQL query allowing NULLs for optional fields
|
||||
$setParts = [
|
||||
'student_id = ?', 'full_name = ?', 'gender_id = ?', 'year_level = ?',
|
||||
'course_id = ?', 'department_id = ?', 'school_id = ?', 'status = ?', 'updated_at = NOW()'
|
||||
];
|
||||
$types = 'ssiiiiii';
|
||||
$params = [
|
||||
$student_data['student_id'],
|
||||
$student_data['full_name'],
|
||||
$student_data['gender_id'],
|
||||
$student_data['year_level'],
|
||||
$student_data['course_id'],
|
||||
$student_data['department_id'],
|
||||
$student_data['school_id'],
|
||||
$student_data['status']
|
||||
];
|
||||
|
||||
// Optional fields: set to NULL when empty
|
||||
if (!empty($student_data['birth_date'])) {
|
||||
$setParts[] = 'birth_date = ?';
|
||||
$types .= 's';
|
||||
$params[] = $student_data['birth_date'];
|
||||
} else {
|
||||
$setParts[] = 'birth_date = NULL';
|
||||
}
|
||||
if (!empty($student_data['contact_number'])) {
|
||||
$setParts[] = 'contact_number = ?';
|
||||
$types .= 's';
|
||||
$params[] = $student_data['contact_number'];
|
||||
} else {
|
||||
$setParts[] = 'contact_number = NULL';
|
||||
}
|
||||
if (!empty($student_data['email'])) {
|
||||
$setParts[] = 'email = ?';
|
||||
$types .= 's';
|
||||
$params[] = $student_data['email'];
|
||||
} else {
|
||||
$setParts[] = 'email = NULL';
|
||||
}
|
||||
if (!empty($student_data['address'])) {
|
||||
$setParts[] = 'address = ?';
|
||||
$types .= 's';
|
||||
$params[] = $student_data['address'];
|
||||
} else {
|
||||
$setParts[] = 'address = NULL';
|
||||
}
|
||||
|
||||
$sql = 'UPDATE students SET ' . implode(', ', $setParts) . ' WHERE id = ?';
|
||||
$types .= 'i';
|
||||
$params[] = $student_id;
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
if (!$stmt) {
|
||||
$message = 'Error preparing update: ' . mysqli_error($conn);
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
mysqli_stmt_bind_param($stmt, $types, ...$params);
|
||||
|
||||
if (mysqli_stmt_execute($stmt)) {
|
||||
$_SESSION['message'] = 'Student updated successfully!';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header("Location: view_student.php?id=$student_id");
|
||||
exit();
|
||||
} else {
|
||||
$error_msg = mysqli_error($conn);
|
||||
$message = 'Error updating student: ' . $error_msg;
|
||||
$message_type = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">
|
||||
<i class="bi bi-pencil-square me-2"></i> Edit Student
|
||||
</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="dashboard.php">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="manage_students.php">Manage Students</a></li>
|
||||
<li class="breadcrumb-item active">Edit Student</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_students.php" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Students
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-<?php echo $message_type == 'success' ? 'check-circle' : 'exclamation-triangle'; ?> me-2"></i>
|
||||
<?php echo $message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($student): ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<!-- Edit Form Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-person-lines-fill me-2"></i> Student Information
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" action="" id="editStudentForm">
|
||||
<input type="hidden" name="id" value="<?php echo $student_id; ?>">
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Student ID <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="student_id" required
|
||||
value="<?php echo htmlspecialchars($student['student_id']); ?>"
|
||||
maxlength="50" id="student_id_field">
|
||||
<div class="form-text">Unique student identification number</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Full Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control" name="full_name" required
|
||||
value="<?php echo htmlspecialchars($student['full_name']); ?>"
|
||||
maxlength="100" id="full_name_field">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Gender <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="gender_id" required id="gender_id_field">
|
||||
<option value="">Select Gender</option>
|
||||
<?php foreach ($genders as $gender): ?>
|
||||
<option value="<?php echo $gender['id']; ?>"
|
||||
<?php echo $student['gender_id'] == $gender['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($gender['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Year Level <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="year_level" required id="year_level_field">
|
||||
<option value="">Select Year Level</option>
|
||||
<?php for ($i = 1; $i <= 4; $i++): ?>
|
||||
<option value="<?php echo $i; ?>"
|
||||
<?php echo $student['year_level'] == $i ? 'selected' : ''; ?>>
|
||||
Year <?php echo $i; ?>
|
||||
</option>
|
||||
<?php endfor; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">School <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="school_id" required id="school_id_field">
|
||||
<option value="">Select School</option>
|
||||
<?php foreach ($schools as $school): ?>
|
||||
<option value="<?php echo $school['id']; ?>"
|
||||
<?php echo $student['school_id'] == $school['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($school['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Department <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="department_id" required id="department_id_field">
|
||||
<option value="">Select Department</option>
|
||||
<?php foreach ($departments as $department): ?>
|
||||
<option value="<?php echo $department['id']; ?>"
|
||||
<?php echo $student['department_id'] == $department['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($department['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Course <span class="text-danger">*</span></label>
|
||||
<select class="form-select" name="course_id" required id="course_id_field">
|
||||
<option value="">Select Course</option>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<option value="<?php echo $course['id']; ?>"
|
||||
<?php echo $student['course_id'] == $course['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo htmlspecialchars($course['code']); ?> - <?php echo htmlspecialchars($course['name']); ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Birth Date</label>
|
||||
<input type="date" class="form-control" name="birth_date"
|
||||
value="<?php echo $student['birth_date']; ?>"
|
||||
max="<?php echo date('Y-m-d'); ?>" id="birth_date_field">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Email Address</label>
|
||||
<input type="email" class="form-control" name="email"
|
||||
value="<?php echo htmlspecialchars($student['email']); ?>"
|
||||
maxlength="100" id="email_field">
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<label class="form-label">Contact Number</label>
|
||||
<input type="tel" class="form-control" name="contact_number"
|
||||
value="<?php echo htmlspecialchars($student['contact_number']); ?>"
|
||||
id="contact_number_field">
|
||||
</div>
|
||||
|
||||
<div class="col-12 mb-3">
|
||||
<label class="form-label">Address</label>
|
||||
<textarea class="form-control" name="address" rows="3"
|
||||
maxlength="255" id="address_field"><?php echo htmlspecialchars($student['address']); ?></textarea>
|
||||
</div>
|
||||
|
||||
<div class="col-12 mb-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" role="switch"
|
||||
name="status" id="statusSwitch" value="1"
|
||||
<?php echo $student['status'] == 1 ? 'checked' : ''; ?>>
|
||||
<label class="form-check-label" for="statusSwitch">
|
||||
Active Student
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between mt-4">
|
||||
<a href="view_student.php?id=<?php echo $student_id; ?>" class="btn btn-secondary">
|
||||
<i class="bi bi-x-circle me-2"></i> Cancel
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary" name="update_student" id="submitBtn">
|
||||
<i class="bi bi-save me-2"></i> Update Student
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<!-- Student Summary Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-person-badge me-2"></i> Student Summary
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="text-center mb-4">
|
||||
<?php if (!empty($student['picture_path'])): ?>
|
||||
<img src="../<?php echo htmlspecialchars($student['picture_path']); ?>"
|
||||
alt="Student Photo" class="rounded-circle mb-3"
|
||||
style="width: 120px; height: 120px; object-fit: cover;">
|
||||
<?php else: ?>
|
||||
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center mx-auto mb-3"
|
||||
style="width: 120px; height: 120px;">
|
||||
<i class="bi bi-person" style="font-size: 3rem; color: white;"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h5><?php echo htmlspecialchars($student['full_name']); ?></h5>
|
||||
<p class="text-muted"><?php echo htmlspecialchars($student['student_id']); ?></p>
|
||||
|
||||
<div class="mb-3">
|
||||
<?php if ($student['status'] == 1): ?>
|
||||
<span class="badge bg-success">
|
||||
<i class="bi bi-check-circle me-1"></i> Active
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">
|
||||
<i class="bi bi-x-circle me-1"></i> Inactive
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="list-group list-group-flush">
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span>Gender</span>
|
||||
<span><?php echo htmlspecialchars($student['gender_name']); ?></span>
|
||||
</div>
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span>Course</span>
|
||||
<span class="fw-bold"><?php echo htmlspecialchars($student['course_code']); ?></span>
|
||||
</div>
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span>Year Level</span>
|
||||
<span class="badge bg-info">Year <?php echo $student['year_level']; ?></span>
|
||||
</div>
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span>Department</span>
|
||||
<span><?php echo htmlspecialchars($student['department_name']); ?></span>
|
||||
</div>
|
||||
<div class="list-group-item d-flex justify-content-between align-items-center">
|
||||
<span>School</span>
|
||||
<span><?php echo htmlspecialchars($student['school_name']); ?></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
<!-- Student Not Found -->
|
||||
<div class="card shadow">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="bi bi-person-x" style="font-size: 4rem; color: #dc3545;"></i>
|
||||
<h3 class="mt-3">Student Not Found</h3>
|
||||
<p class="text-muted">The student you're trying to edit does not exist or has been deleted.</p>
|
||||
<a href="manage_students.php" class="btn btn-primary mt-3">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Students List
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
function validateEditForm() {
|
||||
console.log("Validating form...");
|
||||
|
||||
// Get form values
|
||||
const studentId = document.getElementById("student_id_field").value.trim();
|
||||
const fullName = document.getElementById("full_name_field").value.trim();
|
||||
const genderId = document.getElementById("gender_id_field").value;
|
||||
const yearLevel = document.getElementById("year_level_field").value;
|
||||
const schoolId = document.getElementById("school_id_field").value;
|
||||
const departmentId = document.getElementById("department_id_field").value;
|
||||
const courseId = document.getElementById("course_id_field").value;
|
||||
const email = document.getElementById("email_field").value.trim();
|
||||
|
||||
// Check required fields
|
||||
if (!studentId) {
|
||||
alert("Please enter Student ID");
|
||||
document.getElementById("student_id_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!fullName) {
|
||||
alert("Please enter Full Name");
|
||||
document.getElementById("full_name_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!genderId) {
|
||||
alert("Please select Gender");
|
||||
document.getElementById("gender_id_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!yearLevel) {
|
||||
alert("Please select Year Level");
|
||||
document.getElementById("year_level_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!schoolId) {
|
||||
alert("Please select School");
|
||||
document.getElementById("school_id_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!departmentId) {
|
||||
alert("Please select Department");
|
||||
document.getElementById("department_id_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!courseId) {
|
||||
alert("Please select Course");
|
||||
document.getElementById("course_id_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate email format if provided
|
||||
if (email && !isValidEmail(email)) {
|
||||
alert("Please enter a valid email address");
|
||||
document.getElementById("email_field").focus();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Show loading state
|
||||
document.getElementById("submitBtn").innerHTML = \'<i class="bi bi-hourglass-split me-2"></i> Updating...\';
|
||||
document.getElementById("submitBtn").disabled = true;
|
||||
|
||||
console.log("Form validation passed");
|
||||
return true;
|
||||
}
|
||||
|
||||
function isValidEmail(email) {
|
||||
const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
// Debug form submission
|
||||
document.getElementById("editStudentForm").addEventListener("submit", function(e) {
|
||||
console.log("Form submitted");
|
||||
console.log("Form action:", this.action);
|
||||
console.log("Form method:", this.method);
|
||||
|
||||
const formData = new FormData(this);
|
||||
console.log("Form data:");
|
||||
for (let [key, value] of formData.entries()) {
|
||||
console.log(key + ": " + value);
|
||||
}
|
||||
});
|
||||
|
||||
// Check if form elements exist
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
console.log("DOM loaded");
|
||||
console.log("Form exists:", document.getElementById("editStudentForm") !== null);
|
||||
console.log("Submit button exists:", document.getElementById("submitBtn") !== null);
|
||||
|
||||
// Test form submission via JavaScript
|
||||
document.getElementById("editStudentForm").onsubmit = function() {
|
||||
console.log("Form onsubmit fired");
|
||||
return validateEditForm();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
33
src-backup/admin/get_user.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../includes/database.php';
|
||||
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||
echo json_encode(['success' => false, 'message' => 'Unauthorized']);
|
||||
exit();
|
||||
}
|
||||
|
||||
if (!isset($_GET['id'])) {
|
||||
echo json_encode(['success' => false, 'message' => 'User ID required']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$user_id = (int)$_GET['id'];
|
||||
|
||||
try {
|
||||
$query = "SELECT * FROM users WHERE id = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$user_id]);
|
||||
$user = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||
|
||||
if ($user) {
|
||||
// Remove password from response
|
||||
unset($user['password']);
|
||||
echo json_encode(['success' => true, 'user' => $user]);
|
||||
} else {
|
||||
echo json_encode(['success' => false, 'message' => 'User not found']);
|
||||
}
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
|
||||
}
|
||||
?>
|
||||
847
src-backup/admin/manage_activities.php
Normal file
@@ -0,0 +1,847 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Manage Activities";
|
||||
|
||||
// Handle AJAX deletion
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ajax_delete'])) {
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// CSRF check disabled per configuration
|
||||
|
||||
$activity_id = intval($_POST['activity_id'] ?? 0);
|
||||
|
||||
if ($activity_id <= 0) {
|
||||
echo json_encode(['success' => false, 'message' => 'Invalid activity ID']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if activity exists
|
||||
$check_sql = "SELECT id, name, date, time_in, time_out FROM activities WHERE id = ?";
|
||||
$check_stmt = mysqli_prepare($conn, $check_sql);
|
||||
mysqli_stmt_bind_param($check_stmt, "i", $activity_id);
|
||||
mysqli_stmt_execute($check_stmt);
|
||||
$result = mysqli_stmt_get_result($check_stmt);
|
||||
$activity = mysqli_fetch_assoc($result);
|
||||
|
||||
if (!$activity) {
|
||||
echo json_encode(['success' => false, 'message' => 'Activity not found']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if activity is currently ongoing
|
||||
$today = date('Y-m-d');
|
||||
$current_time = date('H:i:s');
|
||||
|
||||
if ($activity['date'] == $today &&
|
||||
$current_time >= $activity['time_in'] &&
|
||||
$current_time <= $activity['time_out']) {
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Cannot delete an activity that is currently ongoing. Please wait until it ends.'
|
||||
]);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Start transaction
|
||||
mysqli_begin_transaction($conn);
|
||||
|
||||
try {
|
||||
// Get attendance count for logging
|
||||
$attendance_count_sql = "SELECT COUNT(*) as count FROM attendance WHERE activity_id = ?";
|
||||
$attendance_stmt = mysqli_prepare($conn, $attendance_count_sql);
|
||||
mysqli_stmt_bind_param($attendance_stmt, "i", $activity_id);
|
||||
mysqli_stmt_execute($attendance_stmt);
|
||||
$attendance_result = mysqli_stmt_get_result($attendance_stmt);
|
||||
$attendance_count = mysqli_fetch_assoc($attendance_result)['count'];
|
||||
|
||||
// First, delete attendance records
|
||||
$delete_attendance_sql = "DELETE FROM attendance WHERE activity_id = ?";
|
||||
$stmt1 = mysqli_prepare($conn, $delete_attendance_sql);
|
||||
mysqli_stmt_bind_param($stmt1, "i", $activity_id);
|
||||
$attendance_deleted = mysqli_stmt_execute($stmt1);
|
||||
|
||||
if (!$attendance_deleted) {
|
||||
throw new Exception('Failed to delete attendance records');
|
||||
}
|
||||
|
||||
// Then delete the activity
|
||||
$delete_activity_sql = "DELETE FROM activities WHERE id = ?";
|
||||
$stmt2 = mysqli_prepare($conn, $delete_activity_sql);
|
||||
mysqli_stmt_bind_param($stmt2, "i", $activity_id);
|
||||
$activity_deleted = mysqli_stmt_execute($stmt2);
|
||||
|
||||
if (!$activity_deleted) {
|
||||
throw new Exception('Failed to delete activity');
|
||||
}
|
||||
|
||||
// Commit transaction
|
||||
mysqli_commit($conn);
|
||||
|
||||
// Log the deletion
|
||||
$log_message = "Activity deleted via AJAX: '{$activity['name']}' (ID: {$activity_id}). ";
|
||||
$log_message .= "Deleted {$attendance_count} attendance records.";
|
||||
log_action($conn, $_SESSION['user_id'], 'delete_activity', $log_message);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Activity deleted successfully!',
|
||||
'deleted_id' => $activity_id,
|
||||
'attendance_count' => $attendance_count
|
||||
]);
|
||||
|
||||
} catch (Exception $e) {
|
||||
mysqli_rollback($conn);
|
||||
echo json_encode([
|
||||
'success' => false,
|
||||
'message' => 'Error: ' . $e->getMessage()
|
||||
]);
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
// Generate CSRF token for this page
|
||||
$csrf_token = bin2hex(random_bytes(32));
|
||||
$_SESSION['csrf_token'] = $csrf_token;
|
||||
|
||||
// Get all activities with related data
|
||||
$activities = [];
|
||||
$sql = "SELECT a.*, u.full_name as created_by_name,
|
||||
c.code as course_code, c.name as course_name,
|
||||
d.code as department_code, d.name as department_name
|
||||
FROM activities a
|
||||
LEFT JOIN users u ON a.created_by = u.id
|
||||
LEFT JOIN courses c ON a.course_id = c.id
|
||||
LEFT JOIN departments d ON a.department_id = d.id
|
||||
ORDER BY a.date DESC, a.time_in ASC";
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$activities[] = $row;
|
||||
}
|
||||
|
||||
// Statistics calculation
|
||||
$today = date('Y-m-d');
|
||||
$upcoming_count = 0;
|
||||
$ongoing_count = 0;
|
||||
$past_count = 0;
|
||||
|
||||
foreach ($activities as $activity) {
|
||||
$activity_date = $activity['date'];
|
||||
$current_time = date('H:i:s');
|
||||
$activity_start = $activity['time_in'];
|
||||
$activity_end = $activity['time_out'];
|
||||
|
||||
if ($activity_date > $today) {
|
||||
$upcoming_count++;
|
||||
} elseif ($activity_date == $today && $current_time >= $activity_start && $current_time <= $activity_end) {
|
||||
$ongoing_count++;
|
||||
} elseif ($activity_date < $today || ($activity_date == $today && $current_time > $activity_end)) {
|
||||
$past_count++;
|
||||
}
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">Manage Activities</h1>
|
||||
<p class="text-muted">Schedule and manage activities, events, and classes.</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="add_activity.php" class="btn btn-primary">
|
||||
<i class="bi bi-calendar-plus me-2"></i> Schedule New Activity
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if (isset($_SESSION['success_message'])): ?>
|
||||
<div class="alert alert-success alert-dismissible fade show" role="alert">
|
||||
<?php echo $_SESSION['success_message']; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php unset($_SESSION['success_message']); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (isset($_SESSION['error_message'])): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<?php echo $_SESSION['error_message']; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php unset($_SESSION['error_message']); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="messageAlert" class="alert" style="display: none;"></div>
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-primary">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-primary mb-1">Total Activities</div>
|
||||
<div class="h2 font-weight-bold" id="totalCount"><?php echo count($activities); ?></div>
|
||||
<div class="text-muted">All scheduled</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-calendar-check-fill text-primary" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-success">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-success mb-1">Upcoming</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $upcoming_count; ?></div>
|
||||
<div class="text-muted">Future activities</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-calendar-event-fill text-success" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-info">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-info mb-1">Ongoing</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $ongoing_count; ?></div>
|
||||
<div class="text-muted">Happening now</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-clock-history text-info" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-warning">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-warning mb-1">Past Activities</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $past_count; ?></div>
|
||||
<div class="text-muted">Completed</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-calendar-x-fill text-warning" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activity Tabs -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs" id="activityTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="upcoming-tab" data-bs-toggle="tab"
|
||||
data-bs-target="#upcoming" type="button" role="tab">
|
||||
<i class="bi bi-calendar-event me-1"></i> Upcoming
|
||||
<span class="badge bg-primary ms-1" id="upcomingBadge"><?php echo $upcoming_count; ?></span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="ongoing-tab" data-bs-toggle="tab"
|
||||
data-bs-target="#ongoing" type="button" role="tab">
|
||||
<i class="bi bi-clock-history me-1"></i> Ongoing
|
||||
<span class="badge bg-success ms-1"><?php echo $ongoing_count; ?></span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="past-tab" data-bs-toggle="tab"
|
||||
data-bs-target="#past" type="button" role="tab">
|
||||
<i class="bi bi-calendar-x me-1"></i> Past
|
||||
<span class="badge bg-secondary ms-1"><?php echo $past_count; ?></span>
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="all-tab" data-bs-toggle="tab"
|
||||
data-bs-target="#all" type="button" role="tab">
|
||||
<i class="bi bi-list-ul me-1"></i> All Activities
|
||||
<span class="badge bg-info ms-1"><?php echo count($activities); ?></span>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content" id="activityTabsContent">
|
||||
<!-- Upcoming Activities Tab -->
|
||||
<div class="tab-pane fade show active" id="upcoming" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="upcomingTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Activity</th>
|
||||
<th>Date & Time</th>
|
||||
<th>Location</th>
|
||||
<th>Participants</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$has_upcoming = false;
|
||||
foreach ($activities as $activity):
|
||||
if ($activity['date'] > $today || ($activity['date'] == $today && date('H:i:s') < $activity['time_in'])):
|
||||
$has_upcoming = true;
|
||||
?>
|
||||
<tr id="activityRow-<?php echo $activity['id']; ?>">
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($activity['name']); ?></strong><br>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($activity['description'] ? substr($activity['description'], 0, 50) . '...' : 'No description'); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo date('M d, Y', strtotime($activity['date'])); ?></div>
|
||||
<small class="text-muted">
|
||||
<?php echo date('h:i A', strtotime($activity['time_in'])); ?> -
|
||||
<?php echo date('h:i A', strtotime($activity['time_out'])); ?>
|
||||
</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark">
|
||||
<i class="bi bi-geo-alt me-1"></i> <?php echo htmlspecialchars($activity['location']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
switch($activity['required_students']) {
|
||||
case 'all': echo '<span class="badge bg-info">All Students</span>'; break;
|
||||
case 'specific_course':
|
||||
echo '<span class="badge bg-warning">' . htmlspecialchars($activity['course_code'] ?? 'Specific Course') . '</span>';
|
||||
break;
|
||||
case 'specific_department':
|
||||
echo '<span class="badge bg-primary">' . htmlspecialchars($activity['department_name'] ?? 'Specific Department') . '</span>';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($activity['status'] == 1): ?>
|
||||
<span class="badge bg-success">Active</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">Inactive</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="view_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-info" title="View">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
<a href="edit_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-warning" title="Edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-danger delete-activity-btn"
|
||||
data-id="<?php echo $activity['id']; ?>"
|
||||
data-name="<?php echo htmlspecialchars($activity['name']); ?>"
|
||||
title="Delete">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; endforeach; ?>
|
||||
|
||||
<?php if (!$has_upcoming): ?>
|
||||
<tr id="noUpcomingRow">
|
||||
<td colspan="6" class="text-center py-4">
|
||||
<i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No upcoming activities scheduled</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Ongoing Activities Tab -->
|
||||
<div class="tab-pane fade" id="ongoing" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="ongoingTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Activity</th>
|
||||
<th>Time</th>
|
||||
<th>Location</th>
|
||||
<th>Duration</th>
|
||||
<th>Participants</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$has_ongoing = false;
|
||||
foreach ($activities as $activity):
|
||||
$current_time = date('H:i:s');
|
||||
if ($activity['date'] == $today &&
|
||||
$current_time >= $activity['time_in'] &&
|
||||
$current_time <= $activity['time_out']):
|
||||
$has_ongoing = true;
|
||||
|
||||
// Calculate time remaining
|
||||
$end_time = strtotime($activity['time_out']);
|
||||
$remaining = $end_time - time();
|
||||
$hours = floor($remaining / 3600);
|
||||
$minutes = floor(($remaining % 3600) / 60);
|
||||
?>
|
||||
<tr id="activityRow-<?php echo $activity['id']; ?>">
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($activity['name']); ?></strong><br>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($activity['description'] ? substr($activity['description'], 0, 50) . '...' : 'No description'); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo date('h:i A', strtotime($activity['time_in'])); ?> - <?php echo date('h:i A', strtotime($activity['time_out'])); ?></div>
|
||||
<small class="text-muted">Ends in <?php echo $hours . 'h ' . $minutes . 'm'; ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark">
|
||||
<i class="bi bi-geo-alt me-1"></i> <?php echo htmlspecialchars($activity['location']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$start = strtotime($activity['time_in']);
|
||||
$end = strtotime($activity['time_out']);
|
||||
$duration = round(($end - $start) / 3600, 1);
|
||||
echo '<span class="badge bg-info">' . $duration . ' hours</span>';
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
switch($activity['required_students']) {
|
||||
case 'all': echo '<span class="badge bg-info">All Students</span>'; break;
|
||||
case 'specific_course':
|
||||
echo '<span class="badge bg-warning">' . htmlspecialchars($activity['course_code'] ?? 'Specific Course') . '</span>';
|
||||
break;
|
||||
case 'specific_department':
|
||||
echo '<span class="badge bg-primary">' . htmlspecialchars($activity['department_name'] ?? 'Specific Department') . '</span>';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="view_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-info" title="View">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
<a href="../admin/attendance.php" class="btn btn-success" title="Take Attendance">
|
||||
<i class="bi bi-qr-code-scan"></i>
|
||||
</a>
|
||||
<a href="reports.php?activity_id=<?php echo $activity['id']; ?>" class="btn btn-primary" title="View Report">
|
||||
<i class="bi bi-file-earmark-text"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; endforeach; ?>
|
||||
|
||||
<?php if (!$has_ongoing): ?>
|
||||
<tr id="noOngoingRow">
|
||||
<td colspan="6" class="text-center py-4">
|
||||
<i class="bi bi-clock text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No ongoing activities at the moment</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Past Activities Tab -->
|
||||
<div class="tab-pane fade" id="past" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="pastTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Activity</th>
|
||||
<th>Date</th>
|
||||
<th>Time</th>
|
||||
<th>Location</th>
|
||||
<th>Attendance</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
$has_past = false;
|
||||
foreach ($activities as $activity):
|
||||
if ($activity['date'] < $today || ($activity['date'] == $today && date('H:i:s') > $activity['time_out'])):
|
||||
$has_past = true;
|
||||
|
||||
// Get attendance count for this activity
|
||||
$attendance_sql = "SELECT COUNT(*) as count FROM attendance WHERE activity_id = " . $activity['id'];
|
||||
$attendance_result = query($conn, $attendance_sql);
|
||||
$attendance_count = mysqli_fetch_assoc($attendance_result)['count'];
|
||||
?>
|
||||
<tr id="activityRow-<?php echo $activity['id']; ?>">
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($activity['name']); ?></strong><br>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($activity['description'] ? substr($activity['description'], 0, 50) . '...' : 'No description'); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo date('M d, Y', strtotime($activity['date'])); ?></div>
|
||||
<small class="text-muted"><?php echo date('l', strtotime($activity['date'])); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<small class="text-muted">
|
||||
<?php echo date('h:i A', strtotime($activity['time_in'])); ?> -
|
||||
<?php echo date('h:i A', strtotime($activity['time_out'])); ?>
|
||||
</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark">
|
||||
<i class="bi bi-geo-alt me-1"></i> <?php echo htmlspecialchars($activity['location']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-<?php echo $attendance_count > 0 ? 'success' : 'secondary'; ?>">
|
||||
<?php echo $attendance_count; ?> attended
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="view_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-info" title="View">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
<a href="reports.php?activity_id=<?php echo $activity['id']; ?>" class="btn btn-primary" title="View Report">
|
||||
<i class="bi bi-file-earmark-text"></i>
|
||||
</a>
|
||||
<a href="edit_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-warning" title="Edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; endforeach; ?>
|
||||
|
||||
<?php if (!$has_past): ?>
|
||||
<tr id="noPastRow">
|
||||
<td colspan="6" class="text-center py-4">
|
||||
<i class="bi bi-calendar-check text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No past activities found</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- All Activities Tab -->
|
||||
<div class="tab-pane fade" id="all" role="tabpanel">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="allTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Activity</th>
|
||||
<th>Date & Time</th>
|
||||
<th>Location</th>
|
||||
<th>Participants</th>
|
||||
<th>Created By</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="allActivitiesBody">
|
||||
<?php if (empty($activities)): ?>
|
||||
<tr id="noActivitiesRow">
|
||||
<td colspan="7" class="text-center py-4">
|
||||
<i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No activities found. Schedule your first activity!</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($activities as $activity): ?>
|
||||
<tr id="activityRow-<?php echo $activity['id']; ?>">
|
||||
<td>
|
||||
<strong><?php echo htmlspecialchars($activity['name']); ?></strong><br>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($activity['description'] ? substr($activity['description'], 0, 50) . '...' : 'No description'); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo date('M d, Y', strtotime($activity['date'])); ?></div>
|
||||
<small class="text-muted">
|
||||
<?php echo date('h:i A', strtotime($activity['time_in'])); ?> -
|
||||
<?php echo date('h:i A', strtotime($activity['time_out'])); ?>
|
||||
</small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-light text-dark">
|
||||
<i class="bi bi-geo-alt me-1"></i> <?php echo htmlspecialchars($activity['location']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
switch($activity['required_students']) {
|
||||
case 'all': echo '<span class="badge bg-info">All Students</span>'; break;
|
||||
case 'specific_course':
|
||||
echo '<span class="badge bg-warning">' . htmlspecialchars($activity['course_code'] ?? 'Specific Course') . '</span>';
|
||||
break;
|
||||
case 'specific_department':
|
||||
echo '<span class="badge bg-primary">' . htmlspecialchars($activity['department_name'] ?? 'Specific Department') . '</span>';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
<td>
|
||||
<small><?php echo htmlspecialchars($activity['created_by_name']); ?></small><br>
|
||||
<small class="text-muted"><?php echo date('M d, Y', strtotime($activity['created_at'])); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($activity['status'] == 1): ?>
|
||||
<span class="badge bg-success">Active</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">Inactive</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<div class="btn-group btn-group-sm">
|
||||
<a href="view_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-info" title="View">
|
||||
<i class="bi bi-eye"></i>
|
||||
</a>
|
||||
<a href="edit_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-warning" title="Edit">
|
||||
<i class="bi bi-pencil"></i>
|
||||
</a>
|
||||
<button type="button" class="btn btn-danger delete-activity-btn"
|
||||
data-id="<?php echo $activity['id']; ?>"
|
||||
data-name="<?php echo htmlspecialchars($activity['name']); ?>"
|
||||
title="Delete">
|
||||
<i class="bi bi-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">
|
||||
Showing <span id="activitiesCount"><?php echo count($activities); ?></span> activity(s)
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<small class="text-muted">
|
||||
Today: <?php echo date('F j, Y'); ?>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Confirm Delete</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to delete activity "<span id="deleteActivityName"></span>"?</p>
|
||||
<p class="text-danger"><small>This will also delete all attendance records for this activity.</small></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger" id="confirmDeleteBtn">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
let currentActivityId = null;
|
||||
|
||||
// Initialize DataTables
|
||||
const upcomingTable = $("#upcomingTable").DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
|
||||
order: [[1, "asc"]],
|
||||
responsive: true,
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [5] }
|
||||
]
|
||||
});
|
||||
|
||||
const ongoingTable = $("#ongoingTable").DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
|
||||
order: [[1, "asc"]],
|
||||
responsive: true,
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [5] }
|
||||
]
|
||||
});
|
||||
|
||||
const pastTable = $("#pastTable").DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
|
||||
order: [[1, "desc"]],
|
||||
responsive: true,
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [5] }
|
||||
]
|
||||
});
|
||||
|
||||
const allTable = $("#allTable").DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
|
||||
order: [[1, "desc"]],
|
||||
responsive: true,
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [6] }
|
||||
]
|
||||
});
|
||||
|
||||
// Delete button click
|
||||
$(document).on("click", ".delete-activity-btn", function() {
|
||||
currentActivityId = $(this).data("id");
|
||||
const activityName = $(this).data("name");
|
||||
|
||||
$("#deleteActivityName").text(activityName);
|
||||
$("#deleteModal").modal("show");
|
||||
});
|
||||
|
||||
// Confirm delete
|
||||
$("#confirmDeleteBtn").click(function() {
|
||||
if (!currentActivityId) return;
|
||||
|
||||
const $btn = $(this);
|
||||
const originalText = $btn.html();
|
||||
$btn.html(\'<i class="bi bi-hourglass-split"></i> Deleting...\').prop("disabled", true);
|
||||
|
||||
$.ajax({
|
||||
url: "manage_activities.php",
|
||||
method: "POST",
|
||||
data: {
|
||||
ajax_delete: true,
|
||||
activity_id: currentActivityId,
|
||||
csrf_token: "' . $csrf_token . '"
|
||||
},
|
||||
dataType: "json",
|
||||
success: function(response) {
|
||||
$btn.html(originalText).prop("disabled", false);
|
||||
$("#deleteModal").modal("hide");
|
||||
|
||||
if (response.success) {
|
||||
// Remove row from all tables
|
||||
$("#activityRow-" + currentActivityId).fadeOut(300, function() {
|
||||
$(this).remove();
|
||||
|
||||
// Update counters
|
||||
updateCounters();
|
||||
|
||||
// Show success message
|
||||
showMessage(response.message, "success");
|
||||
});
|
||||
} else {
|
||||
showMessage(response.message, "danger");
|
||||
}
|
||||
},
|
||||
error: function(xhr, status, error) {
|
||||
$btn.html(originalText).prop("disabled", false);
|
||||
showMessage("Error deleting activity. Please try again.", "danger");
|
||||
console.error("Delete error:", error);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function updateCounters() {
|
||||
// Get current counts
|
||||
const totalRows = $("#allActivitiesBody tr:not(#noActivitiesRow)").length;
|
||||
const upcomingRows = $("#upcomingTable tbody tr:not(#noUpcomingRow)").length;
|
||||
const ongoingRows = $("#ongoingTable tbody tr:not(#noOngoingRow)").length;
|
||||
const pastRows = $("#pastTable tbody tr:not(#noPastRow)").length;
|
||||
|
||||
// Update counters
|
||||
$("#activitiesCount").text(totalRows);
|
||||
$("#totalCount").text(totalRows);
|
||||
$("#upcomingBadge").text(upcomingRows);
|
||||
|
||||
// Update badges
|
||||
$("#upcoming-tab .badge").text(upcomingRows);
|
||||
$("#ongoing-tab .badge").text(ongoingRows);
|
||||
$("#past-tab .badge").text(pastRows);
|
||||
$("#all-tab .badge").text(totalRows);
|
||||
|
||||
// Show/hide empty messages
|
||||
if (upcomingRows === 0 && $("#noUpcomingRow").length === 0) {
|
||||
$("#upcomingTable tbody").append(\'<tr id="noUpcomingRow"><td colspan="6" class="text-center py-4"><i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i><p class="mt-2">No upcoming activities scheduled</p></td></tr>\');
|
||||
}
|
||||
|
||||
if (ongoingRows === 0 && $("#noOngoingRow").length === 0) {
|
||||
$("#ongoingTable tbody").append(\'<tr id="noOngoingRow"><td colspan="6" class="text-center py-4"><i class="bi bi-clock text-muted" style="font-size: 3rem;"></i><p class="mt-2">No ongoing activities at the moment</p></td></tr>\');
|
||||
}
|
||||
|
||||
if (pastRows === 0 && $("#noPastRow").length === 0) {
|
||||
$("#pastTable tbody").append(\'<tr id="noPastRow"><td colspan="6" class="text-center py-4"><i class="bi bi-calendar-check text-muted" style="font-size: 3rem;"></i><p class="mt-2">No past activities found</p></td></tr>\');
|
||||
}
|
||||
|
||||
if (totalRows === 0 && $("#noActivitiesRow").length === 0) {
|
||||
$("#allActivitiesBody").append(\'<tr id="noActivitiesRow"><td colspan="7" class="text-center py-4"><i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i><p class="mt-2">No activities found. Schedule your first activity!</p></td></tr>\');
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(message, type) {
|
||||
const $alert = $("#messageAlert");
|
||||
$alert.removeClass("alert-success alert-danger alert-warning alert-info")
|
||||
.addClass("alert-" + type)
|
||||
.html(\'<i class="bi me-2"></i>\' + message + \'<button type="button" class="btn-close" data-bs-dismiss="alert"></button>\')
|
||||
.find("i").addClass(type === "success" ? "bi-check-circle" : "bi-exclamation-circle").end()
|
||||
.show();
|
||||
|
||||
// Auto-hide after 5 seconds
|
||||
setTimeout(() => {
|
||||
$alert.fadeOut();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Auto-refresh ongoing tab
|
||||
setInterval(function() {
|
||||
const activeTab = document.querySelector("#activityTabs .nav-link.active");
|
||||
if (activeTab && activeTab.id === "ongoing-tab") {
|
||||
location.reload();
|
||||
}
|
||||
}, 60000);
|
||||
|
||||
// Initialize counters
|
||||
updateCounters();
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
1207
src-backup/admin/manage_students.php
Normal file
200
src-backup/admin/process_user.php
Normal file
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
session_start();
|
||||
require_once __DIR__ . '/../includes/database.php';
|
||||
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||
$_SESSION['message'] = 'Unauthorized access!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: ../auth/login.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$action = $_POST['action'] ?? '';
|
||||
|
||||
switch ($action) {
|
||||
case 'add':
|
||||
addUser();
|
||||
break;
|
||||
case 'edit':
|
||||
editUser();
|
||||
break;
|
||||
case 'toggle_status':
|
||||
toggleUserStatus();
|
||||
break;
|
||||
case 'delete':
|
||||
deleteUser();
|
||||
break;
|
||||
default:
|
||||
$_SESSION['message'] = 'Invalid action!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
function addUser() {
|
||||
global $pdo;
|
||||
|
||||
$full_name = trim($_POST['full_name']);
|
||||
$username = trim($_POST['username']);
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password'];
|
||||
$role = $_POST['role'];
|
||||
$status = $_POST['status'] ?? 1;
|
||||
|
||||
// Validation
|
||||
if (empty($full_name) || empty($username) || empty($password) || empty($role)) {
|
||||
$_SESSION['message'] = 'All required fields must be filled!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
if (strlen($password) < 6) {
|
||||
$_SESSION['message'] = 'Password must be at least 6 characters!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if username already exists
|
||||
$checkQuery = "SELECT COUNT(*) FROM users WHERE username = ?";
|
||||
$stmt = $pdo->prepare($checkQuery);
|
||||
$stmt->execute([$username]);
|
||||
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
$_SESSION['message'] = 'Username already exists!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Hash password
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
// Insert user
|
||||
$query = "INSERT INTO users (full_name, username, email, password, role, status)
|
||||
VALUES (?, ?, ?, ?, ?, ?)";
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$full_name, $username, $email, $hashed_password, $role, $status]);
|
||||
|
||||
$_SESSION['message'] = 'User added successfully!';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['message'] = 'Error adding user: ' . $e->getMessage();
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function editUser() {
|
||||
global $pdo;
|
||||
|
||||
$user_id = $_POST['user_id'];
|
||||
$full_name = trim($_POST['full_name']);
|
||||
$username = trim($_POST['username']);
|
||||
$email = trim($_POST['email']);
|
||||
$password = $_POST['password'];
|
||||
$role = $_POST['role'];
|
||||
$status = $_POST['status'] ?? 1;
|
||||
|
||||
// Validation
|
||||
if (empty($full_name) || empty($username) || empty($role)) {
|
||||
$_SESSION['message'] = 'All required fields must be filled!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Check if username already exists (excluding current user)
|
||||
$checkQuery = "SELECT COUNT(*) FROM users WHERE username = ? AND id != ?";
|
||||
$stmt = $pdo->prepare($checkQuery);
|
||||
$stmt->execute([$username, $user_id]);
|
||||
|
||||
if ($stmt->fetchColumn() > 0) {
|
||||
$_SESSION['message'] = 'Username already exists!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Update query
|
||||
if (!empty($password)) {
|
||||
if (strlen($password) < 6) {
|
||||
$_SESSION['message'] = 'Password must be at least 6 characters!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
$hashed_password = password_hash($password, PASSWORD_DEFAULT);
|
||||
$query = "UPDATE users SET full_name = ?, username = ?, email = ?, password = ?, role = ?, status = ? WHERE id = ?";
|
||||
$params = [$full_name, $username, $email, $hashed_password, $role, $status, $user_id];
|
||||
} else {
|
||||
$query = "UPDATE users SET full_name = ?, username = ?, email = ?, role = ?, status = ? WHERE id = ?";
|
||||
$params = [$full_name, $username, $email, $role, $status, $user_id];
|
||||
}
|
||||
|
||||
try {
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute($params);
|
||||
|
||||
$_SESSION['message'] = 'User updated successfully!';
|
||||
$_SESSION['message_type'] = 'success';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
} catch (PDOException $e) {
|
||||
$_SESSION['message'] = 'Error updating user: ' . $e->getMessage();
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header("Location: users.php");
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
function toggleUserStatus() {
|
||||
global $pdo;
|
||||
|
||||
$user_id = $_POST['user_id'];
|
||||
|
||||
// Get current status
|
||||
$query = "SELECT status FROM users WHERE id = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$user_id]);
|
||||
$current = $stmt->fetchColumn();
|
||||
|
||||
$new_status = $current ? 0 : 1;
|
||||
|
||||
// Update status
|
||||
$updateQuery = "UPDATE users SET status = ? WHERE id = ?";
|
||||
$stmt = $pdo->prepare($updateQuery);
|
||||
$stmt->execute([$new_status, $user_id]);
|
||||
|
||||
echo json_encode(['success' => true, 'message' => 'Status updated successfully']);
|
||||
}
|
||||
|
||||
function deleteUser() {
|
||||
global $pdo;
|
||||
|
||||
$user_id = $_POST['user_id'];
|
||||
|
||||
// Prevent deleting yourself
|
||||
if ($user_id == $_SESSION['user_id']) {
|
||||
echo json_encode(['success' => false, 'message' => 'You cannot delete your own account!']);
|
||||
exit();
|
||||
}
|
||||
|
||||
try {
|
||||
$query = "DELETE FROM users WHERE id = ?";
|
||||
$stmt = $pdo->prepare($query);
|
||||
$stmt->execute([$user_id]);
|
||||
|
||||
echo json_encode(['success' => true, 'message' => 'User deleted successfully']);
|
||||
} catch (PDOException $e) {
|
||||
echo json_encode(['success' => false, 'message' => 'Error deleting user: ' . $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
?>
|
||||
754
src-backup/admin/profile.php
Normal file
@@ -0,0 +1,754 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "My Profile";
|
||||
|
||||
// Initialize variables
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
$user_id = $_SESSION['user_id'];
|
||||
|
||||
// Get current user data
|
||||
$sql = "SELECT * FROM users WHERE id = ?";
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $user_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
|
||||
if (!$result || mysqli_num_rows($result) == 0) {
|
||||
header('Location: logout.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$user = mysqli_fetch_assoc($result);
|
||||
mysqli_stmt_close($stmt);
|
||||
|
||||
// Handle profile update
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['update_profile'])) {
|
||||
$full_name = escape($conn, trim($_POST['full_name']));
|
||||
$email = escape($conn, trim($_POST['email']));
|
||||
$contact_number = escape($conn, trim($_POST['contact_number']));
|
||||
$address = escape($conn, trim($_POST['address']));
|
||||
|
||||
// Validate email
|
||||
if (!empty($email) && !filter_var($email, FILTER_VALIDATE_EMAIL)) {
|
||||
$message = 'Invalid email address.';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
// Check if email already exists
|
||||
$check_sql = "SELECT id FROM users WHERE email = ? AND id != ?";
|
||||
$check_stmt = mysqli_prepare($conn, $check_sql);
|
||||
mysqli_stmt_bind_param($check_stmt, 'si', $email, $user_id);
|
||||
mysqli_stmt_execute($check_stmt);
|
||||
mysqli_stmt_store_result($check_stmt);
|
||||
|
||||
if (mysqli_stmt_num_rows($check_stmt) > 0) {
|
||||
$message = 'Email already exists.';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
// Update profile
|
||||
$update_sql = "UPDATE users SET
|
||||
full_name = ?,
|
||||
email = ?,
|
||||
contact_number = ?,
|
||||
address = ?,
|
||||
updated_at = NOW()
|
||||
WHERE id = ?";
|
||||
|
||||
$update_stmt = mysqli_prepare($conn, $update_sql);
|
||||
mysqli_stmt_bind_param($update_stmt, 'ssssi',
|
||||
$full_name, $email, $contact_number, $address, $user_id);
|
||||
|
||||
if (mysqli_stmt_execute($update_stmt)) {
|
||||
// Update session data
|
||||
$_SESSION['full_name'] = $full_name;
|
||||
$_SESSION['email'] = $email;
|
||||
|
||||
$message = 'Profile updated!';
|
||||
$message_type = 'success';
|
||||
|
||||
// Refresh user data
|
||||
$user['full_name'] = $full_name;
|
||||
$user['email'] = $email;
|
||||
$user['contact_number'] = $contact_number;
|
||||
$user['address'] = $address;
|
||||
} else {
|
||||
$message = 'Error updating profile.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($update_stmt);
|
||||
}
|
||||
mysqli_stmt_close($check_stmt);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle password change
|
||||
elseif (isset($_POST['change_password'])) {
|
||||
$current_password = trim($_POST['current_password']);
|
||||
$new_password = trim($_POST['new_password']);
|
||||
$confirm_password = trim($_POST['confirm_password']);
|
||||
|
||||
// Validate passwords
|
||||
if (empty($current_password) || empty($new_password) || empty($confirm_password)) {
|
||||
$message = 'All fields required.';
|
||||
$message_type = 'danger';
|
||||
} elseif ($new_password !== $confirm_password) {
|
||||
$message = 'Passwords do not match.';
|
||||
$message_type = 'danger';
|
||||
} elseif (strlen($new_password) < 6) {
|
||||
$message = 'Password must be at least 6 characters.';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
// Verify current password
|
||||
$check_sql = "SELECT password FROM users WHERE id = ?";
|
||||
$check_stmt = mysqli_prepare($conn, $check_sql);
|
||||
mysqli_stmt_bind_param($check_stmt, 'i', $user_id);
|
||||
mysqli_stmt_execute($check_stmt);
|
||||
mysqli_stmt_bind_result($check_stmt, $hashed_password);
|
||||
mysqli_stmt_fetch($check_stmt);
|
||||
mysqli_stmt_close($check_stmt);
|
||||
|
||||
if (!password_verify($current_password, $hashed_password)) {
|
||||
$message = 'Current password incorrect.';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
// Hash new password
|
||||
$new_hashed_password = password_hash($new_password, PASSWORD_DEFAULT);
|
||||
|
||||
// Update password
|
||||
$update_sql = "UPDATE users SET password = ?, updated_at = NOW() WHERE id = ?";
|
||||
$update_stmt = mysqli_prepare($conn, $update_sql);
|
||||
mysqli_stmt_bind_param($update_stmt, 'si', $new_hashed_password, $user_id);
|
||||
|
||||
if (mysqli_stmt_execute($update_stmt)) {
|
||||
$message = 'Password changed!';
|
||||
$message_type = 'success';
|
||||
} else {
|
||||
$message = 'Error changing password.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($update_stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle profile picture upload
|
||||
elseif (isset($_FILES['profile_picture']) && $_FILES['profile_picture']['error'] == 0) {
|
||||
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif'];
|
||||
$max_file_size = 2 * 1024 * 1024; // 2MB
|
||||
|
||||
$file_name = $_FILES['profile_picture']['name'];
|
||||
$file_tmp = $_FILES['profile_picture']['tmp_name'];
|
||||
$file_size = $_FILES['profile_picture']['size'];
|
||||
|
||||
// Get file extension
|
||||
$file_ext = strtolower(pathinfo($file_name, PATHINFO_EXTENSION));
|
||||
|
||||
// Validate file
|
||||
if (!in_array($file_ext, $allowed_extensions)) {
|
||||
$message = 'Only JPG, PNG, GIF allowed.';
|
||||
$message_type = 'danger';
|
||||
} elseif ($file_size > $max_file_size) {
|
||||
$message = 'File must be < 2MB.';
|
||||
$message_type = 'danger';
|
||||
} else {
|
||||
// Create uploads directory
|
||||
$upload_dir = '../uploads/profile_pictures/';
|
||||
if (!file_exists($upload_dir)) {
|
||||
mkdir($upload_dir, 0777, true);
|
||||
}
|
||||
|
||||
// Generate unique filename
|
||||
$new_filename = 'profile_' . $user_id . '_' . time() . '.' . $file_ext;
|
||||
$destination = $upload_dir . $new_filename;
|
||||
|
||||
// Delete old profile picture
|
||||
if (!empty($user['profile_picture'])) {
|
||||
$old_file = '../' . $user['profile_picture'];
|
||||
if (file_exists($old_file)) {
|
||||
@unlink($old_file);
|
||||
}
|
||||
}
|
||||
|
||||
// Move uploaded file
|
||||
if (move_uploaded_file($file_tmp, $destination)) {
|
||||
// Update database
|
||||
$relative_path = 'uploads/profile_pictures/' . $new_filename;
|
||||
$update_sql = "UPDATE users SET profile_picture = ?, updated_at = NOW() WHERE id = ?";
|
||||
$update_stmt = mysqli_prepare($conn, $update_sql);
|
||||
mysqli_stmt_bind_param($update_stmt, 'si', $relative_path, $user_id);
|
||||
|
||||
if (mysqli_stmt_execute($update_stmt)) {
|
||||
$user['profile_picture'] = $relative_path;
|
||||
$_SESSION['profile_picture'] = $relative_path;
|
||||
$message = 'Profile picture updated!';
|
||||
$message_type = 'success';
|
||||
} else {
|
||||
$message = 'Error updating picture.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
mysqli_stmt_close($update_stmt);
|
||||
} else {
|
||||
$message = 'Error uploading file.';
|
||||
$message_type = 'danger';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<style>
|
||||
/* Compact Styles */
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
background: #166b0e;
|
||||
color: white;
|
||||
padding: 15px;
|
||||
border-radius: 8px 8px 0 0;
|
||||
}
|
||||
|
||||
.profile-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||
margin-bottom: 15px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.profile-picture-container {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 10px auto 10px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.profile-picture {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
object-fit: cover;
|
||||
border: 3px solid white;
|
||||
box-shadow: 0 3px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.profile-picture-upload {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
right: 5px;
|
||||
background: #166b0e;
|
||||
color: white;
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
padding: 15px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f0f0f0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-weight: 600;
|
||||
color: #6c757d;
|
||||
font-size: 12px;
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.badge-role {
|
||||
background:#cfee43;
|
||||
color: rgb(0, 0, 0);
|
||||
padding: 4px 10px;
|
||||
border-radius: 12px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.form-control, .form-select {
|
||||
font-size: 13px;
|
||||
padding: 6px 10px;
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 13px;
|
||||
padding: 6px 12px;
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: 4px 10px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.table {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.table th {
|
||||
font-size: 12px;
|
||||
padding: 10px;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.table td {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 11px;
|
||||
padding: 3px 8px;
|
||||
}
|
||||
|
||||
.alert {
|
||||
padding: 8px 12px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
padding: 12px 15px;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.profile-header {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.profile-picture-container {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
margin: -40px auto 8px;
|
||||
}
|
||||
|
||||
.profile-picture-upload {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
font-size: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<!-- Profile Header -->
|
||||
<div class="profile-header mb-3">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h1 class="h4 mb-0">My Profile</h1>
|
||||
<small class="opacity-75">Manage account information</small>
|
||||
</div>
|
||||
<span class="badge-role">
|
||||
<i class="bi bi-shield-check me-1"></i> <?php echo htmlspecialchars(ucfirst($user['role'])); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show mb-3 py-2" role="alert" style="font-size: 13px;">
|
||||
<i class="bi bi-<?php echo $message_type == 'success' ? 'check-circle' : 'exclamation-triangle'; ?> me-1"></i>
|
||||
<?php echo $message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close" style="font-size: 10px;"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Profile Picture -->
|
||||
<div class="profile-card">
|
||||
<div class="text-center p-3">
|
||||
<div class="profile-picture-container">
|
||||
<?php if (!empty($user['profile_picture'])): ?>
|
||||
<img src="../<?php echo htmlspecialchars($user['profile_picture']); ?>"
|
||||
alt="Profile"
|
||||
class="profile-picture">
|
||||
<?php else: ?>
|
||||
<div class="profile-picture d-flex align-items-center justify-content-center bg-primary text-white">
|
||||
<i class="bi bi-person" style="font-size: 40px;"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="profile-picture-upload" data-bs-toggle="modal" data-bs-target="#uploadModal">
|
||||
<i class="bi bi-camera"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h4 class="mb-1"><?php echo htmlspecialchars($user['full_name']); ?></h4>
|
||||
<p class="text-muted mb-2"><?php echo htmlspecialchars($user['email']); ?></p>
|
||||
|
||||
<div>
|
||||
<span class="badge bg-info me-1">
|
||||
<i class="bi bi-person-badge"></i> ID: <?php echo $user_id; ?>
|
||||
</span>
|
||||
<span class="badge bg-secondary">
|
||||
<i class="bi bi-calendar"></i> <?php echo date('M Y', strtotime($user['created_at'])); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-3">
|
||||
<!-- Personal Information -->
|
||||
<div class="col-lg-8">
|
||||
<div class="profile-card">
|
||||
<div class="card-header bg-white border-bottom py-2">
|
||||
<h6 class="mb-0"><i class="bi bi-person-lines-fill me-1"></i> Personal Information</h6>
|
||||
</div>
|
||||
<div class="card-body p-3">
|
||||
<form method="POST" action="" id="profileForm">
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Full Name *</label>
|
||||
<input type="text" class="form-control" name="full_name"
|
||||
value="<?php echo htmlspecialchars($user['full_name']); ?>" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Email *</label>
|
||||
<input type="email" class="form-control" name="email"
|
||||
value="<?php echo htmlspecialchars($user['email']); ?>" required>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Contact</label>
|
||||
<input type="tel" class="form-control" name="contact_number"
|
||||
value="<?php echo htmlspecialchars($user['contact_number'] ?? ''); ?>">
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Address</label>
|
||||
<input type="text" class="form-control" name="address"
|
||||
value="<?php echo htmlspecialchars($user['address'] ?? ''); ?>">
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Username</label>
|
||||
<input type="text" class="form-control" value="<?php echo htmlspecialchars($user['username']); ?>" readonly>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Created</label>
|
||||
<input type="text" class="form-control"
|
||||
value="<?php echo date('m/d/Y', strtotime($user['created_at'])); ?>" readonly>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Role</label>
|
||||
<input type="text" class="form-control"
|
||||
value="<?php echo htmlspecialchars(ucfirst($user['role'])); ?>" readonly>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Status</label>
|
||||
<input type="text" class="form-control"
|
||||
value="<?php echo $user['status'] == 1 ? 'Active' : 'Inactive'; ?>" readonly>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center mt-3 pt-2 border-top">
|
||||
<small class="text-muted">
|
||||
Updated: <?php echo date('m/d/Y h:i A', strtotime($user['updated_at'])); ?>
|
||||
</small>
|
||||
<button type="submit" class="btn btn-primary btn-sm" name="update_profile">
|
||||
<i class="bi bi-save me-1"></i> Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Change Password -->
|
||||
<div class="profile-card mt-3">
|
||||
<div class="card-header bg-white border-bottom py-2">
|
||||
<h6 class="mb-0"><i class="bi bi-key-fill me-1"></i> Change Password</h6>
|
||||
</div>
|
||||
<div class="card-body p-3">
|
||||
<form method="POST" action="" id="passwordForm">
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Current Password *</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="password" class="form-control" name="current_password" id="current_password" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePassword('current_password')">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">New Password *</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="password" class="form-control" name="new_password" id="new_password" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePassword('new_password')">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-2">
|
||||
<label class="form-label">Confirm Password *</label>
|
||||
<div class="input-group input-group-sm">
|
||||
<input type="password" class="form-control" name="confirm_password" id="confirm_password" required>
|
||||
<button class="btn btn-outline-secondary" type="button" onclick="togglePassword('confirm_password')">
|
||||
<i class="bi bi-eye"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-info py-2 mt-2 mb-2" style="font-size: 12px;">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
Password must be at least 6 characters
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end">
|
||||
<button type="submit" class="btn btn-warning btn-sm" name="change_password">
|
||||
<i class="bi bi-key me-1"></i> Change Password
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<div class="col-lg-4">
|
||||
<!-- Account Stats -->
|
||||
<div class="stats-card">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="bg-primary text-white rounded p-2 me-2">
|
||||
<i class="bi bi-speedometer2"></i>
|
||||
</div>
|
||||
<h6 class="mb-0">Account Overview</h6>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">User ID</div>
|
||||
<div class="info-value"><?php echo $user_id; ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Role</div>
|
||||
<div class="info-value"><?php echo htmlspecialchars(ucfirst($user['role'])); ?></div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Status</div>
|
||||
<div class="info-value">
|
||||
<?php if ($user['status'] == 1): ?>
|
||||
<span class="badge bg-success">
|
||||
<i class="bi bi-check-circle me-1"></i> Active
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">
|
||||
<i class="bi bi-x-circle me-1"></i> Inactive
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="info-item">
|
||||
<div class="info-label">Last Login</div>
|
||||
<div class="info-value">
|
||||
<?php
|
||||
$last_login = !empty($user['last_login']) ? date('m/d/Y h:i A', strtotime($user['last_login'])) : 'Never';
|
||||
echo $last_login;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="stats-card mt-3">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="bg-info text-white rounded p-2 me-2">
|
||||
<i class="bi bi-lightning"></i>
|
||||
</div>
|
||||
<h6 class="mb-0">Quick Actions</h6>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<a href="dashboard.php" class="btn btn-outline-primary btn-sm">
|
||||
<i class="bi bi-speedometer2 me-1"></i> Dashboard
|
||||
</a>
|
||||
<button class="btn btn-outline-success btn-sm" onclick="window.print()">
|
||||
<i class="bi bi-printer me-1"></i> Print
|
||||
</button>
|
||||
<a href="../auth/logout.php" class="btn btn-outline-danger btn-sm">
|
||||
<i class="bi bi-box-arrow-right me-1"></i> Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Security Tips -->
|
||||
<div class="stats-card mt-3">
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<div class="bg-warning text-white rounded p-2 me-2">
|
||||
<i class="bi bi-shield-check"></i>
|
||||
</div>
|
||||
<h6 class="mb-0">Security Tips</h6>
|
||||
</div>
|
||||
|
||||
<div style="font-size: 12px;">
|
||||
<div class="mb-1">
|
||||
<i class="bi bi-check-circle-fill text-success me-1"></i>
|
||||
Use strong password
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<i class="bi bi-check-circle-fill text-success me-1"></i>
|
||||
Update regularly
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<i class="bi bi-check-circle-fill text-success me-1"></i>
|
||||
Logout when done
|
||||
</div>
|
||||
<div>
|
||||
<i class="bi bi-check-circle-fill text-success me-1"></i>
|
||||
Keep info updated
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Upload Modal -->
|
||||
<div class="modal fade" id="uploadModal" tabindex="-1" aria-labelledby="uploadModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header py-2">
|
||||
<h6 class="modal-title mb-0" id="uploadModalLabel">
|
||||
<i class="bi bi-camera me-1"></i> Upload Photo
|
||||
</h6>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form method="POST" action="" enctype="multipart/form-data">
|
||||
<div class="modal-body py-2">
|
||||
<div class="alert alert-info py-1 mb-2" style="font-size: 11px;">
|
||||
<i class="bi bi-info-circle me-1"></i>
|
||||
JPG, PNG, GIF (Max 2MB)
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label for="profile_picture" class="form-label">Select Image</label>
|
||||
<input type="file" class="form-control form-control-sm" id="profile_picture" name="profile_picture" accept="image/*">
|
||||
</div>
|
||||
|
||||
<div class="preview-container text-center mt-2" style="display: none;">
|
||||
<img id="imagePreview" class="img-fluid rounded" style="max-height: 150px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Upload</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
// Toggle password visibility
|
||||
function togglePassword(fieldId) {
|
||||
const field = document.getElementById(fieldId);
|
||||
const type = field.getAttribute("type") === "password" ? "text" : "password";
|
||||
field.setAttribute("type", type);
|
||||
}
|
||||
|
||||
// Image preview
|
||||
document.getElementById("profile_picture").addEventListener("change", function(e) {
|
||||
const preview = document.getElementById("imagePreview");
|
||||
const previewContainer = document.querySelector(".preview-container");
|
||||
|
||||
if (this.files && this.files[0]) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
preview.src = e.target.result;
|
||||
previewContainer.style.display = "block";
|
||||
}
|
||||
reader.readAsDataURL(this.files[0]);
|
||||
} else {
|
||||
previewContainer.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
// Form validation
|
||||
document.getElementById("profileForm").addEventListener("submit", function(e) {
|
||||
const email = this.querySelector("input[name=\'email\']").value;
|
||||
if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email)) {
|
||||
e.preventDefault();
|
||||
alert("Invalid email address.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
document.getElementById("passwordForm").addEventListener("submit", function(e) {
|
||||
const newPassword = this.querySelector("input[name=\'new_password\']").value;
|
||||
const confirmPassword = this.querySelector("input[name=\'confirm_password\']").value;
|
||||
|
||||
if (newPassword.length < 6) {
|
||||
e.preventDefault();
|
||||
alert("Password must be at least 6 characters.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (newPassword !== confirmPassword) {
|
||||
e.preventDefault();
|
||||
alert("Passwords do not match.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
962
src-backup/admin/reports.php
Normal file
@@ -0,0 +1,962 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "Attendance Reports";
|
||||
|
||||
// Get filter parameters
|
||||
$start_date = $_GET['start_date'] ?? date('Y-m-01'); // First day of current month
|
||||
$end_date = $_GET['end_date'] ?? date('Y-m-t'); // Last day of current month
|
||||
$activity_id = $_GET['activity_id'] ?? '';
|
||||
$course_id = $_GET['course_id'] ?? '';
|
||||
$department_id = $_GET['department_id'] ?? '';
|
||||
$status = $_GET['status'] ?? '';
|
||||
|
||||
// Build SQL query with filters
|
||||
$where_conditions = ["DATE(a.created_at) BETWEEN '$start_date' AND '$end_date'"];
|
||||
$join_tables = "";
|
||||
|
||||
if ($activity_id) {
|
||||
$where_conditions[] = "a.activity_id = " . intval($activity_id);
|
||||
}
|
||||
|
||||
if ($course_id) {
|
||||
$join_tables .= " LEFT JOIN students s ON a.student_id = s.id";
|
||||
$where_conditions[] = "s.course_id = " . intval($course_id);
|
||||
}
|
||||
|
||||
if ($department_id) {
|
||||
if (strpos($join_tables, 'students s') === false) {
|
||||
$join_tables .= " LEFT JOIN students s ON a.student_id = s.id";
|
||||
}
|
||||
$where_conditions[] = "s.department_id = " . intval($department_id);
|
||||
}
|
||||
|
||||
if ($status && in_array($status, ['present', 'late', 'absent', 'excused'])) {
|
||||
$where_conditions[] = "a.status = '$status'";
|
||||
}
|
||||
|
||||
// Get attendance records - FIXED VERSION (walang created_by sa attendance table)
|
||||
$attendance_records = [];
|
||||
$where_clause = count($where_conditions) > 0 ? "WHERE " . implode(" AND ", $where_conditions) : "";
|
||||
|
||||
$sql = "SELECT
|
||||
a.*,
|
||||
s.student_id as student_number,
|
||||
s.full_name as student_name,
|
||||
s.year_level,
|
||||
c.code as course_code,
|
||||
c.name as course_name,
|
||||
d.code as department_code,
|
||||
d.name as department_name,
|
||||
ac.name as activity_name,
|
||||
ac.date as activity_date,
|
||||
ac.time_in as activity_time_in,
|
||||
ac.time_out as activity_time_out,
|
||||
ac.location as activity_location
|
||||
FROM attendance a
|
||||
LEFT JOIN students s ON a.student_id = s.id
|
||||
LEFT JOIN courses c ON s.course_id = c.id
|
||||
LEFT JOIN departments d ON s.department_id = d.id
|
||||
LEFT JOIN activities ac ON a.activity_id = ac.id
|
||||
$join_tables
|
||||
$where_clause
|
||||
ORDER BY a.created_at DESC";
|
||||
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$attendance_records[] = $row;
|
||||
}
|
||||
|
||||
// Get statistics
|
||||
$stats = [
|
||||
'total' => 0,
|
||||
'present' => 0,
|
||||
'late' => 0,
|
||||
'absent' => 0,
|
||||
'excused' => 0
|
||||
];
|
||||
|
||||
foreach ($attendance_records as $record) {
|
||||
$stats['total']++;
|
||||
switch($record['status']) {
|
||||
case 'present': $stats['present']++; break;
|
||||
case 'late': $stats['late']++; break;
|
||||
case 'absent': $stats['absent']++; break;
|
||||
case 'excused': $stats['excused']++; break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get filter dropdown data
|
||||
$activities = [];
|
||||
$courses = [];
|
||||
$departments = [];
|
||||
|
||||
// All activities
|
||||
$result = query($conn, "SELECT * FROM activities ORDER BY date DESC, name ASC");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$activities[] = $row;
|
||||
}
|
||||
|
||||
// All courses
|
||||
$result = query($conn, "SELECT * FROM courses WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$courses[] = $row;
|
||||
}
|
||||
|
||||
// All departments
|
||||
$result = query($conn, "SELECT * FROM departments WHERE status = 1 ORDER BY code");
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$departments[] = $row;
|
||||
}
|
||||
|
||||
// Get daily attendance trend
|
||||
$daily_trend = [];
|
||||
$sql = "SELECT
|
||||
DATE(created_at) as date,
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present,
|
||||
SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late,
|
||||
SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent,
|
||||
SUM(CASE WHEN status = 'excused' THEN 1 ELSE 0 END) as excused
|
||||
FROM attendance
|
||||
WHERE DATE(created_at) BETWEEN '$start_date' AND '$end_date'
|
||||
GROUP BY DATE(created_at)
|
||||
ORDER BY date ASC";
|
||||
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$daily_trend[] = $row;
|
||||
}
|
||||
|
||||
// Get activity-wise statistics
|
||||
$activity_stats = [];
|
||||
$sql = "SELECT
|
||||
ac.name as activity_name,
|
||||
COUNT(a.id) as total_attendance,
|
||||
SUM(CASE WHEN a.status = 'present' THEN 1 ELSE 0 END) as present,
|
||||
SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) as late,
|
||||
ROUND((SUM(CASE WHEN a.status IN ('present', 'late') THEN 1 ELSE 0 END) * 100.0 / COUNT(a.id)), 1) as attendance_rate
|
||||
FROM activities ac
|
||||
LEFT JOIN attendance a ON ac.id = a.activity_id
|
||||
WHERE ac.date BETWEEN '$start_date' AND '$end_date'
|
||||
GROUP BY ac.id
|
||||
ORDER BY ac.date DESC, ac.name ASC";
|
||||
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$activity_stats[] = $row;
|
||||
}
|
||||
|
||||
// Get department-wise statistics
|
||||
$department_stats = [];
|
||||
$sql = "SELECT
|
||||
d.code as department_code,
|
||||
d.name as department_name,
|
||||
COUNT(a.id) as total_attendance,
|
||||
SUM(CASE WHEN a.status = 'present' THEN 1 ELSE 0 END) as present,
|
||||
SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) as late,
|
||||
ROUND((SUM(CASE WHEN a.status IN ('present', 'late') THEN 1 ELSE 0 END) * 100.0 / COUNT(a.id)), 1) as attendance_rate
|
||||
FROM departments d
|
||||
LEFT JOIN students s ON d.id = s.department_id
|
||||
LEFT JOIN attendance a ON s.id = a.student_id
|
||||
WHERE DATE(a.created_at) BETWEEN '$start_date' AND '$end_date'
|
||||
GROUP BY d.id
|
||||
HAVING total_attendance > 0
|
||||
ORDER BY attendance_rate DESC";
|
||||
|
||||
$result = query($conn, $sql);
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$department_stats[] = $row;
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">Attendance Reports</h1>
|
||||
<p class="text-muted">View and analyze attendance data with detailed reports.</p>
|
||||
</div>
|
||||
<div>
|
||||
<button class="btn btn-primary" onclick="printReport()">
|
||||
<i class="bi bi-printer me-2"></i> Print Report
|
||||
</button>
|
||||
<button class="btn btn-success" onclick="exportToExcel()">
|
||||
<i class="bi bi-download me-2"></i> Export Excel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Filter Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-funnel me-2"></i> Filter Reports
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="GET" action="">
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">Start Date</label>
|
||||
<input type="date" class="form-control" name="start_date"
|
||||
value="<?php echo $start_date; ?>" required>
|
||||
</div>
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">End Date</label>
|
||||
<input type="date" class="form-control" name="end_date"
|
||||
value="<?php echo $end_date; ?>" required>
|
||||
</div>
|
||||
<div class="col-md-2 mb-3">
|
||||
<label class="form-label">Activity</label>
|
||||
<select class="form-select" name="activity_id">
|
||||
<option value="">All Activities</option>
|
||||
<?php foreach ($activities as $activity): ?>
|
||||
<option value="<?php echo $activity['id']; ?>"
|
||||
<?php echo $activity_id == $activity['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $activity['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 mb-3">
|
||||
<label class="form-label">Course</label>
|
||||
<select class="form-select" name="course_id">
|
||||
<option value="">All Courses</option>
|
||||
<?php foreach ($courses as $course): ?>
|
||||
<option value="<?php echo $course['id']; ?>"
|
||||
<?php echo $course_id == $course['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $course['code']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-2 mb-3">
|
||||
<label class="form-label">Status</label>
|
||||
<select class="form-select" name="status">
|
||||
<option value="">All Status</option>
|
||||
<option value="present" <?php echo $status == 'present' ? 'selected' : ''; ?>>Present</option>
|
||||
<option value="late" <?php echo $status == 'late' ? 'selected' : ''; ?>>Late</option>
|
||||
<option value="absent" <?php echo $status == 'absent' ? 'selected' : ''; ?>>Absent</option>
|
||||
<option value="excused" <?php echo $status == 'excused' ? 'selected' : ''; ?>>Excused</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-3 mb-3">
|
||||
<label class="form-label">Department</label>
|
||||
<select class="form-select" name="department_id">
|
||||
<option value="">All Departments</option>
|
||||
<?php foreach ($departments as $department): ?>
|
||||
<option value="<?php echo $department['id']; ?>"
|
||||
<?php echo $department_id == $department['id'] ? 'selected' : ''; ?>>
|
||||
<?php echo $department['name']; ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-9 d-flex align-items-end justify-content-end">
|
||||
<button type="submit" class="btn btn-primary me-2">
|
||||
<i class="bi bi-filter me-1"></i> Apply Filters
|
||||
</button>
|
||||
<a href="reports.php" class="btn btn-secondary">
|
||||
<i class="bi bi-x-circle me-1"></i> Clear Filters
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Statistics Cards -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-primary">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-primary mb-1">Total Records</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['total']; ?></div>
|
||||
<div class="text-muted">Attendance records</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-clipboard-data text-primary" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-success">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-success mb-1">Present</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['present']; ?></div>
|
||||
<div class="text-muted">On-time attendance</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-check-circle-fill text-success" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-warning">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-warning mb-1">Late</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['late']; ?></div>
|
||||
<div class="text-muted">Late arrivals</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-clock-history text-warning" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-xl-3 col-md-6 mb-4">
|
||||
<div class="card stat-card border-left-danger">
|
||||
<div class="card-body">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-8">
|
||||
<div class="text-uppercase text-danger mb-1">Absent</div>
|
||||
<div class="h2 font-weight-bold"><?php echo $stats['absent']; ?></div>
|
||||
<div class="text-muted">No attendance</div>
|
||||
</div>
|
||||
<div class="col-4 text-end">
|
||||
<i class="bi bi-x-circle-fill text-danger" style="font-size: 3rem; opacity: 0.7;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Charts Section -->
|
||||
<div class="row mb-4">
|
||||
<!-- Attendance Summary Chart -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-header">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-pie-chart me-2"></i> Attendance Summary
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="chart-container" style="position: relative; height: 300px;">
|
||||
<canvas id="attendanceChart"></canvas>
|
||||
</div>
|
||||
<div class="row mt-3 text-center">
|
||||
<div class="col-3">
|
||||
<div class="text-success">
|
||||
<i class="bi bi-check-circle"></i>
|
||||
<div class="h5 mb-0"><?php echo $stats['present']; ?></div>
|
||||
<small>Present</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="text-warning">
|
||||
<i class="bi bi-clock-history"></i>
|
||||
<div class="h5 mb-0"><?php echo $stats['late']; ?></div>
|
||||
<small>Late</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="text-danger">
|
||||
<i class="bi bi-x-circle"></i>
|
||||
<div class="h5 mb-0"><?php echo $stats['absent']; ?></div>
|
||||
<small>Absent</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="text-info">
|
||||
<i class="bi bi-calendar-check"></i>
|
||||
<div class="h5 mb-0"><?php echo $stats['excused']; ?></div>
|
||||
<small>Excused</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Daily Trend Chart -->
|
||||
<div class="col-lg-6">
|
||||
<div class="card shadow h-100">
|
||||
<div class="card-header">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-bar-chart me-2"></i> Daily Attendance Trend
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="chart-container" style="position: relative; height: 300px;">
|
||||
<canvas id="dailyTrendChart"></canvas>
|
||||
</div>
|
||||
<div class="text-center mt-3">
|
||||
<small class="text-muted">
|
||||
<?php echo date('F j, Y', strtotime($start_date)); ?> to
|
||||
<?php echo date('F j, Y', strtotime($end_date)); ?>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activity Statistics Table -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-calendar-event me-2"></i> Activity-wise Statistics
|
||||
</h6>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="toggleActivityStats()">
|
||||
<i class="bi bi-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body" id="activityStatsBody">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="activityStatsTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Activity</th>
|
||||
<th>Total</th>
|
||||
<th>Present</th>
|
||||
<th>Late</th>
|
||||
<th>Attendance Rate</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($activity_stats)): ?>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center py-4">
|
||||
<i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No activity data for selected period</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($activity_stats as $stat): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong><?php echo $stat['activity_name']; ?></strong>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info"><?php echo $stat['total_attendance']; ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-success"><?php echo $stat['present']; ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-warning"><?php echo $stat['late']; ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="progress flex-grow-1 me-2" style="height: 8px;">
|
||||
<div class="progress-bar progress-bar-striped"
|
||||
role="progressbar"
|
||||
style="width: <?php echo $stat['attendance_rate']; ?>%">
|
||||
</div>
|
||||
</div>
|
||||
<span><?php echo $stat['attendance_rate']; ?>%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$activity_id_for_link = '';
|
||||
foreach ($activities as $activity) {
|
||||
if ($activity['name'] == $stat['activity_name']) {
|
||||
$activity_id_for_link = $activity['id'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($activity_id_for_link): ?>
|
||||
<a href="reports.php?activity_id=<?php echo $activity_id_for_link; ?>&start_date=<?php echo $start_date; ?>&end_date=<?php echo $end_date; ?>"
|
||||
class="btn btn-sm btn-info">
|
||||
<i class="bi bi-eye"></i> View
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Department Statistics Table -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-building me-2"></i> Department Performance
|
||||
</h6>
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="toggleDepartmentStats()">
|
||||
<i class="bi bi-chevron-down"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body" id="departmentStatsBody">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="departmentStatsTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Department</th>
|
||||
<th>Total</th>
|
||||
<th>Present</th>
|
||||
<th>Late</th>
|
||||
<th>Attendance Rate</th>
|
||||
<th>Performance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($department_stats)): ?>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center py-4">
|
||||
<i class="bi bi-building text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No department data for selected period</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($department_stats as $stat): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong><?php echo $stat['department_name']; ?></strong><br>
|
||||
<small class="text-muted"><?php echo $stat['department_code']; ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-info"><?php echo $stat['total_attendance']; ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-success"><?php echo $stat['present']; ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="badge bg-warning"><?php echo $stat['late']; ?></span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="progress flex-grow-1 me-2" style="height: 8px;">
|
||||
<div class="progress-bar progress-bar-striped"
|
||||
role="progressbar"
|
||||
style="width: <?php echo $stat['attendance_rate']; ?>%">
|
||||
</div>
|
||||
</div>
|
||||
<span><?php echo $stat['attendance_rate']; ?>%</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$rate = floatval($stat['attendance_rate']);
|
||||
if ($rate >= 90) {
|
||||
echo '<span class="badge bg-success">Excellent</span>';
|
||||
} elseif ($rate >= 80) {
|
||||
echo '<span class="badge bg-info">Good</span>';
|
||||
} elseif ($rate >= 70) {
|
||||
echo '<span class="badge bg-warning">Fair</span>';
|
||||
} else {
|
||||
echo '<span class="badge bg-danger">Poor</span>';
|
||||
}
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detailed Attendance Records -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header d-flex justify-content-between align-items-center">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-list-ul me-2"></i> Detailed Attendance Records
|
||||
<span class="badge bg-primary ms-2"><?php echo count($attendance_records); ?></span>
|
||||
</h6>
|
||||
<div>
|
||||
<input type="text" id="searchRecords" class="form-control form-control-sm me-2"
|
||||
placeholder="Search records..." style="width: 200px;">
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover mb-0" id="attendanceRecordsTable">
|
||||
<thead class="table-light">
|
||||
<tr>
|
||||
<th>Student</th>
|
||||
<th>Activity</th>
|
||||
<th>Date & Time</th>
|
||||
<th>Time In/Out</th>
|
||||
<th>Status</th>
|
||||
<th>Course</th>
|
||||
<th>Recorded By</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($attendance_records)): ?>
|
||||
<tr>
|
||||
<td colspan="7" class="text-center py-4">
|
||||
<i class="bi bi-clipboard-x text-muted" style="font-size: 3rem;"></i>
|
||||
<p class="mt-2">No attendance records found for the selected filters</p>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($attendance_records as $record): ?>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="avatar me-3">
|
||||
<div class="bg-primary rounded-circle p-2 text-white">
|
||||
<i class="bi bi-person"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<strong><?php echo $record['student_name']; ?></strong><br>
|
||||
<small class="text-muted"><?php echo $record['student_number']; ?></small>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo $record['activity_name']; ?></div>
|
||||
<small class="text-muted">
|
||||
<i class="bi bi-geo-alt"></i> <?php echo $record['activity_location']; ?>
|
||||
</small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo date('M d, Y', strtotime($record['created_at'])); ?></div>
|
||||
<small class="text-muted"><?php echo date('h:i A', strtotime($record['created_at'])); ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<div class="d-flex flex-column">
|
||||
<?php if ($record['time_in']): ?>
|
||||
<small>
|
||||
<i class="bi bi-box-arrow-in-right text-success"></i>
|
||||
<?php echo date('h:i A', strtotime($record['time_in'])); ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
<?php if ($record['time_out']): ?>
|
||||
<small>
|
||||
<i class="bi bi-box-arrow-left text-danger"></i>
|
||||
<?php echo date('h:i A', strtotime($record['time_out'])); ?>
|
||||
</small>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<?php
|
||||
$status = $record['status'] ?? 'pending';
|
||||
$badge_class = 'secondary';
|
||||
$icon = 'clock';
|
||||
|
||||
switch($status) {
|
||||
case 'present':
|
||||
$badge_class = 'success';
|
||||
$icon = 'check-circle';
|
||||
break;
|
||||
case 'late':
|
||||
$badge_class = 'warning';
|
||||
$icon = 'clock-history';
|
||||
break;
|
||||
case 'absent':
|
||||
$badge_class = 'danger';
|
||||
$icon = 'x-circle';
|
||||
break;
|
||||
case 'excused':
|
||||
$badge_class = 'info';
|
||||
$icon = 'calendar-check';
|
||||
break;
|
||||
default:
|
||||
$badge_class = 'secondary';
|
||||
$icon = 'clock';
|
||||
}
|
||||
?>
|
||||
<span class="badge bg-<?php echo $badge_class; ?>">
|
||||
<i class="bi bi-<?php echo $icon; ?> me-1"></i>
|
||||
<?php echo ucfirst($status); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="fw-bold"><?php echo $record['course_code']; ?></div>
|
||||
<small class="text-muted">Year <?php echo $record['year_level']; ?></small>
|
||||
</td>
|
||||
<td>
|
||||
<small>QR System</small>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<small class="text-muted">
|
||||
Showing <?php echo count($attendance_records); ?> record(s)
|
||||
</small>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<small class="text-muted">
|
||||
Generated: <?php echo date('F j, Y h:i A'); ?>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Print Modal -->
|
||||
<div class="modal fade" id="printModal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Print Preview</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="printContent">
|
||||
<!-- Print content will be loaded here -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" onclick="window.print()">
|
||||
<i class="bi bi-printer me-1"></i> Print
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
// Include Chart.js library
|
||||
$page_scripts = '
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Initialize DataTables
|
||||
$("#activityStatsTable").DataTable({
|
||||
pageLength: 5,
|
||||
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, "All"]],
|
||||
order: [[4, "desc"]],
|
||||
responsive: true
|
||||
});
|
||||
|
||||
$("#departmentStatsTable").DataTable({
|
||||
pageLength: 5,
|
||||
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, "All"]],
|
||||
order: [[4, "desc"]],
|
||||
responsive: true
|
||||
});
|
||||
|
||||
$("#attendanceRecordsTable").DataTable({
|
||||
pageLength: 10,
|
||||
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
|
||||
order: [[2, "desc"]],
|
||||
responsive: true
|
||||
});
|
||||
|
||||
// Search functionality
|
||||
$("#searchRecords").on("keyup", function() {
|
||||
$("#attendanceRecordsTable").DataTable().search($(this).val()).draw();
|
||||
});
|
||||
|
||||
// Initialize charts
|
||||
initializeCharts();
|
||||
});
|
||||
|
||||
// Initialize Charts
|
||||
function initializeCharts() {
|
||||
// Attendance Summary Chart (Pie Chart)
|
||||
const ctx1 = document.getElementById("attendanceChart").getContext("2d");
|
||||
new Chart(ctx1, {
|
||||
type: "pie",
|
||||
data: {
|
||||
labels: ["Present", "Late", "Absent", "Excused"],
|
||||
datasets: [{
|
||||
data: [' . $stats['present'] . ', ' . $stats['late'] . ', ' . $stats['absent'] . ', ' . $stats['excused'] . '],
|
||||
backgroundColor: [
|
||||
"#28a745",
|
||||
"#ffc107",
|
||||
"#dc3545",
|
||||
"#17a2b8"
|
||||
],
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "bottom"
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: function(context) {
|
||||
let label = context.label || "";
|
||||
if (label) {
|
||||
label += ": ";
|
||||
}
|
||||
label += context.parsed + " (" + Math.round((context.parsed / ' . $stats['total'] . ') * 100) + "%)";
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Daily Trend Chart (Line Chart)
|
||||
const ctx2 = document.getElementById("dailyTrendChart").getContext("2d");
|
||||
const dates = ' . json_encode(array_column($daily_trend, "date")) . ';
|
||||
const presentData = ' . json_encode(array_column($daily_trend, "present")) . ';
|
||||
const lateData = ' . json_encode(array_column($daily_trend, "late")) . ';
|
||||
const totalData = ' . json_encode(array_column($daily_trend, "total")) . ';
|
||||
|
||||
new Chart(ctx2, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: dates.map(date => new Date(date).toLocaleDateString("en-US", { month: "short", day: "numeric" })),
|
||||
datasets: [
|
||||
{
|
||||
label: "Total Attendance",
|
||||
data: totalData,
|
||||
borderColor: "#3498db",
|
||||
backgroundColor: "rgba(52, 152, 219, 0.1)",
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
},
|
||||
{
|
||||
label: "Present",
|
||||
data: presentData,
|
||||
borderColor: "#28a745",
|
||||
backgroundColor: "rgba(40, 167, 69, 0.1)",
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
},
|
||||
{
|
||||
label: "Late",
|
||||
data: lateData,
|
||||
borderColor: "#ffc107",
|
||||
backgroundColor: "rgba(255, 193, 7, 0.1)",
|
||||
fill: true,
|
||||
tension: 0.4
|
||||
}
|
||||
]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: "bottom"
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
title: {
|
||||
display: true,
|
||||
text: "Number of Students"
|
||||
}
|
||||
},
|
||||
x: {
|
||||
title: {
|
||||
display: true,
|
||||
text: "Date"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle sections
|
||||
function toggleActivityStats() {
|
||||
$("#activityStatsBody").slideToggle();
|
||||
}
|
||||
|
||||
function toggleDepartmentStats() {
|
||||
$("#departmentStatsBody").slideToggle();
|
||||
}
|
||||
|
||||
// Print report - Simple version
|
||||
function printReport() {
|
||||
window.print();
|
||||
}
|
||||
|
||||
// Export to Excel
|
||||
function exportToExcel() {
|
||||
showLoader("Preparing Excel export...");
|
||||
|
||||
const params = new URLSearchParams({
|
||||
start_date: "' . $start_date . '",
|
||||
end_date: "' . $end_date . '",
|
||||
activity_id: "' . $activity_id . '",
|
||||
course_id: "' . $course_id . '",
|
||||
department_id: "' . $department_id . '",
|
||||
status: "' . $status . '"
|
||||
});
|
||||
|
||||
fetch(`../api/export_reports.php?${params}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
hideLoader();
|
||||
if (data.success) {
|
||||
window.open(data.download_url, "_blank");
|
||||
showNotification("Export completed successfully!", "success");
|
||||
} else {
|
||||
showNotification("Error: " + data.message, "danger");
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
hideLoader();
|
||||
showNotification("Export failed: " + error, "danger");
|
||||
});
|
||||
}
|
||||
|
||||
// Quick filter buttons
|
||||
function filterToday() {
|
||||
const today = new Date().toISOString().split("T")[0];
|
||||
window.location.href = `reports.php?start_date=${today}&end_date=${today}`;
|
||||
}
|
||||
|
||||
function filterThisWeek() {
|
||||
const today = new Date();
|
||||
const firstDay = new Date(today.setDate(today.getDate() - today.getDay()));
|
||||
const lastDay = new Date(today.setDate(today.getDate() - today.getDay() + 6));
|
||||
|
||||
const start = firstDay.toISOString().split("T")[0];
|
||||
const end = lastDay.toISOString().split("T")[0];
|
||||
|
||||
window.location.href = `reports.php?start_date=${start}&end_date=${end}`;
|
||||
}
|
||||
|
||||
function filterThisMonth() {
|
||||
const today = new Date();
|
||||
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
||||
const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
||||
|
||||
const start = firstDay.toISOString().split("T")[0];
|
||||
const end = lastDay.toISOString().split("T")[0];
|
||||
|
||||
window.location.href = `reports.php?start_date=${start}&end_date=${end}`;
|
||||
}
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
767
src-backup/admin/users.php
Normal file
@@ -0,0 +1,767 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['user_id']) || $_SESSION['role'] !== 'admin') {
|
||||
header("Location: ../auth/login.php");
|
||||
exit();
|
||||
}
|
||||
|
||||
// Use absolute path with error checking
|
||||
$db_path = __DIR__ . '/../includes/database.php';
|
||||
if (!file_exists($db_path)) {
|
||||
die("Database configuration file not found at: $db_path");
|
||||
}
|
||||
|
||||
require_once $db_path;
|
||||
|
||||
// Check if $pdo is set
|
||||
if (!isset($pdo)) {
|
||||
die("Database connection failed. \$pdo variable not set.");
|
||||
}
|
||||
|
||||
$title = "User Management";
|
||||
|
||||
// Try different paths for header.php
|
||||
$header_paths = [
|
||||
'header.php', // Same directory
|
||||
__DIR__ . '/header.php', // Absolute path in admin
|
||||
__DIR__ . '/../header.php', // Parent directory (attendance_system)
|
||||
__DIR__ . '/../includes/header.php', // Includes directory
|
||||
__DIR__ . '/../templates/header.php', // Templates directory
|
||||
'C:/xampp/htdocs/attendance_system/header.php',
|
||||
'C:/xampp/htdocs/attendance_system/admin/header.php'
|
||||
];
|
||||
|
||||
$header_found = false;
|
||||
foreach ($header_paths as $path) {
|
||||
if (file_exists($path)) {
|
||||
include $path;
|
||||
$header_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$header_found) {
|
||||
// If header not found, create basic HTML structure
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo $title; ?></title>
|
||||
|
||||
<!-- Bootstrap 5 -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||
<!-- DataTables -->
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/dataTables.bootstrap5.min.css">
|
||||
|
||||
<style>
|
||||
body {
|
||||
background-color: #f5f7fb;
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.navbar {
|
||||
background: #37502c;
|
||||
}
|
||||
.card {
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
|
||||
margin-bottom: 15px;
|
||||
border: none;
|
||||
}
|
||||
.card-header {
|
||||
background: linear-gradient(135deg, #205e03 0%, #9bdb34 100%);
|
||||
color: white;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: none;
|
||||
padding: 12px 15px;
|
||||
}
|
||||
.table {
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||
margin-bottom: 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.table th {
|
||||
font-size: 0.8rem;
|
||||
padding: 8px 12px;
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 2px solid #dee2e6;
|
||||
}
|
||||
.table td {
|
||||
padding: 6px 12px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.table tbody tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.status-active {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.status-inactive {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.badge {
|
||||
font-size: 0.75rem;
|
||||
padding: 3px 6px;
|
||||
}
|
||||
.action-buttons .btn {
|
||||
padding: 3px 6px;
|
||||
font-size: 0.8rem;
|
||||
margin: 0 2px;
|
||||
}
|
||||
.search-box {
|
||||
position: relative;
|
||||
}
|
||||
.search-box i {
|
||||
position: absolute;
|
||||
left: 10px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #6c757d;
|
||||
}
|
||||
.search-box input {
|
||||
padding-left: 35px;
|
||||
font-size: 0.85rem;
|
||||
height: 36px;
|
||||
}
|
||||
.form-control, .form-select {
|
||||
font-size: 0.85rem;
|
||||
padding: 6px 10px;
|
||||
height: 36px;
|
||||
}
|
||||
.stat-card {
|
||||
padding: 12px;
|
||||
}
|
||||
.stat-card h3 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.stat-card h6 {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.stat-card i {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Simple Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
<div class="container-fluid">
|
||||
<a class="navbar-brand" href="#">
|
||||
<i class="bi bi-qr-code-scan me-2"></i>AMS - User Management
|
||||
</a>
|
||||
<div class="d-flex align-items-center text-white">
|
||||
<span class="me-3" style="font-size: 0.9rem;">
|
||||
<i class="bi bi-person-circle me-1"></i>
|
||||
<?php echo htmlspecialchars($_SESSION['full_name'] ?? 'User'); ?>
|
||||
</span>
|
||||
<a href="../auth/logout.php" class="btn btn-outline-light btn-sm" style="font-size: 0.8rem;">
|
||||
<i class="bi bi-box-arrow-right"></i> Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<!-- ================ START OF YOUR USER MANAGEMENT CONTENT ================ -->
|
||||
|
||||
<!-- Display messages -->
|
||||
<?php if (isset($_SESSION['message'])): ?>
|
||||
<?php $message_type = $_SESSION['message_type'] ?? 'success'; ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show py-2" role="alert" style="font-size: 0.85rem;">
|
||||
<?php echo $_SESSION['message']; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
?>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="content-wrapper">
|
||||
<div class="container-fluid">
|
||||
<div class="row mb-3">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header d-flex justify-content-between align-items-center py-2">
|
||||
<h6 class="mb-0" style="font-size: 0.9rem;"><i class="bi bi-people-fill me-1"></i>User Management</h6>
|
||||
<button class="btn btn-primary btn-sm py-1 px-2" data-bs-toggle="modal" data-bs-target="#addUserModal" style="font-size: 0.8rem;">
|
||||
<i class="bi bi-person-plus me-1"></i> Add User
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-3">
|
||||
<!-- Search and Filter -->
|
||||
<div class="row mb-2 g-2">
|
||||
<div class="col-md-6">
|
||||
<div class="search-box">
|
||||
<i class="bi bi-search"></i>
|
||||
<input type="text" class="form-control" id="searchInput" placeholder="Search users...">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select class="form-select" id="roleFilter">
|
||||
<option value="">All Roles</option>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="teacher">Teacher</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<select class="form-select" id="statusFilter">
|
||||
<option value="">All Status</option>
|
||||
<option value="1">Active</option>
|
||||
<option value="0">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Users Table - COMPACT VERSION -->
|
||||
<div class="table-responsive">
|
||||
<table class="table table-hover table-sm" id="usersTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="3%">#</th>
|
||||
<th width="20%">Full Name</th>
|
||||
<th width="18%">Email</th>
|
||||
<th width="12%">Username</th>
|
||||
<th width="10%">Role</th>
|
||||
<th width="10%">Status</th>
|
||||
<th width="12%">Created</th>
|
||||
<th width="15%">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php
|
||||
try {
|
||||
$query = "SELECT * FROM users ORDER BY created_at DESC";
|
||||
$stmt = $pdo->query($query);
|
||||
$users = $stmt->fetchAll(PDO::FETCH_ASSOC);
|
||||
$count = 1;
|
||||
|
||||
if (count($users) > 0):
|
||||
foreach ($users as $user):
|
||||
$status_class = $user['status'] ? 'status-active' : 'status-inactive';
|
||||
$status_text = $user['status'] ? 'Active' : 'Inactive';
|
||||
|
||||
$role_badge = '';
|
||||
switch($user['role']) {
|
||||
case 'admin': $role_badge = 'danger'; break;
|
||||
case 'teacher': $role_badge = 'success'; break;
|
||||
default: $role_badge = 'secondary';
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td class="text-muted"><?php echo $count++; ?></td>
|
||||
<td>
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="rounded-circle bg-light p-1 me-2">
|
||||
<i class="bi bi-person text-dark" style="font-size: 0.8rem;"></i>
|
||||
</div>
|
||||
<div>
|
||||
<div style="font-size: 0.85rem; font-weight: 500;"><?php echo htmlspecialchars($user['full_name']); ?></div>
|
||||
<?php if ($user['id'] == $_SESSION['user_id']): ?>
|
||||
<span class="badge bg-warning" style="font-size: 0.65rem;">You</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<small class="text-truncate d-inline-block" style="max-width: 150px;" title="<?php echo htmlspecialchars($user['email'] ?? 'N/A'); ?>">
|
||||
<?php echo htmlspecialchars($user['email'] ?? 'N/A'); ?>
|
||||
</small>
|
||||
</td>
|
||||
<td><code style="font-size: 0.8rem;"><?php echo htmlspecialchars($user['username']); ?></code></td>
|
||||
<td>
|
||||
<span class="badge bg-<?php echo $role_badge; ?>">
|
||||
<?php echo ucfirst($user['role']); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="<?php echo $status_class; ?>">
|
||||
<?php echo $status_text; ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><small><?php echo date('m/d/Y', strtotime($user['created_at'])); ?></small></td>
|
||||
<td>
|
||||
<div class="d-flex">
|
||||
<button class="btn btn-sm btn-outline-primary py-0 px-1"
|
||||
onclick="editUser(<?php echo $user['id']; ?>)"
|
||||
title="Edit User">
|
||||
<i class="bi bi-pencil" style="font-size: 0.8rem;"></i>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-<?php echo $user['status'] ? 'warning' : 'success'; ?> py-0 px-1 mx-1"
|
||||
onclick="toggleStatus(<?php echo $user['id']; ?>, <?php echo $user['status']; ?>)"
|
||||
title="<?php echo $user['status'] ? 'Deactivate' : 'Activate'; ?>">
|
||||
<i class="bi bi-<?php echo $user['status'] ? 'x-circle' : 'check-circle'; ?>" style="font-size: 0.8rem;"></i>
|
||||
</button>
|
||||
<?php if ($user['id'] != $_SESSION['user_id']): ?>
|
||||
<button class="btn btn-sm btn-outline-danger py-0 px-1"
|
||||
onclick="deleteUser(<?php echo $user['id']; ?>, '<?php echo htmlspecialchars($user['full_name']); ?>')"
|
||||
title="Delete User">
|
||||
<i class="bi bi-trash" style="font-size: 0.8rem;"></i>
|
||||
</button>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endforeach;
|
||||
else:
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-muted py-2">
|
||||
<i class="bi bi-people me-1"></i> No users found.
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
endif;
|
||||
} catch (PDOException $e) {
|
||||
?>
|
||||
<tr>
|
||||
<td colspan="8" class="text-center text-danger py-2">
|
||||
<i class="bi bi-exclamation-triangle me-1"></i> Error loading users
|
||||
</td>
|
||||
</tr>
|
||||
<?php } ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- User Stats - Compact Version -->
|
||||
<div class="row g-2">
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card py-2">
|
||||
<div class="card-body p-2">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1" style="font-size: 0.75rem;">Total Users</h6>
|
||||
<h4 class="mb-0" style="font-size: 1.2rem;">
|
||||
<?php
|
||||
$query = "SELECT COUNT(*) as total FROM users";
|
||||
$stmt = $pdo->query($query);
|
||||
echo $stmt->fetch()['total'] ?? 0;
|
||||
?>
|
||||
</h4>
|
||||
</div>
|
||||
<i class="bi bi-people text-primary" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card py-2">
|
||||
<div class="card-body p-2">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1" style="font-size: 0.75rem;">Active Users</h6>
|
||||
<h4 class="mb-0" style="font-size: 1.2rem;">
|
||||
<?php
|
||||
$query = "SELECT COUNT(*) as active FROM users WHERE status = 1";
|
||||
$stmt = $pdo->query($query);
|
||||
echo $stmt->fetch()['active'] ?? 0;
|
||||
?>
|
||||
</h4>
|
||||
</div>
|
||||
<i class="bi bi-check-circle text-success" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card py-2">
|
||||
<div class="card-body p-2">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1" style="font-size: 0.75rem;">Admins</h6>
|
||||
<h4 class="mb-0" style="font-size: 1.2rem;">
|
||||
<?php
|
||||
$query = "SELECT COUNT(*) as admins FROM users WHERE role = 'admin'";
|
||||
$stmt = $pdo->query($query);
|
||||
echo $stmt->fetch()['admins'] ?? 0;
|
||||
?>
|
||||
</h4>
|
||||
</div>
|
||||
<i class="bi bi-shield-check text-danger" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="card stat-card py-2">
|
||||
<div class="card-body p-2">
|
||||
<div class="d-flex justify-content-between align-items-center">
|
||||
<div>
|
||||
<h6 class="text-muted mb-1" style="font-size: 0.75rem;">Teachers</h6>
|
||||
<h4 class="mb-0" style="font-size: 1.2rem;">
|
||||
<?php
|
||||
$query = "SELECT COUNT(*) as teachers FROM users WHERE role = 'teacher'";
|
||||
$stmt = $pdo->query($query);
|
||||
echo $stmt->fetch()['teachers'] ?? 0;
|
||||
?>
|
||||
</h4>
|
||||
</div>
|
||||
<i class="bi bi-person-badge text-info" style="font-size: 1.5rem;"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================ MODALS SECTION ================ -->
|
||||
|
||||
<!-- Add User Modal -->
|
||||
<div class="modal fade" id="addUserModal" tabindex="-1" aria-labelledby="addUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-md">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header py-2">
|
||||
<h6 class="modal-title mb-0" id="addUserModalLabel"><i class="bi bi-person-plus me-1"></i>Add New User</h6>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="process_user.php" method="POST" id="addUserForm">
|
||||
<div class="modal-body p-3">
|
||||
<input type="hidden" name="action" value="add">
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="full_name" class="form-label" style="font-size: 0.85rem;">Full Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="full_name" name="full_name" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="username" class="form-label" style="font-size: 0.85rem;">Username <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="username" name="username" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label for="email" class="form-label" style="font-size: 0.85rem;">Email Address</label>
|
||||
<input type="email" class="form-control form-control-sm" id="email" name="email">
|
||||
</div>
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="password" class="form-label" style="font-size: 0.85rem;">Password <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control form-control-sm" id="password" name="password" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="confirm_password" class="form-label" style="font-size: 0.85rem;">Confirm Password <span class="text-danger">*</span></label>
|
||||
<input type="password" class="form-control form-control-sm" id="confirm_password" name="confirm_password" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="role" class="form-label" style="font-size: 0.85rem;">Role <span class="text-danger">*</span></label>
|
||||
<select class="form-select form-select-sm" id="role" name="role" required>
|
||||
<option value="">Select Role</option>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="teacher">Teacher</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="status" class="form-label" style="font-size: 0.85rem;">Status</label>
|
||||
<select class="form-select form-select-sm" id="status" name="status">
|
||||
<option value="1">Active</option>
|
||||
<option value="0">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Add User</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Edit User Modal -->
|
||||
<div class="modal fade" id="editUserModal" tabindex="-1" aria-labelledby="editUserModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-md">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header py-2">
|
||||
<h6 class="modal-title mb-0" id="editUserModalLabel"><i class="bi bi-pencil me-1"></i>Edit User</h6>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<form action="process_user.php" method="POST" id="editUserForm">
|
||||
<div class="modal-body p-3">
|
||||
<input type="hidden" name="action" value="edit">
|
||||
<input type="hidden" id="edit_user_id" name="user_id">
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="edit_full_name" class="form-label" style="font-size: 0.85rem;">Full Name <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="edit_full_name" name="full_name" required>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="edit_username" class="form-label" style="font-size: 0.85rem;">Username <span class="text-danger">*</span></label>
|
||||
<input type="text" class="form-control form-control-sm" id="edit_username" name="username" required>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<label for="edit_email" class="form-label" style="font-size: 0.85rem;">Email Address</label>
|
||||
<input type="email" class="form-control form-control-sm" id="edit_email" name="email">
|
||||
</div>
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="edit_password" class="form-label" style="font-size: 0.85rem;">New Password (leave blank)</label>
|
||||
<input type="password" class="form-control form-control-sm" id="edit_password" name="password">
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="edit_confirm_password" class="form-label" style="font-size: 0.85rem;">Confirm New Password</label>
|
||||
<input type="password" class="form-control form-control-sm" id="edit_confirm_password" name="confirm_password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-2">
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="edit_role" class="form-label" style="font-size: 0.85rem;">Role <span class="text-danger">*</span></label>
|
||||
<select class="form-select form-select-sm" id="edit_role" name="role" required>
|
||||
<option value="">Select Role</option>
|
||||
<option value="admin">Admin</option>
|
||||
<option value="teacher">Teacher</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-6 mb-2">
|
||||
<label for="edit_status" class="form-label" style="font-size: 0.85rem;">Status</label>
|
||||
<select class="form-select form-select-sm" id="edit_status" name="status">
|
||||
<option value="1">Active</option>
|
||||
<option value="0">Inactive</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer py-2">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary btn-sm">Update User</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-sm">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white py-2">
|
||||
<h6 class="modal-title mb-0" id="deleteModalLabel"><i class="bi bi-exclamation-triangle me-1"></i>Confirm Delete</h6>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body p-3">
|
||||
<p class="mb-2" style="font-size: 0.85rem;">Delete user: <strong id="deleteUserName"></strong>?</p>
|
||||
<p class="text-danger mb-0" style="font-size: 0.8rem;"><i class="bi bi-exclamation-circle me-1"></i>Cannot be undone.</p>
|
||||
</div>
|
||||
<div class="modal-footer py-2">
|
||||
<button type="button" class="btn btn-secondary btn-sm" data-bs-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger btn-sm" id="confirmDelete">Delete</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ================ JAVASCRIPT SECTION ================ -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Table filtering and search - COMPACT VERSION
|
||||
$(document).ready(function() {
|
||||
const table = $('#usersTable').DataTable({
|
||||
pageLength: 15, // More rows per page
|
||||
lengthMenu: [[10, 15, 25, 50, -1], [10, 15, 25, 50, "All"]],
|
||||
responsive: true,
|
||||
dom: '<"row"<"col-sm-12"fr>>rt<"row"<"col-sm-6"i><"col-sm-6"p>>',
|
||||
language: {
|
||||
search: "_INPUT_",
|
||||
searchPlaceholder: "Search...",
|
||||
lengthMenu: "Show _MENU_ entries",
|
||||
info: "Showing _START_ to _END_ of _TOTAL_ users",
|
||||
paginate: {
|
||||
first: "First",
|
||||
last: "Last",
|
||||
next: "→",
|
||||
previous: "←"
|
||||
}
|
||||
},
|
||||
columnDefs: [
|
||||
{ orderable: false, targets: [7] } // Make actions column not sortable
|
||||
]
|
||||
});
|
||||
|
||||
$('#searchInput').on('keyup', function() {
|
||||
table.search(this.value).draw();
|
||||
});
|
||||
|
||||
$('#roleFilter').on('change', function() {
|
||||
table.column(4).search(this.value).draw();
|
||||
});
|
||||
|
||||
$('#statusFilter').on('change', function() {
|
||||
table.column(5).search(this.value).draw();
|
||||
});
|
||||
});
|
||||
|
||||
// Edit User Function
|
||||
function editUser(userId) {
|
||||
fetch(`get_user.php?id=${userId}`)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
const user = data.user;
|
||||
document.getElementById('edit_user_id').value = user.id;
|
||||
document.getElementById('edit_full_name').value = user.full_name;
|
||||
document.getElementById('edit_username').value = user.username;
|
||||
document.getElementById('edit_email').value = user.email || '';
|
||||
document.getElementById('edit_role').value = user.role;
|
||||
document.getElementById('edit_status').value = user.status;
|
||||
|
||||
const editModal = new bootstrap.Modal(document.getElementById('editUserModal'));
|
||||
editModal.show();
|
||||
} else {
|
||||
alert('Error loading user data: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error loading user data');
|
||||
});
|
||||
}
|
||||
|
||||
// Toggle User Status
|
||||
function toggleStatus(userId, currentStatus) {
|
||||
if (confirm(`Are you sure you want to ${currentStatus ? 'deactivate' : 'activate'} this user?`)) {
|
||||
const formData = new FormData();
|
||||
formData.append('action', 'toggle_status');
|
||||
formData.append('user_id', userId);
|
||||
|
||||
fetch('process_user.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + data.message);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error updating user status');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Delete User Function
|
||||
let userToDelete = null;
|
||||
let userNameToDelete = '';
|
||||
|
||||
function deleteUser(userId, userName) {
|
||||
userToDelete = userId;
|
||||
userNameToDelete = userName;
|
||||
document.getElementById('deleteUserName').textContent = userName;
|
||||
const deleteModal = new bootstrap.Modal(document.getElementById('deleteModal'));
|
||||
deleteModal.show();
|
||||
}
|
||||
|
||||
// Confirm Delete
|
||||
document.getElementById('confirmDelete').addEventListener('click', function() {
|
||||
if (userToDelete) {
|
||||
const formData = new FormData();
|
||||
formData.append('action', 'delete');
|
||||
formData.append('user_id', userToDelete);
|
||||
|
||||
fetch('process_user.php', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert('Error: ' + data.message);
|
||||
bootstrap.Modal.getInstance(document.getElementById('deleteModal')).hide();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Error:', error);
|
||||
alert('Error deleting user');
|
||||
bootstrap.Modal.getInstance(document.getElementById('deleteModal')).hide();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Form Validation
|
||||
document.getElementById('addUserForm').addEventListener('submit', function(e) {
|
||||
const password = document.getElementById('password').value;
|
||||
const confirmPassword = document.getElementById('confirm_password').value;
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
e.preventDefault();
|
||||
alert('Passwords do not match!');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
e.preventDefault();
|
||||
alert('Password must be at least 6 characters long!');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
document.getElementById('editUserForm').addEventListener('submit', function(e) {
|
||||
const password = document.getElementById('edit_password').value;
|
||||
const confirmPassword = document.getElementById('edit_confirm_password').value;
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
e.preventDefault();
|
||||
alert('Passwords do not match!');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password && password.length < 6) {
|
||||
e.preventDefault();
|
||||
alert('Password must be at least 6 characters long!');
|
||||
return false;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php
|
||||
// Check if we need to close HTML tags (if no header was found)
|
||||
if (!$header_found) {
|
||||
echo '</div></body></html>';
|
||||
}
|
||||
?>
|
||||
249
src-backup/admin/view_activity.php
Normal file
@@ -0,0 +1,249 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "View Activity";
|
||||
|
||||
// Get activity ID
|
||||
$activity_id = $_GET['id'] ?? 0;
|
||||
|
||||
if ($activity_id <= 0) {
|
||||
$_SESSION['message'] = 'Invalid activity ID!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_activities.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get activity data with related information
|
||||
$sql = "SELECT a.*, u.full_name as created_by_name,
|
||||
c.code as course_code, c.name as course_name,
|
||||
d.code as department_code, d.name as department_name
|
||||
FROM activities a
|
||||
LEFT JOIN users u ON a.created_by = u.id
|
||||
LEFT JOIN courses c ON a.course_id = c.id
|
||||
LEFT JOIN departments d ON a.department_id = d.id
|
||||
WHERE a.id = $activity_id";
|
||||
$result = query($conn, $sql);
|
||||
if (!$result || mysqli_num_rows($result) == 0) {
|
||||
$_SESSION['message'] = 'Activity not found!';
|
||||
$_SESSION['message_type'] = 'danger';
|
||||
header('Location: manage_activities.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$activity = mysqli_fetch_assoc($result);
|
||||
|
||||
// Get attendance stats
|
||||
$attendance_sql = "SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present,
|
||||
SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late,
|
||||
SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent
|
||||
FROM attendance
|
||||
WHERE activity_id = " . $activity['id'];
|
||||
$attendance_result = query($conn, $attendance_sql);
|
||||
$stats = mysqli_fetch_assoc($attendance_result);
|
||||
|
||||
$today = date('Y-m-d');
|
||||
$current_time = date('H:i:s');
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">Activity Details</h1>
|
||||
<p class="text-muted">View detailed information about the activity.</p>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_activities.php" class="btn btn-secondary">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Activities
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Activity Details -->
|
||||
<div class="row">
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header">
|
||||
<h5 class="mb-0"><?php echo htmlspecialchars($activity['name']); ?></h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-4">
|
||||
<h6>Description</h6>
|
||||
<p><?php echo nl2br(htmlspecialchars($activity['description'] ?: 'No description provided')); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6><i class="bi bi-calendar me-2"></i> Date</h6>
|
||||
<p><?php echo date('l, F j, Y', strtotime($activity['date'])); ?></p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6><i class="bi bi-clock me-2"></i> Time</h6>
|
||||
<p>
|
||||
<?php echo date('h:i A', strtotime($activity['time_in'])); ?> -
|
||||
<?php echo date('h:i A', strtotime($activity['time_out'])); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6><i class="bi bi-geo-alt me-2"></i> Location</h6>
|
||||
<p><?php echo htmlspecialchars($activity['location']); ?></p>
|
||||
</div>
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6><i class="bi bi-people me-2"></i> Participants</h6>
|
||||
<p>
|
||||
<?php
|
||||
switch($activity['required_students']) {
|
||||
case 'all':
|
||||
echo '<span class="badge bg-info">All Students</span>';
|
||||
break;
|
||||
case 'specific_course':
|
||||
echo '<span class="badge bg-warning">' . ($activity['course_name'] ?? 'Specific Course') . '</span>';
|
||||
break;
|
||||
case 'specific_department':
|
||||
echo '<span class="badge bg-primary">' . ($activity['department_name'] ?? 'Specific Department') . '</span>';
|
||||
break;
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6>Status</h6>
|
||||
<p>
|
||||
<?php if ($activity['status'] == 1): ?>
|
||||
<span class="badge bg-success">Active</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">Inactive</span>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$activity_date = $activity['date'];
|
||||
$activity_start = $activity['time_in'];
|
||||
$activity_end = $activity['time_out'];
|
||||
|
||||
if ($activity_date > $today) {
|
||||
echo '<span class="badge bg-primary ms-2">Upcoming</span>';
|
||||
} elseif ($activity_date == $today && $current_time >= $activity_start && $current_time <= $activity_end) {
|
||||
echo '<span class="badge bg-success ms-2">Ongoing</span>';
|
||||
} else {
|
||||
echo '<span class="badge bg-secondary ms-2">Past</span>';
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 mb-3">
|
||||
<h6>Created By</h6>
|
||||
<p><?php echo htmlspecialchars($activity['created_by_name']); ?></p>
|
||||
<small class="text-muted">
|
||||
Created: <?php echo date('F j, Y', strtotime($activity['created_at'])); ?><br>
|
||||
<?php if ($activity['updated_at'] != $activity['created_at']): ?>
|
||||
Updated: <?php echo date('F j, Y', strtotime($activity['updated_at'])); ?>
|
||||
<?php endif; ?>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="btn-group">
|
||||
<a href="edit_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-warning">
|
||||
<i class="bi bi-pencil me-1"></i> Edit
|
||||
</a>
|
||||
<a href="reports.php?activity_id=<?php echo $activity['id']; ?>" class="btn btn-primary">
|
||||
<i class="bi bi-file-earmark-text me-1"></i> View Report
|
||||
</a>
|
||||
<?php if ($activity['date'] == $today && $current_time >= $activity['time_in'] && $current_time <= $activity['time_out']): ?>
|
||||
<a href="../admin/attendance.php" class="btn btn-success">
|
||||
<i class="bi bi-qr-code-scan me-1"></i> Take Attendance
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-4">
|
||||
<!-- Attendance Stats Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">Attendance Statistics</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<span>Attendance Rate</span>
|
||||
<strong><?php echo $stats['total'] > 0 ? round(($stats['present'] / $stats['total']) * 100, 1) : 0; ?>%</strong>
|
||||
</div>
|
||||
<div class="progress" style="height: 8px;">
|
||||
<div class="progress-bar" role="progressbar"
|
||||
style="width: <?php echo $stats['total'] > 0 ? ($stats['present'] / $stats['total'] * 100) : 0; ?>%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<small class="d-flex justify-content-between">
|
||||
<span>Present:</span>
|
||||
<strong><?php echo $stats['present'] ?: 0; ?></strong>
|
||||
</small>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<small class="d-flex justify-content-between">
|
||||
<span>Late:</span>
|
||||
<strong><?php echo $stats['late'] ?: 0; ?></strong>
|
||||
</small>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<small class="d-flex justify-content-between">
|
||||
<span>Absent:</span>
|
||||
<strong><?php echo $stats['absent'] ?: 0; ?></strong>
|
||||
</small>
|
||||
</div>
|
||||
<div class="mt-3 pt-3 border-top">
|
||||
<small class="d-flex justify-content-between">
|
||||
<span>Total:</span>
|
||||
<strong><?php echo $stats['total'] ?: 0; ?></strong>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">Quick Actions</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="d-grid gap-2">
|
||||
<a href="reports.php?activity_id=<?php echo $activity['id']; ?>"
|
||||
class="btn btn-primary">
|
||||
<i class="bi bi-file-earmark-text me-1"></i> View Full Report
|
||||
</a>
|
||||
<a href="../admin/attendance.php" class="btn btn-success">
|
||||
<i class="bi bi-qr-code-scan me-1"></i> Take Attendance
|
||||
</a>
|
||||
<a href="edit_activity.php?id=<?php echo $activity['id']; ?>" class="btn btn-warning">
|
||||
<i class="bi bi-pencil me-1"></i> Edit Activity
|
||||
</a>
|
||||
<a href="manage_activities.php" class="btn btn-secondary">
|
||||
<i class="bi bi-list-ul me-1"></i> Back to List
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php include '../includes/footer.php'; ?>
|
||||
586
src-backup/admin/view_student.php
Normal file
@@ -0,0 +1,586 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
$title = "View Student";
|
||||
|
||||
// Initialize variables
|
||||
$student_id = isset($_GET['id']) ? intval($_GET['id']) : 0;
|
||||
$message = '';
|
||||
$message_type = '';
|
||||
|
||||
// Check for URL messages
|
||||
if (isset($_GET['msg'])) {
|
||||
switch ($_GET['msg']) {
|
||||
case 'added':
|
||||
$message = 'Student added successfully!';
|
||||
$message_type = 'success';
|
||||
break;
|
||||
case 'updated':
|
||||
$message = 'Student updated successfully!';
|
||||
$message_type = 'success';
|
||||
break;
|
||||
case 'deleted':
|
||||
$message = 'Student deleted successfully!';
|
||||
$message_type = 'success';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Get student data
|
||||
$student = null;
|
||||
if ($student_id > 0) {
|
||||
$sql = "SELECT s.*, g.name as gender, c.code as course_code, c.name as course_name,
|
||||
d.code as department_code, d.name as department_name,
|
||||
sc.code as school_code, sc.name as school_name
|
||||
FROM students s
|
||||
LEFT JOIN genders g ON s.gender_id = g.id
|
||||
LEFT JOIN courses c ON s.course_id = c.id
|
||||
LEFT JOIN departments d ON s.department_id = d.id
|
||||
LEFT JOIN schools sc ON s.school_id = sc.id
|
||||
WHERE s.id = ?";
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $student_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
|
||||
if ($result && mysqli_num_rows($result) > 0) {
|
||||
$student = mysqli_fetch_assoc($result);
|
||||
} else {
|
||||
$message = 'Student not found!';
|
||||
$message_type = 'danger';
|
||||
header('Location: manage_students.php?msg=notfound');
|
||||
exit();
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
} else {
|
||||
$message = 'Invalid student ID!';
|
||||
$message_type = 'danger';
|
||||
header('Location: manage_students.php?msg=invalid');
|
||||
exit();
|
||||
}
|
||||
|
||||
include '../includes/header.php';
|
||||
?>
|
||||
|
||||
<!-- Page Header -->
|
||||
<div class="container-fluid">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
<div>
|
||||
<h1 class="h3 mb-2">
|
||||
<i class="bi bi-person me-2"></i> Student Details
|
||||
</h1>
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="dashboard.php">Dashboard</a></li>
|
||||
<li class="breadcrumb-item"><a href="manage_students.php">Manage Students</a></li>
|
||||
<li class="breadcrumb-item active">View Student</li>
|
||||
</ol>
|
||||
</nav>
|
||||
</div>
|
||||
<div>
|
||||
<a href="manage_students.php" class="btn btn-outline-secondary me-2">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Students
|
||||
</a>
|
||||
<a href="edit_student.php?id=<?php echo $student_id; ?>" class="btn btn-warning">
|
||||
<i class="bi bi-pencil me-2"></i> Edit Student
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Alert -->
|
||||
<?php if ($message): ?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-<?php echo $message_type == 'success' ? 'check-circle' : 'exclamation-triangle'; ?> me-2"></i>
|
||||
<?php echo $message; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($student): ?>
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<!-- Profile Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-body text-center">
|
||||
<?php if (!empty($student['picture_path'])): ?>
|
||||
<img src="../<?php echo htmlspecialchars($student['picture_path']); ?>"
|
||||
alt="Student Photo" class="rounded-circle mb-3"
|
||||
style="width: 150px; height: 150px; object-fit: cover;">
|
||||
<?php else: ?>
|
||||
<div class="bg-primary rounded-circle d-flex align-items-center justify-content-center mx-auto mb-3"
|
||||
style="width: 150px; height: 150px;">
|
||||
<i class="bi bi-person" style="font-size: 4rem; color: white;"></i>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h4><?php echo htmlspecialchars($student['full_name']); ?></h4>
|
||||
<p class="text-muted mb-1"><?php echo htmlspecialchars($student['student_id']); ?></p>
|
||||
|
||||
<div class="mb-3">
|
||||
<?php if ($student['status'] == 1): ?>
|
||||
<span class="badge bg-success">
|
||||
<i class="bi bi-check-circle me-1"></i> Active
|
||||
</span>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger">
|
||||
<i class="bi bi-x-circle me-1"></i> Inactive
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="d-grid gap-2">
|
||||
<a href="edit_student.php?id=<?php echo $student_id; ?>" class="btn btn-warning">
|
||||
<i class="bi bi-pencil me-2"></i> Edit Profile
|
||||
</a>
|
||||
|
||||
<div class="btn-group">
|
||||
<a href="../qr/generate.php?id=<?php echo $student_id; ?>"
|
||||
class="btn btn-primary" target="_blank">
|
||||
<i class="bi bi-qr-code me-2"></i> View QR
|
||||
</a>
|
||||
<button type="button" class="btn btn-primary dropdown-toggle dropdown-toggle-split"
|
||||
data-bs-toggle="dropdown">
|
||||
<span class="visually-hidden">Toggle Dropdown</span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a class="dropdown-item" href="../qr/generate.php?id=<?php echo $student_id; ?>&print=1" target="_blank">
|
||||
<i class="bi bi-printer me-2"></i> Print QR
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="../qr/generate.php?id=<?php echo $student_id; ?>&download=1">
|
||||
<i class="bi bi-download me-2"></i> Download QR
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="dropdown-item" href="../qr/generate.php?id=<?php echo $student_id; ?>&autoPrint=1" target="_blank">
|
||||
<i class="bi bi-printer-fill me-2"></i> Auto Print
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal">
|
||||
<i class="bi bi-trash me-2"></i> Delete Student
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- QR Code Card -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-info text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-qr-code me-2"></i> QR Code Information
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<strong class="d-block">QR Code</strong>
|
||||
<code class="text-break"><?php echo htmlspecialchars($student['qr_code']); ?></code>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<strong class="d-block">Generated</strong>
|
||||
<?php echo date('F j, Y, h:i A', strtotime($student['created_at'])); ?>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<a href="../qr/generate.php?id=<?php echo $student_id; ?>"
|
||||
class="btn btn-outline-primary btn-sm" target="_blank">
|
||||
<i class="bi bi-eye me-1"></i> Preview QR Code
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-lg-8">
|
||||
<!-- Student Information Card -->
|
||||
<div class="card shadow mb-4">
|
||||
<div class="card-header bg-primary text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-person-lines-fill me-2"></i> Personal Information
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Student ID</strong>
|
||||
<h5 class="text-primary"><?php echo htmlspecialchars($student['student_id']); ?></h5>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Full Name</strong>
|
||||
<h5><?php echo htmlspecialchars($student['full_name']); ?></h5>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Gender</strong>
|
||||
<p class="mb-0"><?php echo htmlspecialchars($student['gender']); ?></p>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Birth Date</strong>
|
||||
<p class="mb-0">
|
||||
<?php if ($student['birth_date']): ?>
|
||||
<?php echo date('F j, Y', strtotime($student['birth_date'])); ?>
|
||||
<small class="text-muted">
|
||||
(<?php echo date_diff(date_create($student['birth_date']), date_create('today'))->y; ?> years old)
|
||||
</small>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">Not set</span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Contact Information</strong>
|
||||
<?php if (!empty($student['email'])): ?>
|
||||
<div class="d-flex align-items-center mb-2">
|
||||
<i class="bi bi-envelope me-2 text-muted"></i>
|
||||
<a href="mailto:<?php echo htmlspecialchars($student['email']); ?>">
|
||||
<?php echo htmlspecialchars($student['email']); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!empty($student['contact_number'])): ?>
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-telephone me-2 text-muted"></i>
|
||||
<a href="tel:<?php echo htmlspecialchars($student['contact_number']); ?>">
|
||||
<?php echo htmlspecialchars($student['contact_number']); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Address</strong>
|
||||
<p class="mb-0">
|
||||
<?php if (!empty($student['address'])): ?>
|
||||
<?php echo nl2br(htmlspecialchars($student['address'])); ?>
|
||||
<?php else: ?>
|
||||
<span class="text-muted">Not set</span>
|
||||
<?php endif; ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Academic Information Card -->
|
||||
<div class="card shadow">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h6 class="m-0 font-weight-bold">
|
||||
<i class="bi bi-mortarboard me-2"></i> Academic Information
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Year Level</strong>
|
||||
<span class="badge bg-info" style="font-size: 1rem;">
|
||||
Year <?php echo $student['year_level']; ?>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">School</strong>
|
||||
<h5><?php echo htmlspecialchars($student['school_name']); ?></h5>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Department</strong>
|
||||
<h5><?php echo htmlspecialchars($student['department_name']); ?></h5>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($student['department_code']); ?></small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Course</strong>
|
||||
<h5><?php echo htmlspecialchars($student['course_name']); ?></h5>
|
||||
<small class="text-muted"><?php echo htmlspecialchars($student['course_code']); ?></small>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<strong class="d-block text-muted mb-1">Account Status</strong>
|
||||
<?php if ($student['status'] == 1): ?>
|
||||
<span class="badge bg-success" style="font-size: 1rem;">
|
||||
<i class="bi bi-check-circle me-1"></i> Active
|
||||
</span>
|
||||
<p class="mt-1 mb-0 text-muted">Student can log in and use the system</p>
|
||||
<?php else: ?>
|
||||
<span class="badge bg-danger" style="font-size: 1rem;">
|
||||
<i class="bi bi-x-circle me-1"></i> Inactive
|
||||
</span>
|
||||
<p class="mt-1 mb-0 text-muted">Student cannot log in to the system</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="d-block text-muted mb-1">Date Created</strong>
|
||||
<p class="mb-0">
|
||||
<i class="bi bi-calendar-plus me-1"></i>
|
||||
<?php echo date('F j, Y, h:i A', strtotime($student['created_at'])); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<strong class="d-block text-muted mb-1">Last Updated</strong>
|
||||
<p class="mb-0">
|
||||
<i class="bi bi-clock-history me-1"></i>
|
||||
<?php echo date('F j, Y, h:i A', strtotime($student['updated_at'])); ?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Modal -->
|
||||
<div class="modal fade" id="deleteModal" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-danger text-white">
|
||||
<h5 class="modal-title">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i> Confirm Delete
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Are you sure you want to delete student <strong><?php echo htmlspecialchars($student['full_name']); ?></strong>?</p>
|
||||
<p class="text-danger">
|
||||
<i class="bi bi-exclamation-circle me-1"></i>
|
||||
This action cannot be undone. All related activities and records will also be deleted.
|
||||
</p>
|
||||
<div class="alert alert-warning">
|
||||
<i class="bi bi-info-circle me-2"></i>
|
||||
<strong>Student Information:</strong><br>
|
||||
ID: <?php echo htmlspecialchars($student['student_id']); ?><br>
|
||||
Course: <?php echo htmlspecialchars($student['course_code']); ?><br>
|
||||
Department: <?php echo htmlspecialchars($student['department_name']); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<form method="POST" action="manage_students.php" style="display: inline;">
|
||||
<input type="hidden" name="delete_student" value="1">
|
||||
<input type="hidden" name="id" value="<?php echo $student_id; ?>">
|
||||
<button type="submit" class="btn btn-danger">
|
||||
<i class="bi bi-trash me-2"></i> Delete Student
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php else: ?>
|
||||
<!-- Student Not Found -->
|
||||
<div class="card shadow">
|
||||
<div class="card-body text-center py-5">
|
||||
<i class="bi bi-person-x" style="font-size: 4rem; color: #dc3545;"></i>
|
||||
<h3 class="mt-3">Student Not Found</h3>
|
||||
<p class="text-muted">The student you're trying to view does not exist or has been deleted.</p>
|
||||
<a href="manage_students.php" class="btn btn-primary mt-3">
|
||||
<i class="bi bi-arrow-left me-2"></i> Back to Students List
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
$page_scripts = '
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Print student information
|
||||
$("#printStudentBtn").click(function() {
|
||||
const printWindow = window.open("", "_blank");
|
||||
printWindow.document.write(`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Student Information - <?php echo htmlspecialchars($student[\'student_id\']); ?></title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 20px; }
|
||||
h1 { text-align: center; margin-bottom: 30px; }
|
||||
.student-info { margin-bottom: 30px; }
|
||||
.section { margin-bottom: 20px; }
|
||||
.section-title { font-weight: bold; border-bottom: 2px solid #333; padding-bottom: 5px; margin-bottom: 10px; }
|
||||
.info-row { margin-bottom: 8px; }
|
||||
.label { font-weight: bold; display: inline-block; width: 150px; }
|
||||
.footer { text-align: center; margin-top: 30px; font-size: 12px; color: #666; }
|
||||
@media print {
|
||||
.no-print { display: none; }
|
||||
button { display: none; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Student Information</h1>
|
||||
<div class="student-info">
|
||||
<div class="section">
|
||||
<div class="section-title">Personal Information</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Student ID:</span>
|
||||
<?php echo htmlspecialchars($student[\'student_id\']); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Full Name:</span>
|
||||
<?php echo htmlspecialchars($student[\'full_name\']); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Gender:</span>
|
||||
<?php echo htmlspecialchars($student[\'gender\']); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Birth Date:</span>
|
||||
<?php echo $student[\'birth_date\'] ? date(\'F j, Y\', strtotime($student[\'birth_date\'])) : \'Not set\'; ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Contact:</span>
|
||||
<?php echo !empty($student[\'contact_number\']) ? htmlspecialchars($student[\'contact_number\']) : \'Not set\'; ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Email:</span>
|
||||
<?php echo !empty($student[\'email\']) ? htmlspecialchars($student[\'email\']) : \'Not set\'; ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Address:</span>
|
||||
<?php echo !empty($student[\'address\']) ? htmlspecialchars($student[\'address\']) : \'Not set\'; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">Academic Information</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Year Level:</span>
|
||||
Year <?php echo $student[\'year_level\']; ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">School:</span>
|
||||
<?php echo htmlspecialchars($student[\'school_name\']); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Department:</span>
|
||||
<?php echo htmlspecialchars($student[\'department_name\']); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Course:</span>
|
||||
<?php echo htmlspecialchars($student[\'course_name\']); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Status:</span>
|
||||
<?php echo $student[\'status\'] == 1 ? \'Active\' : \'Inactive\'; ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">QR Code:</span>
|
||||
<?php echo htmlspecialchars($student[\'qr_code\']); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<div class="section-title">System Information</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Date Created:</span>
|
||||
<?php echo date(\'F j, Y, h:i A\', strtotime($student[\'created_at\'])); ?>
|
||||
</div>
|
||||
<div class="info-row">
|
||||
<span class="label">Last Updated:</span>
|
||||
<?php echo date(\'F j, Y, h:i A\', strtotime($student[\'updated_at\'])); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="footer">
|
||||
Student Management System - Generated on: <?php echo date(\'F j, Y, h:i A\'); ?>
|
||||
</div>
|
||||
<div style="text-align: center; margin-top: 20px;" class="no-print">
|
||||
<button onclick="window.print()">Print Report</button>
|
||||
<button onclick="window.close()" style="margin-left: 10px;">Close</button>
|
||||
</div>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
window.print();
|
||||
};
|
||||
<\/script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
printWindow.document.close();
|
||||
});
|
||||
|
||||
// Copy QR code to clipboard
|
||||
$("#copyQRBtn").click(function() {
|
||||
const qrCode = "<?php echo htmlspecialchars($student[\'qr_code\']); ?>";
|
||||
navigator.clipboard.writeText(qrCode).then(function() {
|
||||
showNotification("QR code copied to clipboard!", "success");
|
||||
}).catch(function(err) {
|
||||
console.error("Failed to copy: ", err);
|
||||
showNotification("Failed to copy QR code", "danger");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Show notification
|
||||
function showNotification(message, type = "info") {
|
||||
const alertClass = {
|
||||
"success": "alert-success",
|
||||
"danger": "alert-danger",
|
||||
"warning": "alert-warning",
|
||||
"info": "alert-info"
|
||||
}[type] || "alert-info";
|
||||
|
||||
const icon = {
|
||||
"success": "check-circle",
|
||||
"danger": "exclamation-triangle",
|
||||
"warning": "exclamation-circle",
|
||||
"info": "info-circle"
|
||||
}[type] || "info-circle";
|
||||
|
||||
// Remove existing alerts
|
||||
$(".alert-dismissible").remove();
|
||||
|
||||
const alertHtml = `
|
||||
<div class="alert ${alertClass} alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-${icon} me-2"></i>
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add alert at the top of the page
|
||||
$(".d-flex.justify-content-between.align-items-center.mb-4").after(alertHtml);
|
||||
|
||||
// Auto-remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
$(".alert-dismissible").alert("close");
|
||||
}, 5000);
|
||||
}
|
||||
</script>
|
||||
';
|
||||
|
||||
include '../includes/footer.php';
|
||||
?>
|
||||
106
src-backup/api/export_activities.php
Normal file
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
echo json_encode(['success' => false, 'message' => 'Not authorized']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get all activities with details
|
||||
$sql = "SELECT
|
||||
a.name,
|
||||
a.date,
|
||||
a.time_in,
|
||||
a.time_out,
|
||||
a.location,
|
||||
a.description,
|
||||
a.required_students,
|
||||
c.code as course_code,
|
||||
c.name as course_name,
|
||||
d.code as department_code,
|
||||
d.name as department_name,
|
||||
u.full_name as created_by,
|
||||
CASE a.status WHEN 1 THEN 'Active' ELSE 'Inactive' END as status,
|
||||
a.created_at,
|
||||
a.updated_at
|
||||
FROM activities a
|
||||
LEFT JOIN users u ON a.created_by = u.id
|
||||
LEFT JOIN courses c ON a.course_id = c.id
|
||||
LEFT JOIN departments d ON a.department_id = d.id
|
||||
ORDER BY a.date DESC, a.time_in ASC";
|
||||
|
||||
$result = query($conn, $sql);
|
||||
$activities = [];
|
||||
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$activities[] = $row;
|
||||
}
|
||||
|
||||
// Create CSV file
|
||||
$filename = 'activities_' . date('Y-m-d_H-i-s') . '.csv';
|
||||
$filepath = '../exports/' . $filename;
|
||||
|
||||
// Create exports directory if not exists
|
||||
if (!file_exists('../exports')) {
|
||||
mkdir('../exports', 0777, true);
|
||||
}
|
||||
|
||||
// Open file for writing
|
||||
$file = fopen($filepath, 'w');
|
||||
|
||||
// Add UTF-8 BOM for Excel compatibility
|
||||
fputs($file, $bom = (chr(0xEF) . chr(0xBB) . chr(0xBF)));
|
||||
|
||||
// Add headers
|
||||
$headers = [
|
||||
'Activity Name',
|
||||
'Date',
|
||||
'Time In',
|
||||
'Time Out',
|
||||
'Location',
|
||||
'Description',
|
||||
'Participants',
|
||||
'Course Code',
|
||||
'Course Name',
|
||||
'Department Code',
|
||||
'Department Name',
|
||||
'Created By',
|
||||
'Status',
|
||||
'Created At',
|
||||
'Updated At'
|
||||
];
|
||||
fputcsv($file, $headers);
|
||||
|
||||
// Add data rows
|
||||
foreach ($activities as $activity) {
|
||||
fputcsv($file, [
|
||||
$activity['name'],
|
||||
$activity['date'],
|
||||
$activity['time_in'],
|
||||
$activity['time_out'],
|
||||
$activity['location'],
|
||||
$activity['description'],
|
||||
$activity['required_students'],
|
||||
$activity['course_code'],
|
||||
$activity['course_name'],
|
||||
$activity['department_code'],
|
||||
$activity['department_name'],
|
||||
$activity['created_by'],
|
||||
$activity['status'],
|
||||
$activity['created_at'],
|
||||
$activity['updated_at']
|
||||
]);
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Export completed',
|
||||
'download_url' => '../exports/' . $filename,
|
||||
'count' => count($activities)
|
||||
]);
|
||||
?>
|
||||
161
src-backup/api/export_reports.php
Normal file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is logged in and is admin
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
||||
echo json_encode(['success' => false, 'message' => 'Not authorized']);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get filter parameters
|
||||
$start_date = $_GET['start_date'] ?? date('Y-m-01');
|
||||
$end_date = $_GET['end_date'] ?? date('Y-m-t');
|
||||
$activity_id = $_GET['activity_id'] ?? '';
|
||||
$course_id = $_GET['course_id'] ?? '';
|
||||
$department_id = $_GET['department_id'] ?? '';
|
||||
$status = $_GET['status'] ?? '';
|
||||
|
||||
// Build SQL query with filters
|
||||
$where_conditions = ["DATE(a.created_at) BETWEEN '$start_date' AND '$end_date'"];
|
||||
$join_tables = "";
|
||||
|
||||
if ($activity_id) {
|
||||
$where_conditions[] = "a.activity_id = " . intval($activity_id);
|
||||
}
|
||||
|
||||
if ($course_id) {
|
||||
$join_tables .= " LEFT JOIN students s ON a.student_id = s.id";
|
||||
$where_conditions[] = "s.course_id = " . intval($course_id);
|
||||
}
|
||||
|
||||
if ($department_id) {
|
||||
if (strpos($join_tables, 'students s') === false) {
|
||||
$join_tables .= " LEFT JOIN students s ON a.student_id = s.id";
|
||||
}
|
||||
$where_conditions[] = "s.department_id = " . intval($department_id);
|
||||
}
|
||||
|
||||
if ($status && in_array($status, ['present', 'late', 'absent', 'excused'])) {
|
||||
$where_conditions[] = "a.status = '$status'";
|
||||
}
|
||||
|
||||
$where_clause = count($where_conditions) > 0 ? "WHERE " . implode(" AND ", $where_conditions) : "";
|
||||
|
||||
// Get attendance records
|
||||
$sql = "SELECT
|
||||
DATE_FORMAT(a.created_at, '%Y-%m-%d') as date,
|
||||
DATE_FORMAT(a.created_at, '%H:%i:%s') as time,
|
||||
s.student_id,
|
||||
s.full_name as student_name,
|
||||
s.year_level,
|
||||
c.code as course_code,
|
||||
c.name as course_name,
|
||||
d.code as department_code,
|
||||
d.name as department_name,
|
||||
ac.name as activity_name,
|
||||
ac.location as activity_location,
|
||||
a.time_in,
|
||||
a.time_out,
|
||||
a.status,
|
||||
u.full_name as recorded_by,
|
||||
a.notes
|
||||
FROM attendance a
|
||||
LEFT JOIN students s ON a.student_id = s.id
|
||||
LEFT JOIN courses c ON s.course_id = c.id
|
||||
LEFT JOIN departments d ON s.department_id = d.id
|
||||
LEFT JOIN activities ac ON a.activity_id = ac.id
|
||||
LEFT JOIN users u ON a.created_by = u.id
|
||||
$join_tables
|
||||
$where_clause
|
||||
ORDER BY a.created_at DESC";
|
||||
|
||||
$result = query($conn, $sql);
|
||||
$records = [];
|
||||
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$records[] = $row;
|
||||
}
|
||||
|
||||
// Create CSV file
|
||||
$filename = 'attendance_report_' . date('Y-m-d_H-i-s') . '.csv';
|
||||
$filepath = '../exports/' . $filename;
|
||||
|
||||
// Create exports directory if not exists
|
||||
if (!file_exists('../exports')) {
|
||||
mkdir('../exports', 0777, true);
|
||||
}
|
||||
|
||||
// Open file for writing
|
||||
$file = fopen($filepath, 'w');
|
||||
|
||||
// Add UTF-8 BOM for Excel compatibility
|
||||
fputs($file, $bom = (chr(0xEF) . chr(0xBB) . chr(0xBF)));
|
||||
|
||||
// Add headers
|
||||
$headers = [
|
||||
'Date',
|
||||
'Time',
|
||||
'Student ID',
|
||||
'Student Name',
|
||||
'Year Level',
|
||||
'Course Code',
|
||||
'Course Name',
|
||||
'Department Code',
|
||||
'Department Name',
|
||||
'Activity Name',
|
||||
'Activity Location',
|
||||
'Time In',
|
||||
'Time Out',
|
||||
'Status',
|
||||
'Recorded By',
|
||||
'Notes'
|
||||
];
|
||||
fputcsv($file, $headers);
|
||||
|
||||
// Add data rows
|
||||
foreach ($records as $record) {
|
||||
fputcsv($file, [
|
||||
$record['date'],
|
||||
$record['time'],
|
||||
$record['student_id'],
|
||||
$record['student_name'],
|
||||
$record['year_level'],
|
||||
$record['course_code'],
|
||||
$record['course_name'],
|
||||
$record['department_code'],
|
||||
$record['department_name'],
|
||||
$record['activity_name'],
|
||||
$record['activity_location'],
|
||||
$record['time_in'],
|
||||
$record['time_out'],
|
||||
ucfirst($record['status']),
|
||||
$record['recorded_by'],
|
||||
$record['notes']
|
||||
]);
|
||||
}
|
||||
|
||||
fclose($file);
|
||||
|
||||
// Get statistics for summary sheet
|
||||
$stats_sql = "SELECT
|
||||
COUNT(*) as total,
|
||||
SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present,
|
||||
SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late,
|
||||
SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent,
|
||||
SUM(CASE WHEN status = 'excused' THEN 1 ELSE 0 END) as excused
|
||||
FROM attendance
|
||||
WHERE DATE(created_at) BETWEEN '$start_date' AND '$end_date'";
|
||||
$stats_result = query($conn, $stats_sql);
|
||||
$stats = mysqli_fetch_assoc($stats_result);
|
||||
|
||||
echo json_encode([
|
||||
'success' => true,
|
||||
'message' => 'Export completed',
|
||||
'download_url' => '../exports/' . $filename,
|
||||
'count' => count($records),
|
||||
'stats' => $stats,
|
||||
'period' => "$start_date to $end_date"
|
||||
]);
|
||||
?>
|
||||
25
src-backup/api/get_courses.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
$department_id = isset($_GET['department_id']) ? intval($_GET['department_id']) : 0;
|
||||
|
||||
$courses = [];
|
||||
if ($department_id > 0) {
|
||||
$sql = "SELECT id, code, name FROM courses
|
||||
WHERE department_id = ? AND status = 1
|
||||
ORDER BY code";
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $department_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$courses[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($courses);
|
||||
?>
|
||||
25
src-backup/api/get_departments.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
$school_id = isset($_GET['school_id']) ? intval($_GET['school_id']) : 0;
|
||||
|
||||
$departments = [];
|
||||
if ($school_id > 0) {
|
||||
$sql = "SELECT id, code, name FROM departments
|
||||
WHERE school_id = ? AND status = 1
|
||||
ORDER BY code";
|
||||
|
||||
$stmt = mysqli_prepare($conn, $sql);
|
||||
mysqli_stmt_bind_param($stmt, 'i', $school_id);
|
||||
mysqli_stmt_execute($stmt);
|
||||
$result = mysqli_stmt_get_result($stmt);
|
||||
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$departments[] = $row;
|
||||
}
|
||||
mysqli_stmt_close($stmt);
|
||||
}
|
||||
|
||||
header('Content-Type: application/json');
|
||||
echo json_encode($departments);
|
||||
?>
|
||||
180
src-backup/api/manual_entry.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
|
||||
echo json_encode(['success' => false, 'message' => 'Not authenticated']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$response = [
|
||||
'success' => false,
|
||||
'message' => '',
|
||||
'data' => []
|
||||
];
|
||||
|
||||
// Get input data
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$student_id_input = $input['student_id'] ?? '';
|
||||
|
||||
if (empty($student_id_input)) {
|
||||
$response['message'] = 'Student ID is required';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Get student by student ID
|
||||
$sql = "SELECT s.*, c.code as course_code, d.name as department_name
|
||||
FROM students s
|
||||
JOIN courses c ON s.course_id = c.id
|
||||
JOIN departments d ON s.department_id = d.id
|
||||
WHERE s.student_id = '" . escape($conn, $student_id_input) . "' AND s.status = 1";
|
||||
$result = query($conn, $sql);
|
||||
|
||||
if (!$result || mysqli_num_rows($result) === 0) {
|
||||
$response['message'] = 'Student not found with ID: ' . $student_id_input;
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$student = mysqli_fetch_assoc($result);
|
||||
|
||||
// Get current time and date
|
||||
$current_time = date('H:i:s');
|
||||
$current_date = date('Y-m-d');
|
||||
|
||||
// Find active activity for the student
|
||||
$activity_sql = "SELECT * FROM activities
|
||||
WHERE status = 1
|
||||
AND date = '$current_date'
|
||||
AND time_in <= '$current_time'
|
||||
AND time_out >= '$current_time'
|
||||
AND (
|
||||
required_students = 'all'
|
||||
OR (required_students = 'specific_course' AND course_id = " . $student['course_id'] . ")
|
||||
OR (required_students = 'specific_department' AND department_id = " . $student['department_id'] . ")
|
||||
)
|
||||
LIMIT 1";
|
||||
|
||||
$activity_result = query($conn, $activity_sql);
|
||||
|
||||
if (!$activity_result || mysqli_num_rows($activity_result) === 0) {
|
||||
// If no current activity, check for any today's activity
|
||||
$activity_sql = "SELECT * FROM activities
|
||||
WHERE status = 1
|
||||
AND date = '$current_date'
|
||||
ORDER BY time_in DESC
|
||||
LIMIT 1";
|
||||
$activity_result = query($conn, $activity_sql);
|
||||
}
|
||||
|
||||
if (!$activity_result || mysqli_num_rows($activity_result) === 0) {
|
||||
$response['message'] = 'No active activity found for today';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$activity = mysqli_fetch_assoc($activity_result);
|
||||
|
||||
// Check if attendance already exists
|
||||
$attendance_sql = "SELECT * FROM attendance
|
||||
WHERE student_id = " . $student['id'] . "
|
||||
AND activity_id = " . $activity['id'];
|
||||
$attendance_result = query($conn, $attendance_sql);
|
||||
|
||||
if ($attendance_result && mysqli_num_rows($attendance_result) > 0) {
|
||||
$attendance = mysqli_fetch_assoc($attendance_result);
|
||||
|
||||
if ($attendance['time_out']) {
|
||||
$response['message'] = 'Attendance already completed for this activity';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Update time out
|
||||
$time_out = date('Y-m-d H:i:s');
|
||||
$update_sql = "UPDATE attendance
|
||||
SET time_out = '$time_out',
|
||||
status = 'present',
|
||||
updated_at = NOW()
|
||||
WHERE id = " . $attendance['id'];
|
||||
|
||||
if (query($conn, $update_sql)) {
|
||||
// Log the action
|
||||
$log_sql = "INSERT INTO attendance_logs
|
||||
(attendance_id, action, old_value, new_value, changed_by, notes)
|
||||
VALUES (
|
||||
" . $attendance['id'] . ",
|
||||
'time_out',
|
||||
NULL,
|
||||
'$time_out',
|
||||
" . $_SESSION['user_id'] . ",
|
||||
'Manual entry - time out'
|
||||
)";
|
||||
query($conn, $log_sql);
|
||||
|
||||
$response['success'] = true;
|
||||
$response['message'] = 'Time out recorded successfully';
|
||||
$response['data'] = [
|
||||
'student_name' => $student['full_name'],
|
||||
'activity_name' => $activity['name'],
|
||||
'time' => date('h:i:s A'),
|
||||
'action' => 'time_out'
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// Create new attendance record
|
||||
$time_in = date('Y-m-d H:i:s');
|
||||
$status = 'present';
|
||||
|
||||
// Check if late
|
||||
$activity_start = strtotime($activity['date'] . ' ' . $activity['time_in']);
|
||||
$current_timestamp = time();
|
||||
|
||||
if (($current_timestamp - $activity_start) > 900) {
|
||||
$status = 'late';
|
||||
}
|
||||
|
||||
$insert_sql = "INSERT INTO attendance
|
||||
(student_id, activity_id, time_in, status, created_at, updated_at)
|
||||
VALUES (
|
||||
" . $student['id'] . ",
|
||||
" . $activity['id'] . ",
|
||||
'$time_in',
|
||||
'$status',
|
||||
NOW(),
|
||||
NOW()
|
||||
)";
|
||||
|
||||
if (query($conn, $insert_sql)) {
|
||||
$attendance_id = getInsertId($conn);
|
||||
|
||||
// Log the action
|
||||
$log_sql = "INSERT INTO attendance_logs
|
||||
(attendance_id, action, old_value, new_value, changed_by, notes)
|
||||
VALUES (
|
||||
$attendance_id,
|
||||
'time_in',
|
||||
NULL,
|
||||
'$time_in',
|
||||
" . $_SESSION['user_id'] . ",
|
||||
'Manual entry - time in'
|
||||
)";
|
||||
query($conn, $log_sql);
|
||||
|
||||
$response['success'] = true;
|
||||
$response['message'] = 'Time in recorded successfully';
|
||||
$response['data'] = [
|
||||
'student_name' => $student['full_name'],
|
||||
'activity_name' => $activity['name'],
|
||||
'time' => date('h:i:s A'),
|
||||
'status' => $status,
|
||||
'action' => 'time_in'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
?>
|
||||
192
src-backup/api/scan_qr.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
header('Content-Type: application/json');
|
||||
|
||||
// Check if user is logged in
|
||||
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true) {
|
||||
echo json_encode(['success' => false, 'message' => 'Not authenticated']);
|
||||
exit();
|
||||
}
|
||||
|
||||
$response = [
|
||||
'success' => false,
|
||||
'message' => '',
|
||||
'data' => []
|
||||
];
|
||||
|
||||
// Get input data
|
||||
$input = json_decode(file_get_contents('php://input'), true);
|
||||
$qr_code = $input['qr_code'] ?? '';
|
||||
|
||||
if (empty($qr_code)) {
|
||||
$response['message'] = 'QR code is required';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Extract student ID from QR code (format: STU_23-0217_692b07dd55c31)
|
||||
$qr_parts = explode('_', $qr_code);
|
||||
if (count($qr_parts) < 3 || $qr_parts[0] !== 'STU') {
|
||||
$response['message'] = 'Invalid QR code format';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$student_id_str = $qr_parts[1]; // e.g., 23-0217
|
||||
|
||||
// Get student details
|
||||
$sql = "SELECT s.*, c.code as course_code, d.name as department_name
|
||||
FROM students s
|
||||
JOIN courses c ON s.course_id = c.id
|
||||
JOIN departments d ON s.department_id = d.id
|
||||
WHERE s.qr_code = '" . escape($conn, $qr_code) . "' AND s.status = 1";
|
||||
$result = query($conn, $sql);
|
||||
|
||||
if (!$result || mysqli_num_rows($result) === 0) {
|
||||
$response['message'] = 'Student not found or QR code invalid';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$student = mysqli_fetch_assoc($result);
|
||||
|
||||
// Get current time
|
||||
$current_time = date('H:i:s');
|
||||
$current_date = date('Y-m-d');
|
||||
|
||||
// Find active activity for the student
|
||||
$activity_sql = "SELECT * FROM activities
|
||||
WHERE status = 1
|
||||
AND date = '$current_date'
|
||||
AND time_in <= '$current_time'
|
||||
AND time_out >= '$current_time'
|
||||
AND (
|
||||
required_students = 'all'
|
||||
OR (required_students = 'specific_course' AND course_id = " . $student['course_id'] . ")
|
||||
OR (required_students = 'specific_department' AND department_id = " . $student['department_id'] . ")
|
||||
)
|
||||
LIMIT 1";
|
||||
|
||||
$activity_result = query($conn, $activity_sql);
|
||||
|
||||
if (!$activity_result || mysqli_num_rows($activity_result) === 0) {
|
||||
// If no current activity, check for any today's activity
|
||||
$activity_sql = "SELECT * FROM activities
|
||||
WHERE status = 1
|
||||
AND date = '$current_date'
|
||||
ORDER BY time_in DESC
|
||||
LIMIT 1";
|
||||
$activity_result = query($conn, $activity_sql);
|
||||
}
|
||||
|
||||
if (!$activity_result || mysqli_num_rows($activity_result) === 0) {
|
||||
$response['message'] = 'No active activity found for today';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
$activity = mysqli_fetch_assoc($activity_result);
|
||||
|
||||
// Check if attendance already exists
|
||||
$attendance_sql = "SELECT * FROM attendance
|
||||
WHERE student_id = " . $student['id'] . "
|
||||
AND activity_id = " . $activity['id'];
|
||||
$attendance_result = query($conn, $attendance_sql);
|
||||
|
||||
if ($attendance_result && mysqli_num_rows($attendance_result) > 0) {
|
||||
// Update time out if already has time in
|
||||
$attendance = mysqli_fetch_assoc($attendance_result);
|
||||
|
||||
if ($attendance['time_out']) {
|
||||
$response['message'] = 'Attendance already completed for this activity';
|
||||
echo json_encode($response);
|
||||
exit();
|
||||
}
|
||||
|
||||
// Update time out
|
||||
$time_out = date('Y-m-d H:i:s');
|
||||
$update_sql = "UPDATE attendance
|
||||
SET time_out = '$time_out',
|
||||
status = 'present',
|
||||
updated_at = NOW()
|
||||
WHERE id = " . $attendance['id'];
|
||||
|
||||
if (query($conn, $update_sql)) {
|
||||
// Log the action
|
||||
$log_sql = "INSERT INTO attendance_logs
|
||||
(attendance_id, action, old_value, new_value, changed_by, notes)
|
||||
VALUES (
|
||||
" . $attendance['id'] . ",
|
||||
'time_out',
|
||||
NULL,
|
||||
'$time_out',
|
||||
" . $_SESSION['user_id'] . ",
|
||||
'QR code scan - time out'
|
||||
)";
|
||||
query($conn, $log_sql);
|
||||
|
||||
$response['success'] = true;
|
||||
$response['message'] = 'Time out recorded successfully';
|
||||
$response['data'] = [
|
||||
'student_name' => $student['full_name'],
|
||||
'activity_name' => $activity['name'],
|
||||
'time' => date('h:i:s A'),
|
||||
'status' => 'present',
|
||||
'action' => 'time_out'
|
||||
];
|
||||
}
|
||||
} else {
|
||||
// Create new attendance record
|
||||
$time_in = date('Y-m-d H:i:s');
|
||||
$status = 'present';
|
||||
|
||||
// Check if late (more than 15 minutes after activity start)
|
||||
$activity_start = strtotime($activity['date'] . ' ' . $activity['time_in']);
|
||||
$current_timestamp = time();
|
||||
|
||||
if (($current_timestamp - $activity_start) > 900) { // 900 seconds = 15 minutes
|
||||
$status = 'late';
|
||||
}
|
||||
|
||||
$insert_sql = "INSERT INTO attendance
|
||||
(student_id, activity_id, time_in, status, created_at, updated_at)
|
||||
VALUES (
|
||||
" . $student['id'] . ",
|
||||
" . $activity['id'] . ",
|
||||
'$time_in',
|
||||
'$status',
|
||||
NOW(),
|
||||
NOW()
|
||||
)";
|
||||
|
||||
if (query($conn, $insert_sql)) {
|
||||
$attendance_id = getInsertId($conn);
|
||||
|
||||
// Log the action
|
||||
$log_sql = "INSERT INTO attendance_logs
|
||||
(attendance_id, action, old_value, new_value, changed_by, notes)
|
||||
VALUES (
|
||||
$attendance_id,
|
||||
'time_in',
|
||||
NULL,
|
||||
'$time_in',
|
||||
" . $_SESSION['user_id'] . ",
|
||||
'QR code scan - time in'
|
||||
)";
|
||||
query($conn, $log_sql);
|
||||
|
||||
$response['success'] = true;
|
||||
$response['message'] = 'Time in recorded successfully';
|
||||
$response['data'] = [
|
||||
'student_name' => $student['full_name'],
|
||||
'activity_name' => $activity['name'],
|
||||
'time' => date('h:i:s A'),
|
||||
'status' => $status,
|
||||
'action' => 'time_in'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($response);
|
||||
?>
|
||||
141
src-backup/assets/css/style.css
Normal file
@@ -0,0 +1,141 @@
|
||||
/* Main Stylesheet */
|
||||
:root {
|
||||
--primary-color: #3498db;
|
||||
--secondary-color: #2c3e50;
|
||||
--success-color: #27ae60;
|
||||
--danger-color: #e74c3c;
|
||||
--warning-color: #f39c12;
|
||||
--info-color: #17a2b8;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: #f8f9fa;
|
||||
color: #336494;
|
||||
margin: 10;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.login-page {
|
||||
background: linear-gradient(135deg, #8bea66 0%, #a0a24b 100%);
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
border-radius: 15px 15px 0 0 !important;
|
||||
}
|
||||
|
||||
/* Table Styles */
|
||||
.table-hover tbody tr:hover {
|
||||
background-color: rgba(52, 152, 219, 0.1);
|
||||
}
|
||||
|
||||
/* Button Styles */
|
||||
.btn {
|
||||
border-radius: 8px;
|
||||
padding: 8px 20px;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
/* Badge Styles */
|
||||
.badge {
|
||||
padding: 5px 10px;
|
||||
border-radius: 10px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Form Styles */
|
||||
.form-control {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #dee2e6;
|
||||
padding: 10px 15px;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: var(--primary-color);
|
||||
box-shadow: 0 0 0 0.2rem rgba(52, 152, 219, 0.25);
|
||||
}
|
||||
|
||||
/* Alert Styles */
|
||||
.alert {
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
}
|
||||
|
||||
/* Custom Scrollbar */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f1f1;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: var(--primary-color);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #2980b9;
|
||||
}
|
||||
|
||||
/* Animation for attendance success */
|
||||
@keyframes successPulse {
|
||||
0% { transform: scale(1); }
|
||||
50% { transform: scale(1.05); }
|
||||
100% { transform: scale(1); }
|
||||
}
|
||||
|
||||
.attendance-success {
|
||||
animation: successPulse 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
/* Scanner container */
|
||||
#qr-reader {
|
||||
border: 2px dashed #dee2e6;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* Calendar icon */
|
||||
.calendar-icon {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
text-align: center;
|
||||
width: 50px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* Print styles */
|
||||
@media print {
|
||||
.sidebar, .navbar, .btn {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-left: 0 !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
BIN
src-backup/assets/image/aldersgate.png
Normal file
|
After Width: | Height: | Size: 511 KiB |
273
src-backup/assets/js/scanner.js
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* QR Code Scanner Module
|
||||
*/
|
||||
class QRScanner {
|
||||
constructor(options = {}) {
|
||||
this.options = {
|
||||
scannerId: 'qr-reader',
|
||||
resultId: 'scan-result',
|
||||
facingMode: 'environment',
|
||||
fps: 10,
|
||||
qrbox: { width: 250, height: 250 },
|
||||
...options
|
||||
};
|
||||
|
||||
this.scanner = null;
|
||||
this.isScanning = false;
|
||||
this.lastScanTime = 0;
|
||||
this.scanCooldown = 2000; // 2 seconds cooldown
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.scanner = new Html5Qrcode(this.options.scannerId);
|
||||
|
||||
// Create result container if not exists
|
||||
if (!document.getElementById(this.options.resultId)) {
|
||||
const resultDiv = document.createElement('div');
|
||||
resultDiv.id = this.options.resultId;
|
||||
document.querySelector(`#${this.options.scannerId}`).parentNode.appendChild(resultDiv);
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
if (this.isScanning) return;
|
||||
|
||||
try {
|
||||
await this.scanner.start(
|
||||
{ facingMode: this.options.facingMode },
|
||||
this.options,
|
||||
this.onScanSuccess.bind(this),
|
||||
this.onScanError.bind(this)
|
||||
);
|
||||
|
||||
this.isScanning = true;
|
||||
this.updateUI('started');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to start scanner:', error);
|
||||
this.showError('Failed to start camera. Please check permissions.');
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this.isScanning) return;
|
||||
|
||||
this.scanner.stop().then(() => {
|
||||
this.isScanning = false;
|
||||
this.updateUI('stopped');
|
||||
}).catch(error => {
|
||||
console.error('Failed to stop scanner:', error);
|
||||
});
|
||||
}
|
||||
|
||||
onScanSuccess(decodedText, decodedResult) {
|
||||
const currentTime = Date.now();
|
||||
|
||||
// Prevent multiple scans in short time
|
||||
if (currentTime - this.lastScanTime < this.scanCooldown) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.lastScanTime = currentTime;
|
||||
|
||||
// Show scanning indicator
|
||||
this.showResult('scanning', 'Scanning QR code...');
|
||||
|
||||
// Process the scan
|
||||
this.processQRCode(decodedText);
|
||||
}
|
||||
|
||||
onScanError(error) {
|
||||
console.warn('QR Scan Error:', error);
|
||||
// Don't show errors to user unless critical
|
||||
}
|
||||
|
||||
async processQRCode(qrData) {
|
||||
try {
|
||||
const response = await fetch('../api/scan_qr.php', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ qr_code: qrData })
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showResult('success', data);
|
||||
this.playSound('success');
|
||||
|
||||
// Auto-stop after successful scan (optional)
|
||||
if (this.options.autoStop) {
|
||||
setTimeout(() => this.stop(), 3000);
|
||||
}
|
||||
|
||||
} else {
|
||||
this.showResult('error', data.message);
|
||||
this.playSound('error');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Processing error:', error);
|
||||
this.showResult('error', 'Network error. Please try again.');
|
||||
this.playSound('error');
|
||||
}
|
||||
}
|
||||
|
||||
showResult(type, data) {
|
||||
const resultDiv = document.getElementById(this.options.resultId);
|
||||
|
||||
let html = '';
|
||||
|
||||
switch(type) {
|
||||
case 'scanning':
|
||||
html = `
|
||||
<div class="alert alert-info">
|
||||
<div class="spinner-border spinner-border-sm me-2" role="status"></div>
|
||||
${data}
|
||||
</div>
|
||||
`;
|
||||
break;
|
||||
|
||||
case 'success':
|
||||
html = `
|
||||
<div class="alert alert-success attendance-success">
|
||||
<div class="d-flex align-items-center">
|
||||
<i class="bi bi-check-circle-fill me-3" style="font-size: 2rem;"></i>
|
||||
<div>
|
||||
<h5 class="mb-1">Attendance Recorded!</h5>
|
||||
<p class="mb-1"><strong>Student:</strong> ${data.data.student_name}</p>
|
||||
<p class="mb-1"><strong>Activity:</strong> ${data.data.activity_name}</p>
|
||||
<p class="mb-0"><strong>Time:</strong> ${data.data.time}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
html = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
${data}
|
||||
</div>
|
||||
`;
|
||||
break;
|
||||
}
|
||||
|
||||
resultDiv.innerHTML = html;
|
||||
|
||||
// Auto-clear result after some time
|
||||
if (type !== 'scanning') {
|
||||
setTimeout(() => {
|
||||
if (resultDiv.innerHTML.includes(html)) {
|
||||
resultDiv.innerHTML = '';
|
||||
}
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
const resultDiv = document.getElementById(this.options.resultId);
|
||||
resultDiv.innerHTML = `
|
||||
<div class="alert alert-danger">
|
||||
<i class="bi bi-camera-video-off me-2"></i>
|
||||
${message}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
updateUI(state) {
|
||||
const scannerDiv = document.getElementById(this.options.scannerId);
|
||||
|
||||
if (state === 'started') {
|
||||
scannerDiv.classList.add('scanning');
|
||||
} else {
|
||||
scannerDiv.classList.remove('scanning');
|
||||
}
|
||||
}
|
||||
|
||||
playSound(type) {
|
||||
// Create audio context for sounds
|
||||
try {
|
||||
const audioContext = new (window.AudioContext || window.webkitAudioContext)();
|
||||
const oscillator = audioContext.createOscillator();
|
||||
const gainNode = audioContext.createGain();
|
||||
|
||||
oscillator.connect(gainNode);
|
||||
gainNode.connect(audioContext.destination);
|
||||
|
||||
if (type === 'success') {
|
||||
oscillator.frequency.setValueAtTime(523.25, audioContext.currentTime); // C5
|
||||
oscillator.frequency.setValueAtTime(659.25, audioContext.currentTime + 0.1); // E5
|
||||
oscillator.frequency.setValueAtTime(783.99, audioContext.currentTime + 0.2); // G5
|
||||
} else {
|
||||
oscillator.frequency.setValueAtTime(200, audioContext.currentTime); // Low tone
|
||||
}
|
||||
|
||||
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
|
||||
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.3);
|
||||
|
||||
oscillator.start();
|
||||
oscillator.stop(audioContext.currentTime + 0.3);
|
||||
|
||||
} catch (error) {
|
||||
console.log('Audio not supported');
|
||||
}
|
||||
}
|
||||
|
||||
toggleCamera() {
|
||||
if (this.options.facingMode === 'environment') {
|
||||
this.options.facingMode = 'user';
|
||||
} else {
|
||||
this.options.facingMode = 'environment';
|
||||
}
|
||||
|
||||
this.stop();
|
||||
setTimeout(() => this.start(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize scanner when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Check for scanner elements on page
|
||||
const scannerElements = document.querySelectorAll('[data-scanner]');
|
||||
|
||||
scannerElements.forEach(element => {
|
||||
const scannerId = element.getAttribute('data-scanner') || 'qr-reader';
|
||||
const scanner = new QRScanner({
|
||||
scannerId: scannerId,
|
||||
autoStop: element.getAttribute('data-auto-stop') === 'true'
|
||||
});
|
||||
|
||||
// Add start/stop buttons if not auto-start
|
||||
if (element.getAttribute('data-auto-start') !== 'true') {
|
||||
const controls = document.createElement('div');
|
||||
controls.className = 'scanner-controls mt-3';
|
||||
controls.innerHTML = `
|
||||
<button class="btn btn-success me-2 start-scan">
|
||||
<i class="bi bi-play-circle"></i> Start Scanner
|
||||
</button>
|
||||
<button class="btn btn-danger me-2 stop-scan">
|
||||
<i class="bi bi-stop-circle"></i> Stop Scanner
|
||||
</button>
|
||||
<button class="btn btn-secondary toggle-camera">
|
||||
<i class="bi bi-camera-video"></i> Switch Camera
|
||||
</button>
|
||||
`;
|
||||
|
||||
element.parentNode.appendChild(controls);
|
||||
|
||||
// Add event listeners
|
||||
controls.querySelector('.start-scan').addEventListener('click', () => scanner.start());
|
||||
controls.querySelector('.stop-scan').addEventListener('click', () => scanner.stop());
|
||||
controls.querySelector('.toggle-camera').addEventListener('click', () => scanner.toggleCamera());
|
||||
} else {
|
||||
// Auto-start scanner
|
||||
setTimeout(() => scanner.start(), 1000);
|
||||
}
|
||||
});
|
||||
});
|
||||
410
src-backup/attendance_system.sql
Normal file
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
Navicat MySQL Dump SQL
|
||||
|
||||
Source Server : localhost_3306
|
||||
Source Server Type : MySQL
|
||||
Source Server Version : 100432 (10.4.32-MariaDB)
|
||||
Source Host : localhost:3306
|
||||
Source Schema : attendance_system
|
||||
|
||||
Target Server Type : MySQL
|
||||
Target Server Version : 100432 (10.4.32-MariaDB)
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 14/12/2025 12:46:51
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
SET FOREIGN_KEY_CHECKS = 0;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for activities
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `activities`;
|
||||
CREATE TABLE `activities` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`date` date NOT NULL,
|
||||
`time_in` time NOT NULL,
|
||||
`time_out` time NOT NULL,
|
||||
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`location` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`required_students` enum('all','specific_course','specific_department') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'all',
|
||||
`course_id` int NULL DEFAULT NULL,
|
||||
`department_id` int NULL DEFAULT NULL,
|
||||
`created_by` int NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status` tinyint NULL DEFAULT 1 COMMENT '1=Active, 0=Inactive',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_date`(`date` ASC) USING BTREE,
|
||||
INDEX `idx_created_by`(`created_by` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE,
|
||||
INDEX `idx_course_id`(`course_id` ASC) USING BTREE,
|
||||
INDEX `idx_department_id`(`department_id` ASC) USING BTREE,
|
||||
CONSTRAINT `activities_ibfk_1` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT `activities_ibfk_2` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT `activities_ibfk_3` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of activities
|
||||
-- ----------------------------
|
||||
INSERT INTO `activities` VALUES (3, 'JPCS Week', '2025-11-20', '08:00:00', '17:00:00', 'Cybersecurity Seminar, Recognition, and Opening Ceremony of JPCS Week with the theme \"Think I.T. DO. I.T. BE IT\".', 'AVR1', 'specific_course', 1, 1, 1, '2025-11-30 00:34:27', '2025-11-30 00:34:27', 1);
|
||||
INSERT INTO `activities` VALUES (4, 'Morning Class Nov 30', '2025-11-30', '08:00:00', '10:00:00', 'Regular class session', 'Room 101', 'all', NULL, NULL, 1, '2025-11-30 17:27:14', '2025-11-30 17:27:14', 1);
|
||||
INSERT INTO `activities` VALUES (5, 'Christmas Party', '2025-12-07', '21:40:00', '23:00:00', '', 'AVR1', 'all', NULL, NULL, 1, '2025-12-07 21:36:33', '2025-12-07 21:36:33', 1);
|
||||
INSERT INTO `activities` VALUES (7, 'Philhealth Yakap Orientation Program', '2025-12-09', '16:00:00', '17:00:00', '', 'AVR1', 'specific_course', 1, NULL, 1, '2025-12-09 15:08:41', '2025-12-09 15:08:41', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for attendance
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `attendance`;
|
||||
CREATE TABLE `attendance` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`student_id` int NOT NULL,
|
||||
`activity_id` int NOT NULL,
|
||||
`time_in` timestamp NULL DEFAULT NULL,
|
||||
`time_out` timestamp NULL DEFAULT NULL,
|
||||
`status` enum('present','absent','late','excused') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'present',
|
||||
`notes` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `unique_student_activity`(`student_id` ASC, `activity_id` ASC) USING BTREE,
|
||||
INDEX `idx_student_id`(`student_id` ASC) USING BTREE,
|
||||
INDEX `idx_activity_id`(`activity_id` ASC) USING BTREE,
|
||||
INDEX `idx_time_in`(`time_in` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE,
|
||||
INDEX `idx_created_at`(`created_at` ASC) USING BTREE,
|
||||
CONSTRAINT `attendance_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `students` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `attendance_ibfk_2` FOREIGN KEY (`activity_id`) REFERENCES `activities` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 23 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of attendance
|
||||
-- ----------------------------
|
||||
INSERT INTO `attendance` VALUES (1, 1, 3, '2025-11-29 17:38:16', NULL, NULL, NULL, '2025-11-30 00:38:16', '2025-11-30 00:38:16');
|
||||
INSERT INTO `attendance` VALUES (2, 1, 5, '2025-12-07 21:38:06', '2025-12-07 21:56:47', 'present', NULL, '2025-12-07 21:38:06', '2025-12-07 21:56:47');
|
||||
INSERT INTO `attendance` VALUES (3, 4, 5, '2025-12-07 21:38:17', NULL, 'present', NULL, '2025-12-07 21:38:17', '2025-12-07 21:38:17');
|
||||
INSERT INTO `attendance` VALUES (4, 3, 5, '2025-12-07 21:38:27', NULL, 'present', NULL, '2025-12-07 21:38:27', '2025-12-07 21:38:27');
|
||||
INSERT INTO `attendance` VALUES (5, 2, 5, '2025-12-07 21:39:44', '2025-12-07 21:39:52', 'present', NULL, '2025-12-07 21:39:44', '2025-12-07 21:39:52');
|
||||
INSERT INTO `attendance` VALUES (6, 19, 5, '2025-12-07 21:51:04', NULL, 'present', NULL, '2025-12-07 21:51:04', '2025-12-07 21:51:04');
|
||||
INSERT INTO `attendance` VALUES (7, 17, 5, '2025-12-07 21:51:17', NULL, 'present', NULL, '2025-12-07 21:51:17', '2025-12-07 21:51:17');
|
||||
INSERT INTO `attendance` VALUES (8, 11, 5, '2025-12-07 21:51:30', NULL, 'present', NULL, '2025-12-07 21:51:30', '2025-12-07 21:51:30');
|
||||
INSERT INTO `attendance` VALUES (12, 4, 7, '2025-12-09 15:09:51', '2025-12-09 15:19:03', 'present', NULL, '2025-12-09 15:09:51', '2025-12-09 15:19:03');
|
||||
INSERT INTO `attendance` VALUES (13, 3, 7, '2025-12-09 15:12:04', '2025-12-09 15:18:15', 'present', NULL, '2025-12-09 15:12:04', '2025-12-09 15:18:15');
|
||||
INSERT INTO `attendance` VALUES (14, 9, 7, '2025-12-09 15:12:31', NULL, 'present', NULL, '2025-12-09 15:12:31', '2025-12-09 15:12:31');
|
||||
INSERT INTO `attendance` VALUES (15, 18, 7, '2025-12-09 15:12:48', NULL, 'present', NULL, '2025-12-09 15:12:48', '2025-12-09 15:12:48');
|
||||
INSERT INTO `attendance` VALUES (16, 5, 7, '2025-12-09 15:13:11', '2025-12-09 15:20:12', 'present', NULL, '2025-12-09 15:13:11', '2025-12-09 15:20:12');
|
||||
INSERT INTO `attendance` VALUES (17, 8, 7, '2025-12-09 15:13:34', '2025-12-09 15:20:57', 'present', NULL, '2025-12-09 15:13:34', '2025-12-09 15:20:57');
|
||||
INSERT INTO `attendance` VALUES (18, 15, 7, '2025-12-09 15:14:01', '2025-12-09 15:23:54', 'present', NULL, '2025-12-09 15:14:01', '2025-12-09 15:23:54');
|
||||
INSERT INTO `attendance` VALUES (19, 11, 7, '2025-12-09 15:14:22', '2025-12-09 15:18:18', 'present', NULL, '2025-12-09 15:14:22', '2025-12-09 15:18:18');
|
||||
INSERT INTO `attendance` VALUES (20, 1, 7, '2025-12-09 15:17:18', '2025-12-09 15:18:11', 'present', NULL, '2025-12-09 15:17:18', '2025-12-09 15:18:11');
|
||||
INSERT INTO `attendance` VALUES (21, 2, 7, '2025-12-09 15:18:23', NULL, 'present', NULL, '2025-12-09 15:18:23', '2025-12-09 15:18:23');
|
||||
INSERT INTO `attendance` VALUES (22, 6, 7, '2025-12-09 15:19:49', NULL, 'present', NULL, '2025-12-09 15:19:49', '2025-12-09 15:19:49');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for attendance_logs
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `attendance_logs`;
|
||||
CREATE TABLE `attendance_logs` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`attendance_id` int NOT NULL,
|
||||
`action` enum('time_in','time_out','status_change','manual_entry') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`old_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`new_value` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`changed_by` int NOT NULL,
|
||||
`changed_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`notes` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `idx_attendance_id`(`attendance_id` ASC) USING BTREE,
|
||||
INDEX `idx_changed_by`(`changed_by` ASC) USING BTREE,
|
||||
INDEX `idx_changed_at`(`changed_at` ASC) USING BTREE,
|
||||
INDEX `idx_action`(`action` ASC) USING BTREE,
|
||||
CONSTRAINT `attendance_logs_ibfk_1` FOREIGN KEY (`attendance_id`) REFERENCES `attendance` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `attendance_logs_ibfk_2` FOREIGN KEY (`changed_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of attendance_logs
|
||||
-- ----------------------------
|
||||
INSERT INTO `attendance_logs` VALUES (1, 2, 'time_in', NULL, '2025-12-07 21:38:06', 1, '2025-12-07 21:38:06', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (2, 3, 'time_in', NULL, '2025-12-07 21:38:17', 1, '2025-12-07 21:38:17', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (3, 4, 'time_in', NULL, '2025-12-07 21:38:27', 1, '2025-12-07 21:38:27', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (4, 5, 'time_in', NULL, '2025-12-07 21:39:44', 1, '2025-12-07 21:39:44', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (5, 5, 'time_out', NULL, '2025-12-07 21:39:52', 1, '2025-12-07 21:39:52', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (6, 6, 'time_in', NULL, '2025-12-07 21:51:04', 1, '2025-12-07 21:51:04', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (7, 7, 'time_in', NULL, '2025-12-07 21:51:17', 1, '2025-12-07 21:51:17', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (8, 8, 'time_in', NULL, '2025-12-07 21:51:30', 1, '2025-12-07 21:51:30', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (9, 2, 'time_out', NULL, '2025-12-07 21:56:47', 1, '2025-12-07 21:56:47', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (14, 12, 'time_in', NULL, '2025-12-09 15:09:51', 1, '2025-12-09 15:09:51', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (15, 13, 'time_in', NULL, '2025-12-09 15:12:04', 1, '2025-12-09 15:12:04', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (16, 14, 'time_in', NULL, '2025-12-09 15:12:31', 1, '2025-12-09 15:12:31', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (17, 15, 'time_in', NULL, '2025-12-09 15:12:48', 1, '2025-12-09 15:12:48', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (18, 16, 'time_in', NULL, '2025-12-09 15:13:11', 1, '2025-12-09 15:13:11', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (19, 17, 'time_in', NULL, '2025-12-09 15:13:34', 1, '2025-12-09 15:13:34', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (20, 18, 'time_in', NULL, '2025-12-09 15:14:01', 1, '2025-12-09 15:14:01', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (21, 19, 'time_in', NULL, '2025-12-09 15:14:22', 1, '2025-12-09 15:14:22', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (22, 20, 'time_in', NULL, '2025-12-09 15:17:18', 1, '2025-12-09 15:17:18', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (23, 20, 'time_out', NULL, '2025-12-09 15:18:11', 1, '2025-12-09 15:18:11', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (24, 13, 'time_out', NULL, '2025-12-09 15:18:15', 1, '2025-12-09 15:18:15', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (25, 19, 'time_out', NULL, '2025-12-09 15:18:18', 1, '2025-12-09 15:18:18', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (26, 21, 'time_in', NULL, '2025-12-09 15:18:23', 1, '2025-12-09 15:18:23', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (27, 12, 'time_out', NULL, '2025-12-09 15:19:03', 1, '2025-12-09 15:19:03', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (28, 22, 'time_in', NULL, '2025-12-09 15:19:49', 1, '2025-12-09 15:19:49', 'Manual entry - time in');
|
||||
INSERT INTO `attendance_logs` VALUES (29, 16, 'time_out', NULL, '2025-12-09 15:20:12', 1, '2025-12-09 15:20:12', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (30, 17, 'time_out', NULL, '2025-12-09 15:20:57', 1, '2025-12-09 15:20:57', 'Manual entry - time out');
|
||||
INSERT INTO `attendance_logs` VALUES (31, 18, 'time_out', NULL, '2025-12-09 15:23:54', 1, '2025-12-09 15:23:54', 'Manual entry - time out');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for attendance_records
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `attendance_records`;
|
||||
CREATE TABLE `attendance_records` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`student_id` int NOT NULL,
|
||||
`course_id` int NOT NULL,
|
||||
`status` enum('present','late','absent') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT 'present',
|
||||
`date_recorded` datetime NULL DEFAULT current_timestamp(),
|
||||
`created_by` int NULL DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
INDEX `student_id`(`student_id` ASC) USING BTREE,
|
||||
INDEX `course_id`(`course_id` ASC) USING BTREE,
|
||||
INDEX `created_by`(`created_by` ASC) USING BTREE,
|
||||
CONSTRAINT `attendance_records_ibfk_1` FOREIGN KEY (`student_id`) REFERENCES `students` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `attendance_records_ibfk_2` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
|
||||
CONSTRAINT `attendance_records_ibfk_3` FOREIGN KEY (`created_by`) REFERENCES `users` (`id`) ON DELETE RESTRICT ON UPDATE RESTRICT
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of attendance_records
|
||||
-- ----------------------------
|
||||
INSERT INTO `attendance_records` VALUES (1, 3, 1, 'present', '2025-12-01 08:39:10', 1, '2025-12-01 08:39:10');
|
||||
INSERT INTO `attendance_records` VALUES (2, 4, 1, 'present', '2025-12-01 08:40:49', 1, '2025-12-01 08:40:49');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for courses
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `courses`;
|
||||
CREATE TABLE `courses` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`department_id` int NOT NULL,
|
||||
`duration_years` int NULL DEFAULT 4,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status` tinyint NULL DEFAULT 1 COMMENT '1=Active, 0=Inactive',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_department_id`(`department_id` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE,
|
||||
CONSTRAINT `courses_ibfk_1` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of courses
|
||||
-- ----------------------------
|
||||
INSERT INTO `courses` VALUES (1, 'BSIT', 'Bachelor of Science in Information Technology', 'Information Technology Program', 1, 4, '2025-11-28 14:43:00', '2025-11-29 23:16:51', 1);
|
||||
INSERT INTO `courses` VALUES (2, 'BSCS', 'Bachelor of Science in Computer Science', 'Computer Science Program', 1, 4, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (3, 'BSACC', 'Bachelor of Science in Accountancy', 'Accountancy Program', 2, 4, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (4, 'BSA', 'Bachelor of Science in Business Administration', 'Business Administration Program', 2, 4, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (5, 'BSHM', 'Bachelor of Science in Hospitality Management', 'Hospitality Management Program', 2, 4, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (6, 'BSTM', 'Bachelor of Science in Tourism Management', 'Tourism Management Program', 2, 4, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (7, 'BSCE', 'Bachelor of Science in Civil Engineering', 'Civil Engineering Program', 4, 5, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (8, 'BSEE', 'Bachelor of Science in Electrical Engineering', 'Electrical Engineering Program', 4, 5, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `courses` VALUES (9, 'BSCRIM', 'Bachelor of Science in Criminology', 'Criminology Program', 5, 4, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for departments
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `departments`;
|
||||
CREATE TABLE `departments` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`school_id` int NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status` tinyint NULL DEFAULT 1 COMMENT '1=Active, 0=Inactive',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_school_id`(`school_id` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE,
|
||||
CONSTRAINT `departments_ibfk_1` FOREIGN KEY (`school_id`) REFERENCES `schools` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 6 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of departments
|
||||
-- ----------------------------
|
||||
INSERT INTO `departments` VALUES (1, 'CASE', 'College of Arts, Sciences, Education & Information Technology', 'CASE Department', 1, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `departments` VALUES (2, 'CBMA', 'College of Business, Management, and Accountancy', 'CBMA Department', 1, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `departments` VALUES (3, 'SMS', 'School of Medical Sciences', 'Medical Sciences Department', 1, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `departments` VALUES (4, 'CET', 'College of Engineering and Technology', 'Engineering Department', 1, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
INSERT INTO `departments` VALUES (5, 'SOC', 'School of Criminology', 'Criminology Department', 1, '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for genders
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `genders`;
|
||||
CREATE TABLE `genders` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_code`(`code` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of genders
|
||||
-- ----------------------------
|
||||
INSERT INTO `genders` VALUES (1, 'M', 'Male', '2025-11-28 14:43:00');
|
||||
INSERT INTO `genders` VALUES (2, 'F', 'Female', '2025-11-28 14:43:00');
|
||||
INSERT INTO `genders` VALUES (3, 'O', 'Others', '2025-11-28 14:43:00');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for schools
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `schools`;
|
||||
CREATE TABLE `schools` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`address` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`contact_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status` tinyint NULL DEFAULT 1 COMMENT '1=Active, 0=Inactive',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_code`(`code` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 5 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of schools
|
||||
-- ----------------------------
|
||||
INSERT INTO `schools` VALUES (1, 'AC', 'Aldersgate College', 'Burgos St., Brgy. Quirino, Solano, Nueva Vizcaya', '0912-345-6789', 'info@aldersgate.edu.ph', '2025-11-28 14:43:00', '2025-11-28 14:43:00', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for students
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `students`;
|
||||
CREATE TABLE `students` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`student_id` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`qr_code` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`qr_code_image` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`picture_path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`full_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`gender_id` int NOT NULL,
|
||||
`year_level` int NOT NULL,
|
||||
`course_id` int NOT NULL,
|
||||
`department_id` int NOT NULL,
|
||||
`school_id` int NOT NULL,
|
||||
`birth_date` date NULL DEFAULT NULL,
|
||||
`contact_number` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`address` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status` tinyint NULL DEFAULT 1 COMMENT '1=Active, 0=Inactive',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `student_id`(`student_id` ASC) USING BTREE,
|
||||
UNIQUE INDEX `qr_code`(`qr_code` ASC) USING BTREE,
|
||||
INDEX `gender_id`(`gender_id` ASC) USING BTREE,
|
||||
INDEX `idx_student_id`(`student_id` ASC) USING BTREE,
|
||||
INDEX `idx_qr_code`(`qr_code` ASC) USING BTREE,
|
||||
INDEX `idx_course_id`(`course_id` ASC) USING BTREE,
|
||||
INDEX `idx_department_id`(`department_id` ASC) USING BTREE,
|
||||
INDEX `idx_school_id`(`school_id` ASC) USING BTREE,
|
||||
INDEX `idx_year_level`(`year_level` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE,
|
||||
INDEX `idx_full_name`(`full_name` ASC) USING BTREE,
|
||||
CONSTRAINT `students_ibfk_1` FOREIGN KEY (`gender_id`) REFERENCES `genders` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT `students_ibfk_2` FOREIGN KEY (`course_id`) REFERENCES `courses` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT `students_ibfk_3` FOREIGN KEY (`department_id`) REFERENCES `departments` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT `students_ibfk_4` FOREIGN KEY (`school_id`) REFERENCES `schools` (`id`) ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 21 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of students
|
||||
-- ----------------------------
|
||||
INSERT INTO `students` VALUES (1, '23-0217', 'STU_23-0217_692b07dd55c31', NULL, '', 'John Lloyd Sumawang', 1, 3, 1, 1, 1, '2004-12-26', '095691555892', 'johnlloydsumawang@gmail.com', 'Bascaran, Solano, Nueva Vizcaya', '2025-11-29 22:49:01', '2025-12-08 19:27:18', 1);
|
||||
INSERT INTO `students` VALUES (2, '23-0403', 'STU_23-0403_692c3532235bc', NULL, '', 'Delight Grace Yogyog', 2, 3, 1, 1, 1, '2005-08-16', '', 'delightyogyog@gmail.com', '', '2025-11-30 20:14:42', '2025-12-08 19:27:55', 1);
|
||||
INSERT INTO `students` VALUES (3, '23-0072', 'STU_23-0072_692c356aef39a', NULL, '', 'Rozalia Jane Dekket', 2, 3, 1, 1, 1, '2004-10-17', '', 'RozaliaJaneDekket@gmail.com', 'Poblacion South, Solano, N.V', '2025-11-30 20:15:38', '2025-12-08 19:28:00', 1);
|
||||
INSERT INTO `students` VALUES (4, '23-0147', 'STU_23-0147_692ce2ea80975', NULL, '', 'Jelyn Marcos Monte', 2, 3, 1, 1, 1, '2004-01-21', '0967126375', 'jelynmonte@gmail.com', 'Solano, Nueva Vizcaya', '2025-12-01 08:35:54', '2025-12-08 19:28:05', 1);
|
||||
INSERT INTO `students` VALUES (5, '15-10187', 'STU_15-10187_692e9a3234f87', 'student_15-10187_1764693277.html', NULL, 'Jayster Rey Cabay', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:50:10', '2025-12-03 00:34:37', 1);
|
||||
INSERT INTO `students` VALUES (6, '016-0097', 'STU_016-0097_692e9a9774dcc', NULL, NULL, 'John Learry Castro', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:51:51', '2025-12-02 15:51:51', 1);
|
||||
INSERT INTO `students` VALUES (7, '22-0278', 'STU_22-0278_692e9ad319f7d', NULL, NULL, 'Mark Edrian Garica', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:52:51', '2025-12-02 15:52:51', 1);
|
||||
INSERT INTO `students` VALUES (8, '22-20099', 'STU_22-20099_692e9b145d566', NULL, NULL, 'Jeon Jeon Jac', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:53:56', '2025-12-02 15:53:56', 1);
|
||||
INSERT INTO `students` VALUES (9, '23-0241', 'STU_23-0241_692e9b5e33af7', NULL, NULL, 'Hercules Jon Honrales', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:55:10', '2025-12-02 15:55:10', 1);
|
||||
INSERT INTO `students` VALUES (10, '20-10056', 'STU_20-10056_692e9be0ed5d2', NULL, NULL, 'Jan Mark Manuel', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:57:20', '2025-12-02 15:57:20', 1);
|
||||
INSERT INTO `students` VALUES (11, '23-0250', 'STU_23-0250_692e9c361c836', NULL, NULL, 'John Carlo Marcelino', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:58:46', '2025-12-02 15:58:46', 1);
|
||||
INSERT INTO `students` VALUES (12, '22-0496', 'STU_22-0496_692e9c71591fd', NULL, NULL, 'Kenn Charlee Martinez', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 15:59:45', '2025-12-02 15:59:45', 1);
|
||||
INSERT INTO `students` VALUES (13, '23-0433', 'STU_23-0433_692e9cfe5cd6d', NULL, NULL, 'Melchor Paculla Jr.', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:02:06', '2025-12-02 16:02:06', 1);
|
||||
INSERT INTO `students` VALUES (14, '016-0128', 'STU_016-0128_692e9d728aa84', NULL, NULL, 'Gregorio Ragasa', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:04:02', '2025-12-02 16:04:02', 1);
|
||||
INSERT INTO `students` VALUES (15, '23-0203', 'STU_23-0203_692e9db4c726c', NULL, NULL, 'Cyruz Sibug', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:05:08', '2025-12-02 16:05:08', 1);
|
||||
INSERT INTO `students` VALUES (16, '20-10492', 'STU_20-10492_692e9df4a5c5a', NULL, NULL, 'Jerald Solis', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:06:12', '2025-12-02 16:06:12', 1);
|
||||
INSERT INTO `students` VALUES (17, '15-10131', 'STU_15-10131_692e9e2135b6a', 'student_15-10131_1764693193.html', NULL, 'Jolas Tucli', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:06:57', '2025-12-03 00:33:13', 1);
|
||||
INSERT INTO `students` VALUES (18, '017-0104', 'STU_017-0104_692e9e4f41721', 'student_017-0104_1764692828.html', NULL, 'Jose Victor Uy', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:07:43', '2025-12-03 00:27:08', 1);
|
||||
INSERT INTO `students` VALUES (19, '18-10147', 'STU_18-10147_692e9e91c98eb', 'student_18-10147_1764692769.html', NULL, 'Jameson Valera', 1, 3, 1, 1, 1, '0000-00-00', '', '', '', '2025-12-02 16:08:49', '2025-12-03 00:26:09', 1);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for system_settings
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `system_settings`;
|
||||
CREATE TABLE `system_settings` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`setting_key` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`setting_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL,
|
||||
`updated_by` int NULL DEFAULT NULL,
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `setting_key`(`setting_key` ASC) USING BTREE,
|
||||
INDEX `updated_by`(`updated_by` ASC) USING BTREE,
|
||||
INDEX `idx_setting_key`(`setting_key` ASC) USING BTREE,
|
||||
CONSTRAINT `system_settings_ibfk_1` FOREIGN KEY (`updated_by`) REFERENCES `users` (`id`) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of system_settings
|
||||
-- ----------------------------
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for users
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `users`;
|
||||
CREATE TABLE `users` (
|
||||
`id` int NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`role` enum('admin','teacher') CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`full_name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
|
||||
`email` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
|
||||
`created_at` timestamp NOT NULL DEFAULT current_timestamp(),
|
||||
`updated_at` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE CURRENT_TIMESTAMP,
|
||||
`status` tinyint NULL DEFAULT 1 COMMENT '1=Active, 0=Inactive',
|
||||
PRIMARY KEY (`id`) USING BTREE,
|
||||
UNIQUE INDEX `username`(`username` ASC) USING BTREE,
|
||||
INDEX `idx_username`(`username` ASC) USING BTREE,
|
||||
INDEX `idx_role`(`role` ASC) USING BTREE,
|
||||
INDEX `idx_status`(`status` ASC) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = DYNAMIC;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of users
|
||||
-- ----------------------------
|
||||
INSERT INTO `users` VALUES (1, 'johnlloydsumawang26', '$2y$10$cH0FJuPLd467oX0q01ZADu6v2lh0kmfNob0HOyO5tuRstcdXBbIuS', 'admin', 'John Lloyd Sumawang', 'johnlloydsumawang@gmail.com', '2025-11-28 14:43:00', '2025-12-13 20:57:06', 1);
|
||||
INSERT INTO `users` VALUES (10, 'SPayDigong', '$2y$10$r02pNIERlJKRmrT6haCP8.YLpEAAEM0hTYRQnWpJ7ktZ6E6GRjQNq', 'admin', 'RODRIGO JR AMORIN', 'redgie@simc.gov.ph', '2025-12-13 20:35:31', '2025-12-13 20:35:40', 1);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
204
src-backup/auth/login.php
Normal file
@@ -0,0 +1,204 @@
|
||||
<?php
|
||||
require_once '../includes/config.php';
|
||||
|
||||
// If already logged in, redirect to appropriate dashboard
|
||||
if (isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true) {
|
||||
switch ($_SESSION['role']) {
|
||||
case 'admin':
|
||||
header('Location: ../admin/dashboard.php');
|
||||
break;
|
||||
case 'teacher':
|
||||
header('Location: ../teacher/dashboard.php');
|
||||
break;
|
||||
default:
|
||||
header('Location: ../index.php');
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
$error = '';
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = trim($_POST['password'] ?? '');
|
||||
|
||||
if (!empty($username) && !empty($password)) {
|
||||
// Check user in database
|
||||
$username_escaped = escape($conn, $username);
|
||||
$sql = "SELECT * FROM users WHERE username = '$username_escaped' AND status = 1 LIMIT 1";
|
||||
$result = query($conn, $sql);
|
||||
|
||||
if ($result && mysqli_num_rows($result) === 1) {
|
||||
$user = mysqli_fetch_assoc($result);
|
||||
|
||||
// Verify password (using password_verify if passwords are hashed)
|
||||
if (password_verify($password, $user['password'])) {
|
||||
// Set session variables
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
$_SESSION['full_name'] = $user['full_name'];
|
||||
$_SESSION['logged_in'] = true;
|
||||
|
||||
// Update last login
|
||||
$update_sql = "UPDATE users SET updated_at = NOW() WHERE id = " . $user['id'];
|
||||
query($conn, $update_sql);
|
||||
|
||||
// Redirect based on role
|
||||
switch ($user['role']) {
|
||||
case 'admin':
|
||||
header('Location: ../admin/dashboard.php');
|
||||
break;
|
||||
case 'teacher':
|
||||
header('Location: ../teacher/dashboard.php');
|
||||
break;
|
||||
default:
|
||||
header('Location: ../index.php');
|
||||
}
|
||||
exit();
|
||||
} else {
|
||||
$error = 'Invalid username or password';
|
||||
}
|
||||
} else {
|
||||
$error = 'Invalid username or password';
|
||||
}
|
||||
} else {
|
||||
$error = 'Please enter both username and password';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - QR Attendance System</title>
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||
<style>
|
||||
body.login-page {
|
||||
background:
|
||||
linear-gradient(rgba(22, 107, 14, 0.85), rgba(218, 230, 55, 0.85)),
|
||||
url('../assets/images/ACbackground.png');
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
|
||||
.login-card {
|
||||
background: white;
|
||||
border-radius: 15px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.2);
|
||||
overflow: hidden;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
background: #166b0e;
|
||||
color: white;
|
||||
padding: 30px 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.login-body {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.form-control {
|
||||
border-radius: 8px;
|
||||
padding: 12px 15px;
|
||||
border: 1px solid #dee2e6;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
|
||||
}
|
||||
|
||||
.btn-login {
|
||||
background: #166b0e;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 12px;
|
||||
border-radius: 8px;
|
||||
font-weight: 500;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn-login:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
|
||||
}
|
||||
|
||||
.logo {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 15px;
|
||||
}
|
||||
|
||||
.logo i {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="login-page">
|
||||
<div class="login-card">
|
||||
<div class="login-header">
|
||||
<h5>Login</h5>
|
||||
</div>
|
||||
|
||||
<div class="login-body">
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert-danger alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-exclamation-triangle me-2"></i>
|
||||
<?php echo $error; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<form method="POST" action="">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">
|
||||
<i class="bi bi-person me-1"></i> Username
|
||||
</label>
|
||||
<input type="text" class="form-control" id="username" name="username"
|
||||
placeholder="Enter username" required autofocus>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<label for="password" class="form-label">
|
||||
<i class="bi bi-lock me-1"></i> Password
|
||||
</label>
|
||||
<input type="password" class="form-control" id="password" name="password"
|
||||
placeholder="Enter password" required>
|
||||
</div>
|
||||
|
||||
<div class="d-grid mb-3">
|
||||
<button type="submit" class="btn btn-login">
|
||||
<i class="bi bi-box-arrow-in-right me-1"></i> Login
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<small class="text-muted">
|
||||
<p>Programmed by: John Lloyd Sumawang</p>
|
||||
</small>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
6
src-backup/auth/logout.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
session_start();
|
||||
session_destroy();
|
||||
header('Location: login.php');
|
||||
exit();
|
||||
?>
|
||||
79
src-backup/includes/auth.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
require_once 'includes/database.php';
|
||||
|
||||
class Auth {
|
||||
private $db;
|
||||
|
||||
public function __construct() {
|
||||
global $db;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
public function login($username, $password) {
|
||||
$username = $this->db->escape($username);
|
||||
|
||||
$sql = "SELECT * FROM users WHERE username = '$username' AND status = 1";
|
||||
$result = $this->db->query($sql);
|
||||
|
||||
if ($result->num_rows === 1) {
|
||||
$user = $result->fetch_assoc();
|
||||
|
||||
if (password_verify($password, $user['password'])) {
|
||||
$_SESSION['user_id'] = $user['id'];
|
||||
$_SESSION['username'] = $user['username'];
|
||||
$_SESSION['role'] = $user['role'];
|
||||
$_SESSION['full_name'] = $user['full_name'];
|
||||
$_SESSION['logged_in'] = true;
|
||||
|
||||
// Update last login
|
||||
$update_sql = "UPDATE users SET updated_at = NOW() WHERE id = " . $user['id'];
|
||||
$this->db->query($update_sql);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function logout() {
|
||||
session_destroy();
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
|
||||
public function isLoggedIn() {
|
||||
return isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true;
|
||||
}
|
||||
|
||||
public function requireLogin() {
|
||||
if (!$this->isLoggedIn()) {
|
||||
header('Location: ../auth/login.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
public function requireRole($allowedRoles) {
|
||||
$this->requireLogin();
|
||||
|
||||
if (!in_array($_SESSION['role'], (array)$allowedRoles)) {
|
||||
header('Location: ../dashboard.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
public function getCurrentUser() {
|
||||
if ($this->isLoggedIn()) {
|
||||
return [
|
||||
'id' => $_SESSION['user_id'],
|
||||
'username' => $_SESSION['username'],
|
||||
'role' => $_SESSION['role'],
|
||||
'full_name' => $_SESSION['full_name']
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$auth = new Auth();
|
||||
?>
|
||||
50
src-backup/includes/config.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
session_start();
|
||||
|
||||
// Database Configuration
|
||||
define('DB_HOST', getenv('DB_HOST') ?: '127.0.0.1');
|
||||
define('DB_USER', getenv('DB_USER') ?: 'root');
|
||||
define('DB_PASS', getenv('DB_PASS') !== false ? getenv('DB_PASS') : '');
|
||||
define('DB_NAME', getenv('DB_NAME') ?: 'attendance_system');
|
||||
|
||||
// System Configuration
|
||||
define('SITE_NAME', 'QR Attendance System');
|
||||
define('SITE_URL', 'http://localhost/attendance_system/');
|
||||
define('TIMEZONE', 'Asia/Manila');
|
||||
|
||||
// QR Code Configuration
|
||||
define('QR_VALIDITY_MINUTES', 30); // QR code validity period
|
||||
|
||||
// Set timezone
|
||||
date_default_timezone_set(TIMEZONE);
|
||||
|
||||
// Error reporting (disable in production)
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', 1);
|
||||
|
||||
// Create database connection
|
||||
$conn = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);
|
||||
|
||||
// Check connection
|
||||
if (!$conn) {
|
||||
die("Database connection failed: " . mysqli_connect_error());
|
||||
}
|
||||
|
||||
// Set charset
|
||||
mysqli_set_charset($conn, "utf8mb4");
|
||||
|
||||
// Function to escape input
|
||||
function escape($conn, $value) {
|
||||
return mysqli_real_escape_string($conn, $value);
|
||||
}
|
||||
|
||||
// Function to execute query
|
||||
function query($conn, $sql) {
|
||||
return mysqli_query($conn, $sql);
|
||||
}
|
||||
|
||||
// Function to get last insert ID
|
||||
function getInsertId($conn) {
|
||||
return mysqli_insert_id($conn);
|
||||
}
|
||||
?>
|
||||
38
src-backup/includes/database.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// Database configuration (use env vars for Docker)
|
||||
$host = getenv('DB_HOST') ?: '127.0.0.1';
|
||||
$dbname = getenv('DB_NAME') ?: 'attendance_system';
|
||||
$username = getenv('DB_USER') ?: 'root';
|
||||
$password = getenv('DB_PASS') !== false ? getenv('DB_PASS') : '';
|
||||
|
||||
try {
|
||||
// Create PDO connection
|
||||
$pdo = new PDO(
|
||||
"mysql:host=$host;dbname=$dbname;charset=utf8mb4",
|
||||
$username,
|
||||
$password,
|
||||
[
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
||||
PDO::ATTR_EMULATE_PREPARES => false
|
||||
]
|
||||
);
|
||||
|
||||
// Optional: Set timezone
|
||||
$pdo->exec("SET time_zone = '+08:00'");
|
||||
|
||||
// Uncomment for debugging
|
||||
// error_log("Database connected successfully");
|
||||
|
||||
} catch (PDOException $e) {
|
||||
// Log the error and show user-friendly message
|
||||
error_log("Database connection failed: " . $e->getMessage());
|
||||
|
||||
// For development - show detailed error
|
||||
if (isset($_SESSION['role']) && $_SESSION['role'] === 'admin') {
|
||||
die("Database connection failed: " . $e->getMessage());
|
||||
} else {
|
||||
die("System temporarily unavailable. Please try again later.");
|
||||
}
|
||||
}
|
||||
?>
|
||||
95
src-backup/includes/footer.php
Normal file
@@ -0,0 +1,95 @@
|
||||
</div> <!-- End of content-wrapper -->
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="footer mt-auto py-3 bg-white border-top">
|
||||
<div class="container-fluid">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-md-6">
|
||||
<span class="text-muted">
|
||||
© <?php echo date('Y'); ?> Attendance Managament System | Programmed by John Lloyd Sumawang
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-6 text-md-end">
|
||||
<span class="text-muted">
|
||||
<i class="bi bi-server me-1"></i> Server Time: <?php echo date('h:i:s A'); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<!-- JavaScript Libraries -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.11.5/js/jquery.dataTables.min.js"></script>
|
||||
<script src="https://cdn.datatables.net/1.11.5/js/dataTables.bootstrap5.min.js"></script>
|
||||
|
||||
<script>
|
||||
// Update current time
|
||||
function updateCurrentTime() {
|
||||
const now = new Date();
|
||||
const timeString = now.toLocaleTimeString('en-US', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit',
|
||||
hour12: true
|
||||
});
|
||||
document.getElementById('current-time').textContent = timeString;
|
||||
}
|
||||
|
||||
setInterval(updateCurrentTime, 1000);
|
||||
|
||||
// Mobile sidebar toggle
|
||||
document.getElementById('sidebarToggle').addEventListener('click', function() {
|
||||
document.querySelector('.sidebar').classList.toggle('show');
|
||||
});
|
||||
|
||||
// Close sidebar when clicking outside on mobile
|
||||
document.addEventListener('click', function(event) {
|
||||
const sidebar = document.querySelector('.sidebar');
|
||||
const toggleBtn = document.getElementById('sidebarToggle');
|
||||
|
||||
if (window.innerWidth < 768 &&
|
||||
!sidebar.contains(event.target) &&
|
||||
!toggleBtn.contains(event.target) &&
|
||||
sidebar.classList.contains('show')) {
|
||||
sidebar.classList.remove('show');
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize tooltips
|
||||
var tooltipTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="tooltip"]'));
|
||||
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
||||
return new bootstrap.Tooltip(tooltipTriggerEl);
|
||||
});
|
||||
|
||||
// Auto-dismiss alerts after 5 seconds
|
||||
setTimeout(function() {
|
||||
var alerts = document.querySelectorAll('.alert:not(.alert-permanent)');
|
||||
alerts.forEach(function(alert) {
|
||||
var bsAlert = new bootstrap.Alert(alert);
|
||||
bsAlert.close();
|
||||
});
|
||||
}, 5000);
|
||||
|
||||
// Add active class to current page in navigation
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const currentPage = window.location.pathname.split('/').pop();
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
|
||||
navLinks.forEach(link => {
|
||||
if (link.getAttribute('href') === currentPage) {
|
||||
link.classList.add('active');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<!-- Page-specific scripts -->
|
||||
<?php if (isset($page_scripts)): ?>
|
||||
<?php echo $page_scripts; ?>
|
||||
<?php endif; ?>
|
||||
</body>
|
||||
</html>
|
||||
531
src-backup/includes/header.php
Normal file
@@ -0,0 +1,531 @@
|
||||
<?php
|
||||
if (!isset($title)) {
|
||||
$title = 'QR Attendance System';
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?php echo $title; ?></title>
|
||||
|
||||
<!-- Bootstrap 5 -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
|
||||
<!-- DataTables -->
|
||||
<link rel="stylesheet" href="https://cdn.datatables.net/1.11.5/css/dataTables.bootstrap5.min.css">
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary: #549239;
|
||||
--secondary: #504e2c;
|
||||
--success: #27ae60;
|
||||
--danger: #e74c3c;
|
||||
--warning: #f39c12;
|
||||
--light: #f8f9fa;
|
||||
--dark: #343a40;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
background-color: #f5f7fb;
|
||||
color: #333333;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Main container */
|
||||
.main-container {
|
||||
display: flex;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar {
|
||||
width: 250px;
|
||||
background: #37502c;
|
||||
color: white;
|
||||
transition: all 0.3s;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
padding: 20px 15px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border-bottom: 1px solid rgba(255,255,255,0.1);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
text-align: center;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
background: rgba(255,255,255,0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 15px;
|
||||
border: 3px solid var(--primary);
|
||||
}
|
||||
|
||||
.user-avatar i {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.sidebar .nav-link {
|
||||
color: #b6c3b0;
|
||||
padding: 12px 20px;
|
||||
margin: 2px 10px;
|
||||
border-radius: 8px;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sidebar .nav-link:hover {
|
||||
color: white;
|
||||
background: rgba(169, 219, 52, 0.2);
|
||||
transform: translateX(5px);
|
||||
}
|
||||
|
||||
.sidebar .nav-link.active {
|
||||
color: white;
|
||||
background: var(--primary);
|
||||
box-shadow: 0 4px 15px rgba(9, 109, 9, 0.4);
|
||||
}
|
||||
|
||||
.sidebar .nav-link i {
|
||||
width: 25px;
|
||||
font-size: 1.2rem;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.sidebar .nav-item {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
/* Main content area */
|
||||
.main-content {
|
||||
flex: 1;
|
||||
margin-left: 250px;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Top navbar */
|
||||
.top-navbar {
|
||||
background: white;
|
||||
border-bottom: 1px solid #e3e6f0;
|
||||
padding: 0.8rem 1.5rem;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
color: var(--primary);
|
||||
font-weight: 600;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-family: 'Courier New', monospace;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Content wrapper */
|
||||
.content-wrapper {
|
||||
flex: 1;
|
||||
padding: 20px;
|
||||
background: #f5f7fb;
|
||||
}
|
||||
|
||||
/* Cards */
|
||||
.card {
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
|
||||
margin-bottom: 20px;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 25px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background:#166b0e;
|
||||
color: white;
|
||||
border-radius: 10px 10px 0 0;
|
||||
border: none;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
.card-header h6 {
|
||||
margin: 0;
|
||||
font-weight: 600;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.btn {
|
||||
border-radius: 8px;
|
||||
padding: 8px 20px;
|
||||
font-weight: 500;
|
||||
border: none;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: #205e03;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
.badge {
|
||||
padding: 6px 12px;
|
||||
border-radius: 20px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.table {
|
||||
background: white;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.table thead th {
|
||||
border-bottom: 2px solid #e3e6f0;
|
||||
font-weight: 700;
|
||||
color: var(--secondary);
|
||||
background: #f8f9fa;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.table tbody td {
|
||||
padding: 12px 15px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody tr:hover {
|
||||
background-color: rgba(155, 219, 52, 0.05);
|
||||
}
|
||||
|
||||
/* Form styles */
|
||||
.form-control, .form-select {
|
||||
border-radius: 8px;
|
||||
padding: 10px 15px;
|
||||
border: 1px solid #dee2e6;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.form-control:focus, .form-select:focus {
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 0.25rem rgba(155, 219, 52, 0.25);
|
||||
}
|
||||
|
||||
/* Modal styles */
|
||||
.modal-content {
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
background: #56b32b;
|
||||
color: white;
|
||||
border-radius: 10px 10px 0 0;
|
||||
padding: 15px 20px;
|
||||
}
|
||||
|
||||
/* Stats cards */
|
||||
.stat-card {
|
||||
border-left: 4px solid var(--primary);
|
||||
}
|
||||
|
||||
.stat-card .card-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.stat-card i {
|
||||
font-size: 2.5rem;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
/* Responsive adjustments */
|
||||
@media (max-width: 768px) {
|
||||
.sidebar {
|
||||
margin-left: -250px;
|
||||
position: fixed;
|
||||
z-index: 1001;
|
||||
}
|
||||
|
||||
.sidebar.show {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.top-navbar {
|
||||
padding: 0.8rem 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Animation for alerts */
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; transform: translateY(-10px); }
|
||||
to { opacity: 1; transform: translateY(0); }
|
||||
}
|
||||
|
||||
.alert {
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
/* Action buttons */
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.action-buttons .btn {
|
||||
padding: 5px 10px;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Status badges */
|
||||
.status-active {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status-inactive {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
/* Search box */
|
||||
.search-box {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-box i {
|
||||
position: absolute;
|
||||
left: 15px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #6c757d;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
padding-left: 40px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="main-container">
|
||||
<!-- Sidebar -->
|
||||
<aside class="sidebar">
|
||||
<div class="sidebar-header">
|
||||
<h4 class="text-center mb-0">
|
||||
<i class="bi bi-qr-code-scan me-2"></i>
|
||||
AMS
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<!-- User Info -->
|
||||
<div class="user-info">
|
||||
<div class="user-avatar">
|
||||
<i class="bi bi-person-circle"></i>
|
||||
</div>
|
||||
<h5 class="mb-1"><?php echo htmlspecialchars($_SESSION['full_name'] ?? 'User'); ?></h5>
|
||||
<small class="text-light">
|
||||
<?php
|
||||
$role = $_SESSION['role'] ?? 'user';
|
||||
$role_badge = '';
|
||||
switch($role) {
|
||||
case 'admin': $role_badge = 'danger'; break;
|
||||
case 'teacher': $role_badge = 'success'; break;
|
||||
case 'student': $role_badge = 'info'; break;
|
||||
default: $role_badge = 'secondary';
|
||||
}
|
||||
?>
|
||||
<span class="badge bg-<?php echo $role_badge; ?>">
|
||||
<?php echo ucfirst($role); ?>
|
||||
</span>
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<!-- Navigation -->
|
||||
<div class="sidebar-nav px-2">
|
||||
<ul class="nav flex-column">
|
||||
<?php if ($_SESSION['role'] === 'admin'): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'dashboard.php' ? 'active' : ''; ?>" href="dashboard.php">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'users.php' ? 'active' : ''; ?>" href="users.php">
|
||||
<i class="bi bi-people-fill"></i> User
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'manage_students.php' ? 'active' : ''; ?>" href="manage_students.php">
|
||||
<i class="bi bi-people"></i> Students
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'manage_activities.php' ? 'active' : ''; ?>" href="manage_activities.php">
|
||||
<i class="bi bi-calendar-event"></i> Activities
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'attendance.php' ? 'active' : ''; ?>" href="attendance.php">
|
||||
<i class="bi bi-qr-code-scan"></i> Scan QR
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'reports.php' ? 'active' : ''; ?>" href="reports.php">
|
||||
<i class="bi bi-file-earmark-text"></i> Reports
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<?php elseif ($_SESSION['role'] === 'teacher'): ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'dashboard.php' ? 'active' : ''; ?>" href="dashboard.php">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'attendance.php' ? 'active' : ''; ?>" href="attendance.php">
|
||||
<i class="bi bi-qr-code-scan"></i> Take Attendance
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'reports.php' ? 'active' : ''; ?>" href="reports.php">
|
||||
<i class="bi bi-file-earmark-text"></i> Reports
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'activities.php' ? 'active' : ''; ?>" href="activities.php">
|
||||
<i class="bi bi-calendar-event"></i> My Activities
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<?php else: ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'dashboard.php' ? 'active' : ''; ?>" href="dashboard.php">
|
||||
<i class="bi bi-speedometer2"></i> Dashboard
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'profile.php' ? 'active' : ''; ?>" href="profile.php">
|
||||
<i class="bi bi-person"></i> My Profile
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'attendance.php' ? 'active' : ''; ?>" href="attendance.php">
|
||||
<i class="bi bi-clock-history"></i> Attendance
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link <?php echo basename($_SERVER['PHP_SELF']) == 'qr_code.php' ? 'active' : ''; ?>" href="qr_code.php">
|
||||
<i class="bi bi-qr-code"></i> My QR Code
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
|
||||
<!-- Logout -->
|
||||
<ul class="nav flex-column mt-4">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link text-danger" href="../auth/logout.php">
|
||||
<i class="bi bi-box-arrow-right"></i> Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="main-content">
|
||||
<!-- Top Navbar -->
|
||||
<nav class="top-navbar navbar navbar-expand-lg">
|
||||
<div class="container-fluid">
|
||||
<!-- Mobile sidebar toggle -->
|
||||
<button class="btn btn-outline-primary d-md-none me-2" type="button" id="sidebarToggle">
|
||||
<i class="bi bi-list"></i>
|
||||
</button>
|
||||
|
||||
<!-- Page title -->
|
||||
<span class="navbar-brand">
|
||||
<?php echo htmlspecialchars($title); ?>
|
||||
</span>
|
||||
|
||||
<!-- Time and notifications -->
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="time-display me-3">
|
||||
<i class="bi bi-clock me-1"></i>
|
||||
<span id="current-time"><?php echo date('h:i:s A'); ?></span>
|
||||
</div>
|
||||
<div class="date-display me-3">
|
||||
<i class="bi bi-calendar-check me-1"></i>
|
||||
<?php echo date('F j, Y'); ?>
|
||||
</div>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown">
|
||||
<i class="bi bi-gear"></i>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-end">
|
||||
<li><a class="dropdown-item" href="profile.php"><i class="bi bi-person me-2"></i> Profile</a></li>
|
||||
<li><a class="dropdown-item" href="change_password.php"><i class="bi bi-lock me-2"></i> Change Password</a></li>
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
<li><a class="dropdown-item text-danger" href="../auth/logout.php"><i class="bi bi-box-arrow-right me-2"></i> Logout</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- Page Content -->
|
||||
<div class="content-wrapper">
|
||||
<!-- Content will be inserted here -->
|
||||
|
||||
<?php
|
||||
// Check for session messages
|
||||
if (isset($_SESSION['message'])) {
|
||||
$message_type = $_SESSION['message_type'] ?? 'success';
|
||||
?>
|
||||
<div class="alert alert-<?php echo $message_type; ?> alert-dismissible fade show" role="alert">
|
||||
<?php echo $_SESSION['message']; ?>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<?php
|
||||
unset($_SESSION['message']);
|
||||
unset($_SESSION['message_type']);
|
||||
}
|
||||
?>
|
||||
38
src-backup/includes/phpqrcode/CHANGELOG
Normal file
@@ -0,0 +1,38 @@
|
||||
* 1.0.0 build 2010031920
|
||||
|
||||
- first public release
|
||||
- help in readme, install
|
||||
- cleanup ans separation of QRtools and QRspec
|
||||
- now TCPDF binding requires minimal changes in TCPDF, having most of job
|
||||
done in QRtools tcpdfBarcodeArray
|
||||
- nicer QRtools::timeBenchmark output
|
||||
- license and copyright notices in files
|
||||
- indent cleanup - from tab to 4spc, keep it that way please :)
|
||||
- sf project, repository, wiki
|
||||
- simple code generator in index.php
|
||||
|
||||
* 1.1.0 build 2010032113
|
||||
|
||||
- added merge tool wich generate merged version of code
|
||||
located in phpqrcode.php
|
||||
- splited qrconst.php from qrlib.php
|
||||
|
||||
* 1.1.1 build 2010032405
|
||||
|
||||
- patch by Rick Seymour allowing saving PNG and displaying it at the same time
|
||||
- added version info in VERSION file
|
||||
- modified merge tool to include version info into generated file
|
||||
- fixed e-mail in almost all head comments
|
||||
|
||||
* 1.1.2 build 2010032722
|
||||
|
||||
- full integration with TCPDF thanks to Nicola Asuni, it's author
|
||||
- fixed bug with alphanumeric encoding detection
|
||||
|
||||
* 1.1.3 build 2010081807
|
||||
|
||||
- short opening tags replaced with standard ones
|
||||
|
||||
* 1.1.4 build 2010100721
|
||||
|
||||
- added missing static keyword QRinput::check (found by Luke Brookhart, Onjax LLC)
|
||||
67
src-backup/includes/phpqrcode/INSTALL
Normal file
@@ -0,0 +1,67 @@
|
||||
== REQUIREMENTS ==
|
||||
|
||||
* PHP5
|
||||
* PHP GD2 extension with JPEG and PNG support
|
||||
|
||||
== INSTALLATION ==
|
||||
|
||||
If you want to recreate cache by yourself make sure cache directory is
|
||||
writable and you have permisions to write into it. Also make sure you are
|
||||
able to read files in it if you have cache option enabled
|
||||
|
||||
== CONFIGURATION ==
|
||||
|
||||
Feel free to modify config constants in qrconfig.php file. Read about it in
|
||||
provided comments and project wiki page (links in README file)
|
||||
|
||||
== QUICK START ==
|
||||
|
||||
Notice: probably you should'nt use all of this in same script :)
|
||||
|
||||
<?phpb
|
||||
|
||||
//include only that one, rest required files will be included from it
|
||||
include "qrlib.php"
|
||||
|
||||
//write code into file, Error corection lecer is lowest, L (one form: L,M,Q,H)
|
||||
//each code square will be 4x4 pixels (4x zoom)
|
||||
//code will have 2 code squares white boundary around
|
||||
|
||||
QRcode::png('PHP QR Code :)', 'test.png', 'L', 4, 2);
|
||||
|
||||
//same as above but outputs file directly into browser (with appr. header etc.)
|
||||
//all other settings are default
|
||||
//WARNING! it should be FIRST and ONLY output generated by script, otherwise
|
||||
//rest of output will land inside PNG binary, breaking it for sure
|
||||
QRcode::png('PHP QR Code :)');
|
||||
|
||||
//show benchmark
|
||||
QRtools::timeBenchmark();
|
||||
|
||||
//rebuild cache
|
||||
QRtools::buildCache();
|
||||
|
||||
//code generated in text mode - as a binary table
|
||||
//then displayed out as HTML using Unicode block building chars :)
|
||||
$tab = $qr->encode('PHP QR Code :)');
|
||||
QRspec::debug($tab, true);
|
||||
|
||||
== TCPDF INTEGRATION ==
|
||||
|
||||
Inside bindings/tcpdf you will find slightly modified 2dbarcodes.php.
|
||||
Instal phpqrcode liblaty inside tcpdf folder, then overwrite (or merge)
|
||||
2dbarcodes.php
|
||||
|
||||
Then use similar as example #50 from TCPDF examples:
|
||||
|
||||
<?php
|
||||
|
||||
$style = array(
|
||||
'border' => true,
|
||||
'padding' => 4,
|
||||
'fgcolor' => array(0,0,0),
|
||||
'bgcolor' => false, //array(255,255,255)
|
||||
);
|
||||
|
||||
//code name: QR, specify error correction level after semicolon (L,M,Q,H)
|
||||
$pdf->write2DBarcode('PHP QR Code :)', 'QR,L', '', '', 30, 30, $style, 'N');
|
||||
165
src-backup/includes/phpqrcode/LICENSE
Normal file
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
45
src-backup/includes/phpqrcode/README
Normal file
@@ -0,0 +1,45 @@
|
||||
This is PHP implementation of QR Code 2-D barcode generator. It is pure-php
|
||||
LGPL-licensed implementation based on C libqrencode by Kentaro Fukuchi.
|
||||
|
||||
== LICENSING ==
|
||||
|
||||
Copyright (C) 2010 by Dominik Dzienia
|
||||
|
||||
This library is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the Free
|
||||
Software Foundation; either version 3 of the License, or any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. See the GNU Lesser General Public License (LICENSE file)
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this library; if not, write to the Free Software Foundation, Inc., 51
|
||||
Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
== INSTALATION AND USAGE ==
|
||||
|
||||
* INSTALL file
|
||||
* http://sourceforge.net/apps/mediawiki/phpqrcode/index.php?title=Main_Page
|
||||
|
||||
== CONTACT ==
|
||||
|
||||
Fell free to contact me via e-mail (deltalab at poczta dot fm) or using
|
||||
folowing project pages:
|
||||
|
||||
* http://sourceforge.net/projects/phpqrcode/
|
||||
* http://phpqrcode.sourceforge.net/
|
||||
|
||||
== ACKNOWLEDGMENTS ==
|
||||
|
||||
Based on C libqrencode library (ver. 3.1.1)
|
||||
Copyright (C) 2006-2010 by Kentaro Fukuchi
|
||||
http://megaui.net/fukuchi/works/qrencode/index.en.html
|
||||
|
||||
QR Code is registered trademarks of DENSO WAVE INCORPORATED in JAPAN and other
|
||||
countries.
|
||||
|
||||
Reed-Solomon code encoder is written by Phil Karn, KA9Q.
|
||||
Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q
|
||||
|
||||
2
src-backup/includes/phpqrcode/VERSION
Normal file
@@ -0,0 +1,2 @@
|
||||
1.1.4
|
||||
2010100721
|
||||
2875
src-backup/includes/phpqrcode/bindings/tcpdf/qrcode.php
Normal file
2
src-backup/includes/phpqrcode/cache/frame_1.dat
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
xڝ<EFBFBD><EFBFBD>
|
||||
<EFBFBD> E9<45>u<06><>`<60>"PńC<C584>牗T!0$
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_1.png
vendored
Normal file
|
After Width: | Height: | Size: 126 B |
BIN
src-backup/includes/phpqrcode/cache/frame_10.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_10.png
vendored
Normal file
|
After Width: | Height: | Size: 202 B |
BIN
src-backup/includes/phpqrcode/cache/frame_11.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_11.png
vendored
Normal file
|
After Width: | Height: | Size: 205 B |
BIN
src-backup/includes/phpqrcode/cache/frame_12.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_12.png
vendored
Normal file
|
After Width: | Height: | Size: 216 B |
BIN
src-backup/includes/phpqrcode/cache/frame_13.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_13.png
vendored
Normal file
|
After Width: | Height: | Size: 210 B |
BIN
src-backup/includes/phpqrcode/cache/frame_14.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_14.png
vendored
Normal file
|
After Width: | Height: | Size: 213 B |
BIN
src-backup/includes/phpqrcode/cache/frame_15.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_15.png
vendored
Normal file
|
After Width: | Height: | Size: 219 B |
1
src-backup/includes/phpqrcode/cache/frame_16.dat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A<0E> E]s<>IX<49>;<3B><01>n6<6E><36>`<60>q<EFBFBD><71><EFBFBD>W6<57><36><EFBFBD><04>`<60>%A/3!<21><><EFBFBD><EFBFBD><EFBFBD>!g<><67>̡<EFBFBD>1N)<0B>E<EFBFBD><45>|;<3B><>>6⸏<36>97$<0E><><EFBFBD><EFBFBD>c]kk<6B><6B>w<EFBFBD>1<EFBFBD><31>[<5B>m<EFBFBD>C͜c<CD9C>R<><52><EFBFBD><EFBFBD>><3E><><1A><><EFBFBD>E,<2C>hʼnp<C589>#<1C>xF<1C>yW<79><57>VWG<57><47><EFBFBD>3<EFBFBD><33>+<2B><0F><><EFBFBD>˓<EFBFBD>S<EFBFBD><53>}Ğ<>#<1C>G8b^c^c<><63><11>p<EFBFBD>c&3YQ"<11><1B><><EFBFBD><EFBFBD>v<EFBFBD><76><11><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<EFBFBD>9<EFBFBD>܇<EFBFBD>}<7D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <09>Ŀ<EFBFBD>Q<><51>L<EFBFBD>/<2F><><EFBFBD><EFBFBD>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_16.png
vendored
Normal file
|
After Width: | Height: | Size: 211 B |
BIN
src-backup/includes/phpqrcode/cache/frame_17.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_17.png
vendored
Normal file
|
After Width: | Height: | Size: 211 B |
2
src-backup/includes/phpqrcode/cache/frame_18.dat
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A
|
||||
<EFBFBD>0E]<5D>օ,2;s<><73>&<26>͚h<14><1D><>O<EFBFBD><4F><EFBFBD><7F><EFBFBD><EFBFBD>1&09OIv@DD<44><0C>&<26>ىK<D989>X<EFBFBD><58>Fv<46><<11>dq<64>9<><%h<><68>Y<>s!(d<><64><EFBFBD>s;~||b(<28><>Yůg#<23>`<60>K<16><>S<EFBFBD><53><EFBFBD><EFBFBD>Ķ<EFBFBD><C4B6>s<1C>idߍLg:ә<>t<EFBFBD>/gm<67><6D><EFBFBD><EFBFBD>k<EFBFBD>M<>3<EFBFBD>{<7B>4rT<72>Q<EFBFBD><51>e<EFBFBD><65>s<EFBFBD>><3E><ә<>t<EFBFBD>3<EFBFBD><33><EFBFBD>;<12>H<EFBFBD>#љ<>t<EFBFBD>3<EFBFBD><EFBFBD>Y<EFBFBD>+og<>h<EFBFBD><68><EFBFBD><EFBFBD>ٽ<EFBFBD>ln<6C><6E>F><3E>i^<5E>#awm;g<>~p<>g<EFBFBD>Ns{6z<36><7A><EFBFBD><EFBFBD><19><><EFBFBD><EFBFBD>p<><70>'
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_18.png
vendored
Normal file
|
After Width: | Height: | Size: 228 B |
3
src-backup/includes/phpqrcode/cache/frame_19.dat
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A
|
||||
<EFBFBD> E<><45><EFBFBD>.<2E>No<4E>7ћ<37><D19B>iiR<>N2<4E><32>W%<25>x<04>@<40>ڜ<EFBFBD>'<27>
|
||||
u<EFBFBD>6<EFBFBD><EFBFBD><EFBFBD>.<2E>*S;}<7D><><EFBFBD>à<EFBFBD>T<0B><><EFBFBD>zr<>t<><74>%<25>,<2C><><EFBFBD><EFBFBD><EFBFBD>}<7D>;<3B><><EFBFBD>)<29><><EFBFBD><EFBFBD><EFBFBD>Z<EFBFBD><5A>L<EFBFBD><4C><EFBFBD><EFBFBD><EFBFBD>P<EFBFBD><50>$<24><><EFBFBD><1E>q<EFBFBD>g<EFBFBD>L<EFBFBD><4C>dJ<64>;<3B><>w<><77><EFBFBD>.]z#<23><><EFBFBD>[͝<><CD9D>Og<4F><67><EFBFBD><EFBFBD>"<22><> <09>B<EFBFBD><17><>}<7D>}<7D>;<3B><>w<><77><1D><>#1Gb<47><62>;<3B><>w<><77><EFBFBD>_<EFBFBD>C+w<>@Df<44><04><><EFBFBD><EFBFBD>u<EFBFBD><75>2<EFBFBD><32><EFBFBD><EFBFBD>N<EFBFBD><4E>9R7|pW<70>k<EFBFBD><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>k<><6B><EFBFBD><07><><1C><><1C><>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_19.png
vendored
Normal file
|
After Width: | Height: | Size: 225 B |
1
src-backup/includes/phpqrcode/cache/frame_2.dat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
x<EFBFBD>͒<EFBFBD>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_2.png
vendored
Normal file
|
After Width: | Height: | Size: 144 B |
BIN
src-backup/includes/phpqrcode/cache/frame_20.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_20.png
vendored
Normal file
|
After Width: | Height: | Size: 225 B |
1
src-backup/includes/phpqrcode/cache/frame_21.dat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A<0E> E]s<>IX<49>;<3B><01>n6Up<55><13><>в<EFBFBD><D0B2>]٘<><i-eW<65><57><EFBFBD><EFBFBD>)<29><>ŕ<EFBFBD><C595>
H\jvq<76>HL\6<><36><EFBFBD>ЅrI<72><06>Lܹ<4C><DCB9>%<25><18>@<40><><EFBFBD>V<EFBFBD>v<EFBFBD><76><EFBFBD><EFBFBD><EFBFBD>(<28>P4|<7C>Xn<58>gɝ<><15>~]D<><44><EFBFBD><EFBFBD>u1Us S\<5C><16><>,<2C><>2<EFBFBD><1F>N<EFBFBD><4E>?D<>K<EFBFBD><4B>F-:<3A>eJ]p_<70><16><>,<2C>a0<61>`<60><><EFBFBD>X<><16>`<60><><0C>w,`X<>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>5<0B><>Y4{<7B><><EFBFBD><EFBFBD>2<EFBFBD><32><EFBFBD>v<EFBFBD>Js<4A><73><EFBFBD><EFBFBD>9<EFBFBD><39><EFBFBD>)<29>u<EFBFBD>۹<EFBFBD><DBB9><EFBFBD>,<17>]<5D><><EFBFBD><EFBFBD>^_<>7$<24>_<EFBFBD>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_21.png
vendored
Normal file
|
After Width: | Height: | Size: 235 B |
3
src-backup/includes/phpqrcode/cache/frame_22.dat
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A
|
||||
<EFBFBD>0E]{<7B><>.<2E>]{{{<7B><>Z<EFBFBD>Bep<65><06>we@<1F>V<EFBFBD>ERZ3<5A><33>"*2o<32>4<EFBFBD>y<EFBFBD>)i#d<>bdF҅<46><12>I"<22><><14>4<EFBFBD><34>W<17>I<EFBFBD>u<EFBFBD><75>45<34>x<EFBFBD>.Z<>S<EFBFBD>{<7B><><EFBFBD>8<EFBFBD><38><07>k={o.<2E>q<EFBFBD><71><01>[<13><>:帒q<E5B892><71><EFBFBD>y
|
||||
)t#<23><>N8<4E>dCj<43>-O<>OG}<7D>:/<2F>:s<>z!<21>)^<<3C>e<EFBFBD><65>S<EFBFBD>u<EFBFBD>{<7B> '<27>p<EFBFBD> '<27>=<3D>=<3D>=<3D>'<27>p<EFBFBD> '<27>p<EFBFBD>ߣߣ<DFA3><DFA3><1F>N8<4E><38><EFBFBD><EFBFBD>9<EFBFBD><39><EFBFBD><EFBFBD>pQQ<51>]H<19>pz<70><7A><EFBFBD>G<EFBFBD>^<5E><>Q<EFBFBD><51>I|<7C>߳<EFBFBD>u;9<><39><EFBFBD><EFBFBD><EFBFBD>d;<3B>X~$<24><><EFBFBD><13>t<1E><><1B><>dy
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_22.png
vendored
Normal file
|
After Width: | Height: | Size: 226 B |
3
src-backup/includes/phpqrcode/cache/frame_23.dat
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A
|
||||
<EFBFBD> E<><45><EFBFBD>fo<>7ћU<D19B>) %M!Δ<><CE94>Yu(<<1E><><17>sK<73><4B>T<EFBFBD><54><EFBFBD>
|
||||
<EFBFBD>&<26>I<>\i+<2B>Ъ<EFBFBD>(m<><6D>FQ<46><51><EFBFBD>h<EFBFBD><68><EFBFBD><EFBFBD><EFBFBD>v~n1<6E>o<>]s<><73><EFBFBD><EFBFBD><EFBFBD>_ޟ<18>3`<60>_w2<77>ȹ<EFBFBD>lc[<5B><>;<3B><12>c֟ˤ<D69F>N<EFBFBD><4E>4<EFBFBD>p<EFBFBD>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_23.png
vendored
Normal file
|
After Width: | Height: | Size: 220 B |
1
src-backup/includes/phpqrcode/cache/frame_24.dat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A<0E> E<><45><EFBFBD>MX0;<3B><><EFBFBD>nVP4<50>HSS<19>x<EFBFBD>U3<55>/O<><4F>LiJ4<4A><34><EFBFBD>V<EFBFBD>JC<4A>%<25><>6VR&<16><>D<EFBFBD>B<EFBFBD>HjD<6A><44>J<0E>??<3F><><EFBFBD>Bl<42>cDZ<><C7B1><EFBFBD>'<27>U<EFBFBD><55>X<EFBFBD>U<EFBFBD>ޏ0<DE8F><30>yw<79>į<EFBFBD>j<EFBFBD><6A>똳<EFBFBD>3ś<33><C59B><EFBFBD>cj<63><6A><EFBFBD>{<7B><><12>:Gq<>G<1C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E>N<EFBFBD>v;<3B><>笓J<0C><><EFBFBD><<3C><><EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>#<23>8<EFBFBD><38>#<23>8<EFBFBD>H'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Gq<>G<1C><>tr:9<>#<23>8<EFBFBD><38>#<23>8<EFBFBD>ؓh<D893><68><15>N<EFBFBD>t<EFBFBD><74><EFBFBD><EFBFBD>_<EFBFBD><5F>>t<>e<EFBFBD><65>S<EFBFBD><53><EFBFBD><EFBFBD><EFBFBD><EFBFBD>^<5E>\g<><67><EFBFBD>Qe?<3F>vu<><75>o<EFBFBD><6F>;<3B><1A>><3E><>*<2A>wl<77><02>m<>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_24.png
vendored
Normal file
|
After Width: | Height: | Size: 242 B |
3
src-backup/includes/phpqrcode/cache/frame_25.dat
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A
|
||||
<EFBFBD> <10><><EFBFBD>s낋<73>]r<>x<13>Y51mM<>BG
|
||||
<EFBFBD><EFBFBD>*Sx|Ua5Ƶ<35>Z<><5A><EFBFBD>-,<2C>1<EFBFBD><31>H<15>P<EFBFBD>Rj<52><6A>X5<58><35>i<EFBFBD><69><EFBFBD><EFBFBD>G<EFBFBD>>W<><57><EFBFBD>R<EFBFBD><52><EFBFBD>/<2F><>+uT廯<54><0C>ӯ嗴<D3AF>u<EFBFBD><75><0E><>[S<>a<EFBFBD>[kv<6B><76>5<EFBFBD>+5n<1F><><EFBFBD>J<EFBFBD><4A>%+V<>X<EFBFBD>bŊ<62>߬u'<27><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SR<53><52><EFBFBD><EFBFBD>tzZ<7A><5A>+<2B>+V<>X<EFBFBD>bŊ<62>ٟٟٟ<D99F><D99F>+V<>X<EFBFBD>b<EFBFBD><62><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>}Ŋ+V<>X<EFBFBD><58><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>VI<56><49><EFBFBD><EFBFBD><15>+k<>q<>[<5B><>t<1E><>oVZ<56><5A>voNV<4E>w<1C>}<7D>{<7B>r<ýR<C3BD><52>"<22>R<EFBFBD><52>]<1D>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_25.png
vendored
Normal file
|
After Width: | Height: | Size: 242 B |
2
src-backup/includes/phpqrcode/cache/frame_26.dat
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A
|
||||
<EFBFBD> E<><45>օ,t<>7<EFBFBD>7ћU<D19B> E)i7<><37>*~c<><63><EFBFBD><EFBFBD>X<14>EB<45><42><EFBFBD>FC<><43><EFBFBD>6<EFBFBD>:&<26>L,<2C><>Mv.<2E><><EFBFBD><EFBFBD>Kg<4B>ո<EFBFBD>YM<59>><3E><><EFBFBD>><3E>mۚ<6D>?<3F><>v<><76><EFBFBD>mg?<3F><>ұ<EFBFBD><D2B1><EFBFBD><EFBFBD>η<1D>d<EFBFBD><64>C<><16>U<EFBFBD><55>Ik<49><6B><EFBFBD>E\<5C><>Ms<4D>f<>a<EFBFBD>f<>a><3E>[sӈ9쬩ެ8b<38><k<><6B>7<EFBFBD>}<7D><>k<><6B><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3<EFBFBD>0<EFBFBD>3<>0<EFBFBD>3<><33>*r<15><>\<5C>7f<>a<EFBFBD>f<>a<EFBFBD>fr<15><>\<5C>7f<>a<EFBFBD>f<>a<EFBFBD>Y<EFBFBD><59><18><><0C>d<EFBFBD>4<EFBFBD>9k<><6B><EFBFBD><EFBFBD><EFBFBD>y<EFBFBD>X y<>g<EFBFBD><67><EFBFBD>)<1B><>dw<64>n̢<6E>U<EFBFBD>><3E><><EFBFBD>]<5D><>Lg<4C><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Eo<45> w1
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_26.png
vendored
Normal file
|
After Width: | Height: | Size: 244 B |
BIN
src-backup/includes/phpqrcode/cache/frame_27.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_27.png
vendored
Normal file
|
After Width: | Height: | Size: 237 B |
BIN
src-backup/includes/phpqrcode/cache/frame_28.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_28.png
vendored
Normal file
|
After Width: | Height: | Size: 234 B |
2
src-backup/includes/phpqrcode/cache/frame_29.dat
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A<0E> <10>a<EFBFBD> <09><><EFBFBD><EFBFBD>@n7+*<2A><><EFBFBD><EFBFBD>4<EFBFBD>!<21>?<3F>J<EFBFBD><4A><EFBFBD> <09><><EFBFBD>抮<EFBFBD>]<5D><1A><>S<EFBFBD><53>Tf)<29><>s<EFBFBD>I<EFBFBD>"<22>Ȕb<C894><62>0<EFBFBD><30>|<7C>"Luٸ<75>,<2C><>E<18>1\6<>*<2A>uQ<75>?<3F>>a<>υ<EFBFBD><CF85><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD>-r<><72><EFBFBD>n.<2E>ꯋ\<5C>T<EFBFBD><54>:<3A>*)|)<29><>,<2C><>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>x_<78><5F>}:^R<><52>Uoɢ<6F>u<EFBFBD>~<7E>މX`<60>XЏЏЏЏ<D08F>_`<60>X`<60>XЏЏЏ<D08F>_`<60>X`<60>XЏЏЏЏ<D08F>wb<77>X`<60><16><>PU<><55>)D<><44>"c<>{<7B>z<EFBFBD><7A><EFBFBD>3<EFBFBD><33><EFBFBD><}<7D><><EFBFBD>^?b<>m<EFBFBD><6D><EFBFBD>잃<EFBFBD><EC9E83><EFBFBD><EFBFBD><EFBFBD>a<EFBFBD><61><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.<2E>]
|
||||
<EFBFBD>{Q6u<07>T,9
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_29.png
vendored
Normal file
|
After Width: | Height: | Size: 232 B |
1
src-backup/includes/phpqrcode/cache/frame_3.dat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_3.png
vendored
Normal file
|
After Width: | Height: | Size: 147 B |
BIN
src-backup/includes/phpqrcode/cache/frame_30.dat
vendored
Normal file
BIN
src-backup/includes/phpqrcode/cache/frame_30.png
vendored
Normal file
|
After Width: | Height: | Size: 255 B |
1
src-backup/includes/phpqrcode/cache/frame_31.dat
vendored
Normal file
@@ -0,0 +1 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A<0E> <10>a<EFBFBD> <0B><>
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_31.png
vendored
Normal file
|
After Width: | Height: | Size: 260 B |
2
src-backup/includes/phpqrcode/cache/frame_32.dat
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
<EFBFBD> <14><>־<EFBFBD><D6BE><EFBFBD><EFBFBD>.<2E> <20>D<EFBFBD>l<EFBFBD>,<0C><>Mz<4D><7A>6<EFBFBD><10>Ç gcJ<63>D;<3B>'.<2E>A<EFBFBD>Iq<49>މ<EFBFBD>I,Ir<49>Y<EFBFBD><59><EFBFBD><EFBFBD>Fk%<25>D<EFBFBD>O<14>y|ED<45>D<EFBFBD><44>(L<>_Y<5F><59>>*ߚ?a<>O<EFBFBD><15>k<7F>L_<4C><[c<><63><EFBFBD><EFBFBD>><3E>c˘<63>u<1C>LI<4C><49>%<25>#<23>0<EFBFBD>#<23>0<EFBFBD>#<23><>otѢ<74><D1A2><EFBFBD>}<7D><>4<EFBFBD>f<EFBFBD>v_)<29><>E<EFBFBD>p<EFBFBD><1F><>h5R<35><52>8<EFBFBD>8<EFBFBD>1<EFBFBD>#<23>0<EFBFBD>#<23>0<EFBFBD><30><EFBFBD>i<EFBFBD><69>tZ<74>#<23>0<EFBFBD>#<23>0<EFBFBD>#<23>0<EFBFBD><30><EFBFBD>i<EFBFBD><69>tZ<74>#<23>0<EFBFBD>#<23>0<EFBFBD>#<23>0<EFBFBD><30><EFBFBD>i<EFBFBD><69>tZ<74>l<EFBFBD>0<EFBFBD>#<23>0<EFBFBD><08><>9q"<22><>HܜH<DC9C>Q<EFBFBD><51><1B><>"<22><>L5}-<2D><>Y<59><D7BE><EFBFBD>k<EFBFBD>`<60><>><3E>z鸳<><E9B8B3><EFBFBD>4&<26>p<EFBFBD><70>!<21><><EFBFBD>!<21><>`<60>:5
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_32.png
vendored
Normal file
|
After Width: | Height: | Size: 262 B |
14
src-backup/includes/phpqrcode/cache/frame_33.dat
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
x<EFBFBD><EFBFBD><EFBFBD>A<0E> <10>a<EFBFBD><EFBFBD><DEBA><EFBFBD><EFBFBD><EFBFBD>@n7+*L++<2B>柮<12><><05><>bb<62>*LC<4C><12><><EFBFBD><EFBFBD>ck<>H<EFBFBD>r<><72>j<EFBFBD><6A><EFBFBD>J5Y<35>i~0<>_<EFBFBD><5F><EFBFBD><EFBFBD><EFBFBD>T<EFBFBD>T<EFBFBD>}<7D><>e<EFBFBD>><3E><>5<EFBFBD>b_<62>w<EFBFBD>͟?<3F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><0E>\<5C><>Ra<>i+7<><37>W<EFBFBD><57>\<5C><>wLUN<55>L<EFBFBD><4C>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>j<EFBFBD><6A>O<4F><7F>kc<6B><63><EFBFBD><EFBFBD><1D>\˩|%<25>o<<3C><>k<EFBFBD><6B>L<EFBFBD>+<2B>+<2B>v<EFBFBD><76><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><>>}<06><0C>8<><38><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><0C><19>3<EFBFBD>g<EFBFBD><67><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><>3<EFBFBD>g<EFBFBD><67>@<40><><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><><EFBFBD>
|
||||
+<2B><>:R<><52><EFBFBD>X<EFBFBD><58>B<EFBFBD>9<EFBFBD><39>I<EFBFBD>=<>k<EFBFBD><07><>o/Sw<53>ؘ<EFBFBD>ٯ<EFBFBD>`g<><67><EFBFBD><EFBFBD><EFBFBD><1C>r_ٙ<5F>Y<EFBFBD><59>VSY<53><59>zIefnmQoz
|
||||
BIN
src-backup/includes/phpqrcode/cache/frame_33.png
vendored
Normal file
|
After Width: | Height: | Size: 253 B |