Initial commit

This commit is contained in:
2026-01-07 14:09:59 +08:00
commit 8a00aa71d5
939 changed files with 40616 additions and 0 deletions

6
.htaccess Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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>

View 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';
?>

View 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';
?>

View 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';
?>

View 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';
?>

View 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'; ?>

View 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';
?>

View 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';
?>

View 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()]);
}
?>

View 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';
?>

File diff suppressed because it is too large Load Diff

View 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()]);
}
}
?>

View 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';
?>

View 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
View 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>';
}
?>

View 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'; ?>

View 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';
?>

View 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)
]);
?>

View 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"
]);
?>

View 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);
?>

View 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);
?>

View 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
View 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);
?>

View 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;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 KiB

View 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);
}
});
});

View 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
View 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>

View File

@@ -0,0 +1,6 @@
<?php
session_start();
session_destroy();
header('Location: login.php');
exit();
?>

View 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();
?>

View 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);
}
?>

View 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.");
}
}
?>

View 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>

View 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']);
}
?>

View 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)

View 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');

View 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.

View 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

View File

@@ -0,0 +1,2 @@
1.1.4
2010100721

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
<EFBFBD><EFBFBD>
<EFBFBD> E9<45>u<06><>`<60>"PńC<C584>T!0$

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 211 B

View 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>'

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 B

View File

@@ -0,0 +1,3 @@
x<EFBFBD><EFBFBD><EFBFBD>A
<EFBFBD> E<><45><EFBFBD>.<2E>No<4E><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><>

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

View File

@@ -0,0 +1 @@
x<EFBFBD>͒<EFBFBD>

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 225 B

View 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><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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

View File

@@ -0,0 +1,3 @@
x<EFBFBD><EFBFBD><EFBFBD>A
<EFBFBD>0 E]{<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

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

View 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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

View 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><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<>

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

View File

@@ -0,0 +1,3 @@
x<EFBFBD><EFBFBD><EFBFBD>A
<EFBFBD> <10><><EFBFBD>s낋<73>]r<>x<13>Y51mM<>BG
<EFBFBD><EFBFBD>*Sx|Ua<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><62>߬u'<27><07><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>SR<53><52><EFBFBD><EFBFBD>tzZ<7A><5A>+<2B>+V<>X<EFBFBD><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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 B

View 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><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>7 f<>a<EFBFBD>f<>a<EFBFBD>fr<15><>\<5C>7 f<>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><6E>U<EFBFBD>><3E><><EFBFBD>]<5D><>Lg<4C><67><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Eo<45> w1

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 B

View 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>U<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

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 B

View File

@@ -0,0 +1 @@
x<EFBFBD><EFBFBD><EFBFBD><EFBFBD>

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

View File

@@ -0,0 +1 @@
x<EFBFBD><EFBFBD><EFBFBD>A<0E> <10>a<EFBFBD>޺ <0B><>

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

View 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><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><><59><D7BE><EFBFBD>k<EFBFBD>`<60><>><3E>z<><E9B8B3><EFBFBD>4&<26>p<EFBFBD><70>!<21><><EFBFBD>!<21><>`<60>:5

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

View 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>c k<>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

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

Some files were not shown because too many files have changed in this diff Show More