Sindbad~EG File Manager
<?php
require_once 'config/config.php';
$db = new Database();
$conn = $db->getConnection();
$error_message = '';
$access_granted = false;
$code_info = null;
// Handle code verification
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['access_code'])) {
$access_code = sanitizeInput($_POST['access_code']);
// Verify special code
$query = "SELECT * FROM special_codes WHERE code = ? AND is_active = 1
AND (expires_at IS NULL OR expires_at > NOW())
AND (max_usage IS NULL OR usage_count < max_usage)";
$stmt = $conn->prepare($query);
$stmt->execute([$access_code]);
$code_info = $stmt->fetch();
if ($code_info) {
$access_granted = true;
$_SESSION['special_access_code'] = $access_code;
// Update usage count
$update_query = "UPDATE special_codes SET usage_count = usage_count + 1 WHERE id = ?";
$update_stmt = $conn->prepare($update_query);
$update_stmt->execute([$code_info['id']]);
} else {
$error_message = 'Invalid or expired access code. Please check your code and try again.';
}
} elseif (isset($_SESSION['special_access_code'])) {
// Check if session code is still valid
$query = "SELECT * FROM special_codes WHERE code = ? AND is_active = 1
AND (expires_at IS NULL OR expires_at > NOW())";
$stmt = $conn->prepare($query);
$stmt->execute([$_SESSION['special_access_code']]);
$code_info = $stmt->fetch();
if ($code_info) {
$access_granted = true;
} else {
unset($_SESSION['special_access_code']);
}
}
// Get site settings
$query = "SELECT setting_key, setting_value FROM settings WHERE setting_key IN ('site_title', 'site_logo')";
$stmt = $conn->prepare($query);
$stmt->execute();
$settings = [];
while ($row = $stmt->fetch()) {
$settings[$row['setting_key']] = $row['setting_value'];
}
if ($access_granted) {
// Get filter data
$programs_query = "SELECT id, name FROM programs WHERE is_active = 1 ORDER BY name";
$programs_stmt = $conn->prepare($programs_query);
$programs_stmt->execute();
$programs = $programs_stmt->fetchAll();
$districts_query = "SELECT id, name FROM locations WHERE type = 'district' AND is_active = 1 ORDER BY name";
$districts_stmt = $conn->prepare($districts_query);
$districts_stmt->execute();
$districts = $districts_stmt->fetchAll();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Special Attendance Reports - <?php echo $settings['site_title'] ?? SITE_TITLE; ?></title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<style>
.gradient-bg {
background: linear-gradient(135deg, #3B82F6 0%, #F59E0B 50%, #6B7280 100%);
}
.tab-content { display: none; }
.tab-content.active { display: block; }
.tab-button.active { background-color: #3B82F6; color: white; }
</style>
</head>
<body class="bg-gray-50 min-h-screen">
<!-- Header -->
<header class="gradient-bg text-white py-6">
<div class="container mx-auto px-4">
<div class="flex items-center justify-between">
<div class="flex items-center">
<img src="<?php echo $settings['site_logo'] ?? SITE_LOGO; ?>" alt="Logo" class="h-12 w-12 mr-4">
<h1 class="text-2xl font-bold"><?php echo $settings['site_title'] ?? SITE_TITLE; ?></h1>
</div>
<nav class="hidden md:flex space-x-6">
<a href="index.php" class="hover:text-yellow-300 transition duration-300">
<i class="fas fa-home mr-2"></i>Home
</a>
<a href="check_status.php" class="hover:text-yellow-300 transition duration-300">
<i class="fas fa-search mr-2"></i>Check Attendance
</a>
</nav>
</div>
</div>
</header>
<main class="container mx-auto px-4 py-12">
<?php if (!$access_granted): ?>
<!-- Access Code Form -->
<div class="max-w-md mx-auto">
<div class="bg-white rounded-lg shadow-lg p-8">
<div class="text-center mb-6">
<i class="fas fa-lock text-4xl text-gray-400 mb-4"></i>
<h2 class="text-2xl font-bold text-gray-900">Access Required</h2>
<p class="text-gray-600 mt-2">Enter your special access code to view attendance reports</p>
</div>
<form method="POST">
<div class="mb-4">
<label for="access_code" class="block text-sm font-medium text-gray-700 mb-2">
Access Code
</label>
<input type="text"
id="access_code"
name="access_code"
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent text-center text-lg font-mono uppercase"
placeholder="Enter access code"
required>
</div>
<?php if ($error_message): ?>
<div class="bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded-lg mb-4">
<i class="fas fa-exclamation-triangle mr-2"></i>
<?php echo $error_message; ?>
</div>
<?php endif; ?>
<button type="submit" class="w-full bg-blue-600 text-white py-3 px-6 rounded-lg hover:bg-blue-700 transition duration-300 font-semibold">
<i class="fas fa-unlock mr-2"></i>Access Reports
</button>
</form>
</div>
</div>
<?php else: ?>
<!-- Reports Interface -->
<div class="max-w-7xl mx-auto">
<div class="bg-white rounded-lg shadow-lg p-6 mb-8">
<div class="flex items-center justify-between mb-6">
<h2 class="text-2xl font-bold text-gray-900">
<i class="fas fa-chart-bar mr-2 text-blue-600"></i>Special Attendance Reports
</h2>
<div class="flex items-center space-x-4">
<span class="text-sm text-gray-500">Access Code:
<span class="font-mono bg-blue-100 px-2 py-1 rounded"><?php echo $_SESSION['special_access_code']; ?></span>
</span>
<a href="?logout=1" class="text-red-600 hover:text-red-800">
<i class="fas fa-sign-out-alt mr-1"></i>Logout
</a>
</div>
</div>
<!-- Tabs -->
<div class="border-b border-gray-200 mb-6">
<nav class="-mb-px flex space-x-8">
<button class="tab-button active py-2 px-1 border-b-2 border-blue-500 font-medium text-sm" data-tab="summary">
<i class="fas fa-chart-pie mr-2"></i>Summary Reports
</button>
<button class="tab-button py-2 px-1 border-b-2 border-transparent font-medium text-sm text-gray-500 hover:text-gray-700" data-tab="details">
<i class="fas fa-list-ul mr-2"></i>Mini Reports
</button>
<button class="tab-button py-2 px-1 border-b-2 border-transparent font-medium text-sm text-gray-500 hover:text-gray-700" data-tab="extra">
<i class="fas fa-map-marked-alt mr-2"></i>Extra Reports
</button>
<button class="tab-button py-2 px-1 border-b-2 border-transparent font-medium text-sm text-gray-500 hover:text-gray-700" data-tab="districts">
<i class="fas fa-chart-bar mr-2"></i>Districts Report
</button>
</nav>
</div>
<!-- Summary Tab -->
<div id="summary-tab" class="tab-content active">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6 mb-6">
<!-- Filters -->
<div class="bg-gray-50 rounded-lg p-4">
<h3 class="font-semibold text-gray-900 mb-3">Filters</h3>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Program</label>
<select id="program-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Programs</option>
<?php foreach ($programs as $program): ?>
<option value="<?php echo $program['id']; ?>"><?php echo htmlspecialchars($program['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">District</label>
<select id="district-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Districts</option>
<?php foreach ($districts as $district): ?>
<option value="<?php echo $district['id']; ?>"><?php echo htmlspecialchars($district['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Officer Type</label>
<select id="officer-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Officer Types</option>
<option value="Deacon">Deacon</option>
<option value="Deaconess">Deaconess</option>
<option value="Elder">Elder</option>
<option value="Pastor">Pastor</option>
<option value="Apostle">Apostle</option>
<option value="Prophet">Prophet</option>
<option value="Evangelist">Evangelist</option>
<option value="Other">Other</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">From Date</label>
<input type="date" id="from-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">To Date</label>
<input type="date" id="to-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<button onclick="loadSummaryData()" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700">
<i class="fas fa-filter mr-2"></i>Apply Filters
</button>
</div>
</div>
<!-- Summary Stats -->
<div class="lg:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-4">
<div class="bg-blue-50 rounded-lg p-4">
<div class="flex items-center">
<div class="w-12 h-12 bg-blue-100 rounded-full flex items-center justify-center mr-4">
<i class="fas fa-users text-blue-600 text-xl"></i>
</div>
<div>
<h4 class="text-lg font-semibold text-gray-900">Total Attendees</h4>
<p class="text-2xl font-bold text-blue-600" id="total-attendees">0</p>
</div>
</div>
</div>
<div class="bg-green-50 rounded-lg p-4">
<div class="flex items-center">
<div class="w-12 h-12 bg-green-100 rounded-full flex items-center justify-center mr-4">
<i class="fas fa-calendar-check text-green-600 text-xl"></i>
</div>
<div>
<h4 class="text-lg font-semibold text-gray-900">Programs</h4>
<p class="text-2xl font-bold text-green-600" id="total-programs">0</p>
</div>
</div>
</div>
<div class="bg-purple-50 rounded-lg p-4">
<div class="flex items-center">
<div class="w-12 h-12 bg-purple-100 rounded-full flex items-center justify-center mr-4">
<i class="fas fa-map-marker-alt text-purple-600 text-xl"></i>
</div>
<div>
<h4 class="text-lg font-semibold text-gray-900">Districts</h4>
<p class="text-2xl font-bold text-purple-600" id="total-districts">0</p>
</div>
</div>
</div>
<div class="bg-orange-50 rounded-lg p-4">
<div class="flex items-center">
<div class="w-12 h-12 bg-orange-100 rounded-full flex items-center justify-center mr-4">
<i class="fas fa-user-tie text-orange-600 text-xl"></i>
</div>
<div>
<h4 class="text-lg font-semibold text-gray-900">Officers</h4>
<p class="text-2xl font-bold text-orange-600" id="total-officers">0</p>
</div>
</div>
</div>
</div>
</div>
<!-- Export Buttons -->
<div class="mb-6">
<div class="flex flex-wrap gap-2">
<button onclick="exportData('csv')" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
<i class="fas fa-file-csv mr-2"></i>Export CSV
</button>
<button onclick="exportData('excel')" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700">
<i class="fas fa-file-excel mr-2"></i>Export Excel
</button>
<button onclick="exportData('pdf')" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700">
<i class="fas fa-file-pdf mr-2"></i>Export PDF
</button>
</div>
</div>
<!-- Summary Data Table -->
<div id="summary-results" class="bg-white rounded-lg border">
<div class="p-6 text-center text-gray-500">
<i class="fas fa-chart-bar text-4xl mb-4"></i>
<p>Click "Apply Filters" to load summary data</p>
</div>
</div>
</div>
<!-- Details Tab -->
<div id="details-tab" class="tab-content">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-6">
<!-- Detail Filters -->
<div class="bg-gray-50 rounded-lg p-4">
<h3 class="font-semibold text-gray-900 mb-3">Filters</h3>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Program</label>
<select id="detail-program-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Programs</option>
<?php foreach ($programs as $program): ?>
<option value="<?php echo $program['id']; ?>"><?php echo htmlspecialchars($program['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">District</label>
<select id="detail-district-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Districts</option>
<?php foreach ($districts as $district): ?>
<option value="<?php echo $district['id']; ?>"><?php echo htmlspecialchars($district['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Officer Type</label>
<select id="detail-officer-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Officer Types</option>
<option value="Deacon">Deacon</option>
<option value="Deaconess">Deaconess</option>
<option value="Elder">Elder</option>
<option value="Pastor">Pastor</option>
<option value="Apostle">Apostle</option>
<option value="Prophet">Prophet</option>
<option value="Evangelist">Evangelist</option>
<option value="Other">Other</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">From Date</label>
<input type="date" id="detail-from-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">To Date</label>
<input type="date" id="detail-to-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<button onclick="loadDetailData()" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700">
<i class="fas fa-filter mr-2"></i>Apply Filters
</button>
</div>
</div>
<!-- Detail Stats -->
<div class="lg:col-span-3">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div class="bg-indigo-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Total Records</h4>
<p class="text-2xl font-bold text-indigo-600" id="detail-total-records">0</p>
</div>
<div class="bg-teal-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Unique Attendees</h4>
<p class="text-2xl font-bold text-teal-600" id="detail-unique-attendees">0</p>
</div>
<div class="bg-pink-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Locations</h4>
<p class="text-2xl font-bold text-pink-600" id="detail-locations">0</p>
</div>
</div>
<!-- Detail Export Buttons -->
<div class="mb-4">
<div class="flex flex-wrap gap-2">
<button onclick="exportDetailData('csv')" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
<i class="fas fa-file-csv mr-2"></i>Export Details CSV
</button>
<button onclick="exportDetailData('excel')" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700">
<i class="fas fa-file-excel mr-2"></i>Export Details Excel
</button>
<button onclick="exportDetailData('pdf')" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700">
<i class="fas fa-file-pdf mr-2"></i>Export Details PDF
</button>
</div>
</div>
</div>
</div>
<!-- Detail Data Table -->
<div id="detail-results" class="bg-white rounded-lg border">
<div class="p-6 text-center text-gray-500">
<i class="fas fa-list-ul text-4xl mb-4"></i>
<p>Click "Apply Filters" to load detailed attendance data</p>
</div>
</div>
</div>
<!-- Extra Reports Tab -->
<div id="extra-tab" class="tab-content">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-6">
<!-- Extra Filters -->
<div class="bg-gray-50 rounded-lg p-4">
<h3 class="font-semibold text-gray-900 mb-3">Filters & Grouping</h3>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Program</label>
<select id="extra-program-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Programs</option>
<?php foreach ($programs as $program): ?>
<option value="<?php echo $program['id']; ?>"><?php echo htmlspecialchars($program['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">District</label>
<select id="extra-district-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Districts</option>
<?php foreach ($districts as $district): ?>
<option value="<?php echo $district['id']; ?>"><?php echo htmlspecialchars($district['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Officer Type</label>
<select id="extra-officer-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Officer Types</option>
<option value="Deacon">Deacon</option>
<option value="Deaconess">Deaconess</option>
<option value="Elder">Elder</option>
<option value="Pastor">Pastor</option>
<option value="Apostle">Apostle</option>
<option value="Prophet">Prophet</option>
<option value="Evangelist">Evangelist</option>
<option value="Other">Other</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Group By</label>
<select id="extra-groupby-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="district">Group by District</option>
<option value="officer_type">Group by Officer Type</option>
<option value="gps_location">Group by GPS Location</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">From Date</label>
<input type="date" id="extra-from-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">To Date</label>
<input type="date" id="extra-to-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<button onclick="loadExtraData()" class="w-full bg-blue-600 text-white py-2 px-4 rounded-lg hover:bg-blue-700">
<i class="fas fa-filter mr-2"></i>Apply Filters
</button>
</div>
</div>
<!-- Extra Stats -->
<div class="lg:col-span-3">
<div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6">
<div class="bg-indigo-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Total Records</h4>
<p class="text-2xl font-bold text-indigo-600" id="extra-total-records">0</p>
</div>
<div class="bg-teal-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Unique Attendees</h4>
<p class="text-2xl font-bold text-teal-600" id="extra-unique-attendees">0</p>
</div>
<div class="bg-pink-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">GPS Records</h4>
<p class="text-2xl font-bold text-pink-600" id="extra-gps-records">0</p>
</div>
<div class="bg-amber-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Groups</h4>
<p class="text-2xl font-bold text-amber-600" id="extra-groups">0</p>
</div>
</div>
<!-- Extra Export Buttons -->
<div class="mb-4">
<div class="flex flex-wrap gap-2">
<button onclick="exportExtraData('csv')" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
<i class="fas fa-file-csv mr-2"></i>Export Extra CSV
</button>
<button onclick="exportExtraData('excel')" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700">
<i class="fas fa-file-excel mr-2"></i>Export Extra Excel
</button>
<button onclick="exportExtraData('pdf')" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700">
<i class="fas fa-file-pdf mr-2"></i>Export Extra PDF
</button>
</div>
</div>
</div>
</div>
<!-- Extra Data Table -->
<div id="extra-results" class="bg-white rounded-lg border">
<div class="p-6 text-center text-gray-500">
<i class="fas fa-map-marked-alt text-4xl mb-4"></i>
<p>Click "Apply Filters" to load extra attendance data with GPS information</p>
</div>
</div>
</div>
<!-- Districts Report Tab -->
<div id="districts-tab" class="tab-content">
<div class="grid grid-cols-1 lg:grid-cols-4 gap-6 mb-6">
<!-- Districts Filters -->
<div class="bg-gray-50 rounded-lg p-4">
<h3 class="font-semibold text-gray-900 mb-3">Filters & Grouping</h3>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Program</label>
<select id="districts-program-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Programs</option>
<?php foreach ($programs as $program): ?>
<option value="<?php echo $program['id']; ?>"><?php echo htmlspecialchars($program['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">District</label>
<select id="districts-district-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Districts</option>
<?php foreach ($districts as $district): ?>
<option value="<?php echo $district['id']; ?>"><?php echo htmlspecialchars($district['name']); ?></option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Officer Type</label>
<select id="districts-officer-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="">All Officer Types</option>
<option value="Deacon">Deacon</option>
<option value="Deaconess">Deaconess</option>
<option value="Elder">Elder</option>
<option value="Pastor">Pastor</option>
<option value="Apostle">Apostle</option>
<option value="Prophet">Prophet</option>
<option value="Evangelist">Evangelist</option>
<option value="Other">Other</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">Group By</label>
<select id="districts-groupby-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
<option value="district">Group by District</option>
<option value="officer_type">Group by Officer Type</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">From Date</label>
<input type="date" id="districts-from-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-1">To Date</label>
<input type="date" id="districts-to-date-filter" class="w-full px-3 py-2 border border-gray-300 rounded-lg">
</div>
<button onclick="loadDistrictsData()" class="w-full bg-orange-600 text-white py-2 px-4 rounded-lg hover:bg-orange-700">
<i class="fas fa-chart-bar mr-2"></i>Generate Chart
</button>
</div>
</div>
<!-- Districts Stats -->
<div class="lg:col-span-3">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
<div class="bg-orange-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Total Records</h4>
<p class="text-2xl font-bold text-orange-600" id="districts-total-records">0</p>
</div>
<div class="bg-cyan-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Unique Groups</h4>
<p class="text-2xl font-bold text-cyan-600" id="districts-unique-groups">0</p>
</div>
<div class="bg-emerald-50 rounded-lg p-4 text-center">
<h4 class="text-sm font-medium text-gray-700">Average per Group</h4>
<p class="text-2xl font-bold text-emerald-600" id="districts-average-per-group">0</p>
</div>
</div>
<!-- Districts Export Buttons -->
<div class="mb-4">
<div class="flex flex-wrap gap-2">
<button onclick="exportDistrictsData('csv')" class="bg-blue-600 text-white px-4 py-2 rounded-lg hover:bg-blue-700">
<i class="fas fa-file-csv mr-2"></i>Export CSV
</button>
<button onclick="exportDistrictsData('excel')" class="bg-green-600 text-white px-4 py-2 rounded-lg hover:bg-green-700">
<i class="fas fa-file-excel mr-2"></i>Export Excel
</button>
<button onclick="exportDistrictsData('pdf')" class="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700">
<i class="fas fa-file-pdf mr-2"></i>Export PDF
</button>
</div>
</div>
</div>
</div>
<!-- Districts Chart Container -->
<div id="districts-results" class="bg-white rounded-lg border">
<div class="p-6 text-center text-gray-500">
<i class="fas fa-chart-bar text-4xl mb-4"></i>
<p>Click "Generate Chart" to load districts attendance chart</p>
</div>
</div>
</div>
</div>
</div>
<?php endif; ?>
</main>
<script>
// Tab switching
document.querySelectorAll('.tab-button').forEach(button => {
button.addEventListener('click', function() {
const tabName = this.dataset.tab;
// Update button states
document.querySelectorAll('.tab-button').forEach(btn => {
btn.classList.remove('active', 'border-blue-500', 'text-blue-600');
btn.classList.add('border-transparent', 'text-gray-500');
});
this.classList.add('active', 'border-blue-500', 'text-blue-600');
this.classList.remove('border-transparent', 'text-gray-500');
// Update tab content
document.querySelectorAll('.tab-content').forEach(content => {
content.classList.remove('active');
});
document.getElementById(tabName + '-tab').classList.add('active');
});
});
// Load summary data
function loadSummaryData() {
const program = document.getElementById('program-filter').value;
const district = document.getElementById('district-filter').value;
const officer_type = document.getElementById('officer-filter').value;
const from_date = document.getElementById('from-date-filter').value;
const to_date = document.getElementById('to-date-filter').value;
fetch('api/special_reports_summary.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
program: program,
district: district,
officer_type: officer_type,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateSummaryStats(data.stats);
updateSummaryTable(data.data);
} else {
alert('Error loading data: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error loading data');
});
}
// Load detail data
function loadDetailData() {
const program = document.getElementById('detail-program-filter').value;
const district = document.getElementById('detail-district-filter').value;
const officer_type = document.getElementById('detail-officer-filter').value;
const from_date = document.getElementById('detail-from-date-filter').value;
const to_date = document.getElementById('detail-to-date-filter').value;
fetch('api/special_reports_details.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
program: program,
district: district,
officer_type: officer_type,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateDetailStats(data.stats);
updateDetailTable(data.data);
} else {
alert('Error loading data: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error loading data');
});
}
// Load extra data
function loadExtraData() {
const program = document.getElementById('extra-program-filter').value;
const district = document.getElementById('extra-district-filter').value;
const officer_type = document.getElementById('extra-officer-filter').value;
const group_by = document.getElementById('extra-groupby-filter').value;
const from_date = document.getElementById('extra-from-date-filter').value;
const to_date = document.getElementById('extra-to-date-filter').value;
fetch('api/special_reports_extra.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
program: program,
district: district,
officer_type: officer_type,
group_by: group_by,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateExtraStats(data.stats);
updateExtraTable(data.data, data.group_by);
} else {
alert('Error loading data: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error loading data');
});
}
function updateSummaryStats(stats) {
document.getElementById('total-attendees').textContent = stats.total_attendees || 0;
document.getElementById('total-programs').textContent = stats.total_programs || 0;
document.getElementById('total-districts').textContent = stats.total_districts || 0;
document.getElementById('total-officers').textContent = stats.total_officers || 0;
}
function updateDetailStats(stats) {
document.getElementById('detail-total-records').textContent = stats.total_records || 0;
document.getElementById('detail-unique-attendees').textContent = stats.unique_attendees || 0;
document.getElementById('detail-locations').textContent = stats.locations || 0;
}
function updateExtraStats(stats) {
document.getElementById('extra-total-records').textContent = stats.total_records || 0;
document.getElementById('extra-unique-attendees').textContent = stats.unique_attendees || 0;
document.getElementById('extra-gps-records').textContent = stats.gps_records || 0;
document.getElementById('extra-groups').textContent = stats.groups || 0;
}
function updateSummaryTable(data) {
const container = document.getElementById('summary-results');
if (!data || data.length === 0) {
container.innerHTML = `
<div class="p-6 text-center text-gray-500">
<i class="fas fa-info-circle text-4xl mb-4"></i>
<p>No attendance records found for the selected filters</p>
</div>
`;
return;
}
let tableHTML = `
<div class="mb-4 px-6 py-3 bg-blue-50 border-l-4 border-blue-400">
<div class="flex items-center">
<i class="fas fa-users text-blue-600 mr-2"></i>
<span class="text-blue-800 font-semibold">Total Members: ${data.length}</span>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Phone</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Officer Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Program</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">District</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Assembly</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
`;
data.forEach(record => {
const date = new Date(record.submitted_at).toLocaleDateString();
tableHTML += `
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${record.full_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.email || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.telephone || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
${record.officer_type ? `<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">${record.officer_type}</span>` : '-'}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.program_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.district_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.assembly_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${date}</td>
</tr>
`;
});
tableHTML += `
</tbody>
</table>
</div>
`;
container.innerHTML = tableHTML;
}
function updateDetailTable(data) {
const container = document.getElementById('detail-results');
if (!data || data.length === 0) {
container.innerHTML = `
<div class="p-6 text-center text-gray-500">
<i class="fas fa-info-circle text-4xl mb-4"></i>
<p>No attendance records found for the selected filters</p>
</div>
`;
return;
}
let tableHTML = `
<div class="mb-4 px-6 py-3 bg-green-50 border-l-4 border-green-400">
<div class="flex items-center">
<i class="fas fa-list-ul text-green-600 mr-2"></i>
<span class="text-green-800 font-semibold">Total Records: ${data.length}</span>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Phone</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Officer Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Program</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">District</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Assembly</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Tracking Code</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
`;
data.forEach(record => {
const date = new Date(record.submitted_at).toLocaleDateString();
tableHTML += `
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${record.full_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.email || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.telephone || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
${record.officer_type ? `<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">${record.officer_type}</span>` : '-'}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.program_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.district_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.assembly_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${date}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 font-mono">${record.tracking_code || '-'}</td>
</tr>
`;
});
tableHTML += `
</tbody>
</table>
</div>
`;
container.innerHTML = tableHTML;
}
function updateExtraTable(data, groupBy) {
const container = document.getElementById('extra-results');
if (!data || data.length === 0) {
container.innerHTML = `
<div class="p-6 text-center text-gray-500">
<i class="fas fa-info-circle text-4xl mb-4"></i>
<p>No attendance records found for the selected filters</p>
</div>
`;
return;
}
let tableHTML = `
<div class="mb-4 px-6 py-3 bg-purple-50 border-l-4 border-purple-400">
<div class="flex items-center">
<i class="fas fa-map-marked-alt text-purple-600 mr-2"></i>
<span class="text-purple-800 font-semibold">Total Records: ${data.length}</span>
</div>
</div>
<div class="overflow-x-auto">
<table class="min-w-full divide-y divide-gray-200">
<thead class="bg-gray-50">
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Name</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Email</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Phone</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Officer Type</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Program</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">District</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Assembly</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">GPS Coordinates</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">GPS Accuracy</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Location Address</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
`;
let currentGroup = null;
let groupCounts = {};
// First pass: count records per group
data.forEach(record => {
const groupValue = record.group_value || 'Not Specified';
groupCounts[groupValue] = (groupCounts[groupValue] || 0) + 1;
});
data.forEach(record => {
const date = new Date(record.submitted_at).toLocaleDateString();
// Add group header if grouping is enabled and group changes
if (record.group_value !== currentGroup) {
currentGroup = record.group_value;
let groupLabel = '';
const groupCount = groupCounts[currentGroup || 'Not Specified'];
switch(groupBy) {
case 'officer_type':
groupLabel = `Officer Type: ${currentGroup || 'Not Specified'}`;
break;
case 'gps_location':
groupLabel = `GPS Location: ${currentGroup || 'No GPS Data'}`;
break;
default:
groupLabel = `District: ${currentGroup || 'Not Specified'}`;
break;
}
tableHTML += `
<tr class="bg-blue-50">
<td colspan="11" class="px-6 py-3 text-sm font-semibold text-blue-900">
<div class="flex items-center justify-between">
<div>
<i class="fas fa-layer-group mr-2"></i>${groupLabel}
</div>
<div class="bg-blue-200 px-3 py-1 rounded-full text-xs font-bold text-blue-800">
${groupCount} record${groupCount !== 1 ? 's' : ''}
</div>
</div>
</td>
</tr>
`;
}
tableHTML += `
<tr class="hover:bg-gray-50">
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">${record.full_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.email || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.telephone || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
${record.officer_type ? `<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">${record.officer_type}</span>` : '-'}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.program_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.district_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.assembly_name || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
${record.has_gps ? `<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800"><i class="fas fa-map-marker-alt mr-1"></i>${record.gps_coordinates}</span>` : '<span class="text-gray-400">No GPS</span>'}
</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${record.accuracy_formatted || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500 max-w-xs truncate" title="${record.location_address || ''}">${record.location_address || '-'}</td>
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">${date}</td>
</tr>
`;
});
tableHTML += `
</tbody>
</table>
</div>
`;
container.innerHTML = tableHTML;
}
// Export functions
function exportData(format) {
const program = document.getElementById('program-filter').value;
const district = document.getElementById('district-filter').value;
const officer_type = document.getElementById('officer-filter').value;
const from_date = document.getElementById('from-date-filter').value;
const to_date = document.getElementById('to-date-filter').value;
const params = new URLSearchParams({
format: format,
type: 'summary',
program: program,
district: district,
officer_type: officer_type,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
});
window.open('api/export_special_reports.php?' + params.toString(), '_blank');
}
function exportDetailData(format) {
const program = document.getElementById('detail-program-filter').value;
const district = document.getElementById('detail-district-filter').value;
const officer_type = document.getElementById('detail-officer-filter').value;
const from_date = document.getElementById('detail-from-date-filter').value;
const to_date = document.getElementById('detail-to-date-filter').value;
const params = new URLSearchParams({
format: format,
type: 'details',
program: program,
district: district,
officer_type: officer_type,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
});
window.open('api/export_special_reports.php?' + params.toString(), '_blank');
}
function exportExtraData(format) {
const program = document.getElementById('extra-program-filter').value;
const district = document.getElementById('extra-district-filter').value;
const officer_type = document.getElementById('extra-officer-filter').value;
const group_by = document.getElementById('extra-groupby-filter').value;
const from_date = document.getElementById('extra-from-date-filter').value;
const to_date = document.getElementById('extra-to-date-filter').value;
const params = new URLSearchParams({
format: format,
type: 'extra',
program: program,
district: district,
officer_type: officer_type,
group_by: group_by,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
});
window.open('api/export_special_reports.php?' + params.toString(), '_blank');
}
// Load districts data
function loadDistrictsData() {
const program = document.getElementById('districts-program-filter').value;
const district = document.getElementById('districts-district-filter').value;
const officer_type = document.getElementById('districts-officer-filter').value;
const group_by = document.getElementById('districts-groupby-filter').value;
const from_date = document.getElementById('districts-from-date-filter').value;
const to_date = document.getElementById('districts-to-date-filter').value;
fetch('api/special_reports_districts.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
program: program,
district: district,
officer_type: officer_type,
group_by: group_by,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
updateDistrictsStats(data.stats);
updateDistrictsChart(data.chart_data, data.group_by);
} else {
alert('Error loading data: ' + data.message);
}
})
.catch(error => {
console.error('Error:', error);
alert('Error loading data');
});
}
function updateDistrictsStats(stats) {
document.getElementById('districts-total-records').textContent = stats.total_records || 0;
document.getElementById('districts-unique-groups').textContent = stats.unique_groups || 0;
document.getElementById('districts-average-per-group').textContent = stats.average_per_group || 0;
}
function updateDistrictsChart(chartData, groupBy) {
const container = document.getElementById('districts-results');
if (!chartData || chartData.length === 0) {
container.innerHTML = `
<div class="p-6 text-center text-gray-500">
<i class="fas fa-info-circle text-4xl mb-4"></i>
<p>No attendance data found for the selected filters</p>
</div>
`;
return;
}
// Calculate total and percentages
const totalRecords = chartData.reduce((sum, item) => sum + parseInt(item.count), 0);
// Create chart container with side-by-side layout
let chartHTML = `
<div class="p-6">
<div class="mb-6">
<h3 class="text-lg font-semibold text-gray-900">
Attendance Distribution by ${groupBy === 'officer_type' ? 'Officer Type' : 'District'}
</h3>
<p class="text-sm text-gray-600">Total records: ${totalRecords}</p>
</div>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Bar Chart -->
<div class="lg:col-span-1">
<h4 class="text-md font-medium text-gray-800 mb-4">Bar Chart</h4>
<div class="space-y-4">
`;
// Find max count for scaling
const maxCount = Math.max(...chartData.map(item => parseInt(item.count)));
chartData.forEach(item => {
const barPercentage = maxCount > 0 ? (parseInt(item.count) / maxCount) * 100 : 0;
const actualPercentage = totalRecords > 0 ? ((parseInt(item.count) / totalRecords) * 100).toFixed(1) : 0;
const barColor = getBarColor(item.group_label, groupBy);
chartHTML += `
<div class="bg-gray-50 rounded-lg p-4">
<div class="flex items-center justify-between mb-2">
<div class="font-medium text-gray-900">${item.group_label || 'Not Specified'}</div>
<div class="text-lg font-bold ${barColor.textClass}">${item.count} (${actualPercentage}%)</div>
</div>
<div class="w-full bg-gray-200 rounded-full h-6">
<div class="${barColor.bgClass} h-6 rounded-full flex items-center justify-end pr-2"
style="width: ${Math.max(barPercentage, 5)}%">
<span class="text-xs font-medium text-white">${item.count}</span>
</div>
</div>
</div>
`;
});
chartHTML += `
</div>
</div>
<!-- Pie Chart -->
<div class="lg:col-span-2">
<h4 class="text-md font-medium text-gray-800 mb-4">Pie Chart</h4>
<div class="flex flex-col items-center">
<div class="relative w-64 h-64 mb-4">
<svg viewBox="0 0 200 200" class="w-full h-full transform -rotate-90">
`;
// Generate pie chart segments
let currentAngle = 0;
chartData.forEach((item, index) => {
const percentage = totalRecords > 0 ? (parseInt(item.count) / totalRecords) * 100 : 0;
const angle = (percentage / 100) * 360;
const barColor = getBarColor(item.group_label, groupBy);
if (angle > 0) {
const startAngle = currentAngle;
const endAngle = currentAngle + angle;
const x1 = 100 + 80 * Math.cos((startAngle * Math.PI) / 180);
const y1 = 100 + 80 * Math.sin((startAngle * Math.PI) / 180);
const x2 = 100 + 80 * Math.cos((endAngle * Math.PI) / 180);
const y2 = 100 + 80 * Math.sin((endAngle * Math.PI) / 180);
const largeArcFlag = angle > 180 ? 1 : 0;
const pathData = `M 100 100 L ${x1} ${y1} A 80 80 0 ${largeArcFlag} 1 ${x2} ${y2} Z`;
// Get color class for SVG
const svgColor = getSVGColor(barColor.bgClass);
chartHTML += `<path d="${pathData}" fill="${svgColor}" stroke="white" stroke-width="2"/>`;
currentAngle += angle;
}
});
chartHTML += `
</svg>
</div>
<!-- Pie Chart Legend -->
<div class="space-y-2 w-full">
`;
chartData.forEach(item => {
const percentage = totalRecords > 0 ? ((parseInt(item.count) / totalRecords) * 100).toFixed(1) : 0;
const barColor = getBarColor(item.group_label, groupBy);
chartHTML += `
<div class="flex items-center justify-between p-2 bg-gray-50 rounded">
<div class="flex items-center">
<div class="w-4 h-4 rounded ${barColor.bgClass} mr-2"></div>
<span class="text-sm font-medium">${item.group_label || 'Not Specified'}</span>
</div>
<span class="text-sm font-bold ${barColor.textClass}">${item.count} (${percentage}%)</span>
</div>
`;
});
chartHTML += `
</div>
</div>
</div>
</div>
</div>
`;
container.innerHTML = chartHTML;
}
function getBarColor(label, groupBy) {
const colors = {
district: [
{ bgClass: 'bg-blue-500', textClass: 'text-blue-600' },
{ bgClass: 'bg-green-500', textClass: 'text-green-600' },
{ bgClass: 'bg-purple-500', textClass: 'text-purple-600' },
{ bgClass: 'bg-orange-500', textClass: 'text-orange-600' },
{ bgClass: 'bg-red-500', textClass: 'text-red-600' },
{ bgClass: 'bg-indigo-500', textClass: 'text-indigo-600' },
{ bgClass: 'bg-pink-500', textClass: 'text-pink-600' },
{ bgClass: 'bg-teal-500', textClass: 'text-teal-600' }
],
officer_type: {
'Pastor': { bgClass: 'bg-purple-500', textClass: 'text-purple-600' },
'Elder': { bgClass: 'bg-blue-500', textClass: 'text-blue-600' },
'Deacon': { bgClass: 'bg-green-500', textClass: 'text-green-600' },
'Deaconess': { bgClass: 'bg-pink-500', textClass: 'text-pink-600' },
'Apostle': { bgClass: 'bg-indigo-500', textClass: 'text-indigo-600' },
'Prophet': { bgClass: 'bg-yellow-500', textClass: 'text-yellow-600' },
'Evangelist': { bgClass: 'bg-orange-500', textClass: 'text-orange-600' },
'Other': { bgClass: 'bg-gray-500', textClass: 'text-gray-600' }
}
};
if (groupBy === 'officer_type') {
return colors.officer_type[label] || colors.officer_type['Other'];
} else {
// Use hash of label to get consistent color for districts
let hash = 0;
for (let i = 0; i < label.length; i++) {
hash = label.charCodeAt(i) + ((hash << 5) - hash);
}
const colorIndex = Math.abs(hash) % colors.district.length;
return colors.district[colorIndex];
}
}
function getSVGColor(bgClass) {
const colorMap = {
'bg-blue-500': '#3b82f6',
'bg-green-500': '#10b981',
'bg-purple-500': '#8b5cf6',
'bg-orange-500': '#f97316',
'bg-red-500': '#ef4444',
'bg-indigo-500': '#6366f1',
'bg-pink-500': '#ec4899',
'bg-teal-500': '#14b8a6',
'bg-yellow-500': '#eab308',
'bg-gray-500': '#6b7280'
};
return colorMap[bgClass] || '#6b7280';
}
function exportDistrictsData(format) {
const program = document.getElementById('districts-program-filter').value;
const district = document.getElementById('districts-district-filter').value;
const officer_type = document.getElementById('districts-officer-filter').value;
const group_by = document.getElementById('districts-groupby-filter').value;
const from_date = document.getElementById('districts-from-date-filter').value;
const to_date = document.getElementById('districts-to-date-filter').value;
const params = new URLSearchParams({
format: format,
type: 'districts',
program: program,
district: district,
officer_type: officer_type,
group_by: group_by,
from_date: from_date,
to_date: to_date,
access_code: '<?php echo $_SESSION['special_access_code'] ?? ''; ?>'
});
window.open('api/export_special_reports.php?' + params.toString(), '_blank');
}
// Auto-uppercase access code input
const accessCodeInput = document.getElementById('access_code');
if (accessCodeInput) {
accessCodeInput.addEventListener('input', function(e) {
e.target.value = e.target.value.toUpperCase();
});
}
</script>
<?php if (isset($_GET['logout'])): ?>
<script>
<?php unset($_SESSION['special_access_code']); ?>
window.location.href = 'special_attendance_reports.php';
</script>
<?php endif; ?>
</body>
</html>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists