Sindbad~EG File Manager
<?php
session_start();
require_once '../config/database.php';
require_once '../includes/functions.php';
// Check if user is logged in and is admin
if (!isLoggedIn() || !hasRole(['superuser', 'area_admin', 'district_admin', 'assembly_admin'])) {
header('Location: ../login.php');
exit();
}
$db = new CopMadinaDB();
$conn = $db->getConnection();
$user_role = $_SESSION['user_role'];
$user_id = $_SESSION['user_id'];
$message = '';
$messageType = '';
// Handle admin check-out functionality
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'admin_checkout') {
$registrationCode = trim($_POST['registration_code']);
$registrationType = $_POST['registration_type'];
if (empty($registrationCode)) {
$message = 'Registration code is required for check-out.';
$messageType = 'error';
} else {
if ($registrationType === 'member') {
// Check member registrations
$stmt = $conn->prepare("
SELECT er.*, e.title as event_title, u.first_name, u.last_name
FROM event_registrations er
JOIN events e ON er.event_id = e.id
JOIN users u ON er.user_id = u.id
WHERE er.registration_code = ? AND e.status = 'published' AND er.checked_in_at IS NOT NULL AND er.checked_out_at IS NULL
");
$stmt->execute([$registrationCode]);
$registration = $stmt->fetch();
if ($registration) {
// Update check-out time
$updateStmt = $conn->prepare("UPDATE event_registrations SET checked_out_at = NOW(), updated_at = NOW() WHERE registration_code = ?");
$result = $updateStmt->execute([$registrationCode]);
if ($result) {
// Calculate duration
$durationStmt = $conn->prepare("SELECT TIMESTAMPDIFF(MINUTE, checked_in_at, NOW()) as duration_minutes FROM event_registrations WHERE registration_code = ?");
$durationStmt->execute([$registrationCode]);
$duration = $durationStmt->fetch()['duration_minutes'];
// Log attendance
$logStmt = $conn->prepare("INSERT INTO attendance_logs (event_id, user_id, registration_code, registration_type, action, action_time, duration_minutes, ip_address, user_agent) VALUES (?, ?, ?, 'member', 'check_out', NOW(), ?, ?, ?)");
$logStmt->execute([
$registration['event_id'],
$registration['user_id'],
$registrationCode,
$duration,
$_SERVER['REMOTE_ADDR'] ?? null,
$_SERVER['HTTP_USER_AGENT'] ?? null
]);
$hours = floor($duration / 60);
$minutes = $duration % 60;
$durationText = ($hours > 0 ? $hours . 'h ' : '') . $minutes . 'm';
$message = "Successfully checked out {$registration['first_name']} {$registration['last_name']} from '{$registration['event_title']}'. Duration: {$durationText}";
$messageType = 'success';
// Log the admin action
logActivity($user_id, 'admin_checkout', "Admin checked out member: {$registration['first_name']} {$registration['last_name']} (Code: {$registrationCode})");
} else {
$message = 'Failed to check out member. Please try again.';
$messageType = 'error';
}
} else {
$message = 'Member registration not found or not currently checked in.';
$messageType = 'error';
}
} else {
// Check non-member registrations
$stmt = $conn->prepare("
SELECT nr.*, e.title as event_title
FROM nonmember_registrations nr
JOIN events e ON nr.event_id = e.id
WHERE nr.registration_code = ? AND e.status = 'published' AND nr.checked_in_at IS NOT NULL AND nr.checked_out_at IS NULL
");
$stmt->execute([$registrationCode]);
$registration = $stmt->fetch();
if ($registration) {
// Update check-out time
$updateStmt = $conn->prepare("UPDATE nonmember_registrations SET checked_out_at = NOW(), updated_at = NOW() WHERE registration_code = ?");
$result = $updateStmt->execute([$registrationCode]);
if ($result) {
// Calculate duration
$durationStmt = $conn->prepare("SELECT TIMESTAMPDIFF(MINUTE, checked_in_at, NOW()) as duration_minutes FROM nonmember_registrations WHERE registration_code = ?");
$durationStmt->execute([$registrationCode]);
$duration = $durationStmt->fetch()['duration_minutes'];
// Log attendance
$logStmt = $conn->prepare("INSERT INTO attendance_logs (event_id, user_id, registration_code, registration_type, action, action_time, duration_minutes, ip_address, user_agent) VALUES (?, ?, ?, 'nonmember', 'check_out', NOW(), ?, ?, ?)");
$logStmt->execute([
$registration['event_id'],
null, // No user_id for non-members
$registrationCode,
$duration,
$_SERVER['REMOTE_ADDR'] ?? null,
$_SERVER['HTTP_USER_AGENT'] ?? null
]);
$hours = floor($duration / 60);
$minutes = $duration % 60;
$durationText = ($hours > 0 ? $hours . 'h ' : '') . $minutes . 'm';
$message = "Successfully checked out {$registration['first_name']} {$registration['last_name']} from '{$registration['event_title']}'. Duration: {$durationText}";
$messageType = 'success';
// Log the admin action
logActivity($user_id, 'admin_checkout', "Admin checked out non-member: {$registration['first_name']} {$registration['last_name']} (Code: {$registrationCode})");
} else {
$message = 'Failed to check out non-member. Please try again.';
$messageType = 'error';
}
} else {
$message = 'Non-member registration not found or not currently checked in.';
$messageType = 'error';
}
}
}
}
// Handle export functionality
if (isset($_GET['export']) && $_GET['export'] === 'csv') {
$eventId = $_GET['event_id'] ?? null;
$districtId = $_GET['district_id'] ?? null;
$assemblyId = $_GET['assembly_id'] ?? null;
// Build export query
$sql = "
SELECT
'member' as type,
er.registration_code,
CONCAT(u.first_name, ' ', u.last_name) as attendee_name,
e.title as event_title,
d.name as district_name,
a.name as assembly_name,
er.checked_in_at,
er.checked_out_at,
CASE
WHEN er.checked_out_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, er.checked_in_at, er.checked_out_at)
WHEN er.checked_in_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, er.checked_in_at, NOW())
ELSE NULL
END as duration_minutes
FROM event_registrations er
JOIN users u ON er.user_id = u.id
JOIN events e ON er.event_id = e.id
LEFT JOIN districts d ON e.district_id = d.id
LEFT JOIN assemblies a ON e.assembly_id = a.id
WHERE er.status != 'cancelled'
UNION ALL
SELECT
'nonmember' as type,
nr.registration_code,
CONCAT(
COALESCE(JSON_UNQUOTE(JSON_EXTRACT(nr.form_data, '$.first_name')), ''),
' ',
COALESCE(JSON_UNQUOTE(JSON_EXTRACT(nr.form_data, '$.last_name')), '')
) as attendee_name,
e.title as event_title,
d.name as district_name,
a.name as assembly_name,
nr.checked_in_at,
nr.checked_out_at,
CASE
WHEN nr.checked_out_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, nr.checked_in_at, nr.checked_out_at)
WHEN nr.checked_in_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, nr.checked_in_at, NOW())
ELSE NULL
END as duration_minutes
FROM nonmember_registrations nr
JOIN events e ON nr.event_id = e.id
LEFT JOIN districts d ON e.district_id = d.id
LEFT JOIN assemblies a ON e.assembly_id = a.id
WHERE nr.status != 'cancelled'
ORDER BY attendee_name
";
$stmt = $conn->prepare($sql);
$stmt->execute();
$records = $stmt->fetchAll();
// Set headers for CSV download
header('Content-Type: text/csv');
header('Content-Disposition: attachment; filename="attendance_report_' . date('Y-m-d') . '.csv"');
$output = fopen('php://output', 'w');
// CSV headers
fputcsv($output, [
'Registration Code', 'Name', 'Type', 'Event', 'District', 'Assembly',
'Check-In Time', 'Check-Out Time', 'Duration (Minutes)'
]);
// CSV data
foreach ($records as $record) {
fputcsv($output, [
$record['registration_code'],
$record['attendee_name'],
ucfirst($record['type']),
$record['event_title'],
$record['district_name'] ?: 'N/A',
$record['assembly_name'] ?: 'N/A',
$record['checked_in_at'] ? date('Y-m-d H:i:s', strtotime($record['checked_in_at'])) : '',
$record['checked_out_at'] ? date('Y-m-d H:i:s', strtotime($record['checked_out_at'])) : '',
$record['duration_minutes'] ?: 0
]);
}
fclose($output);
exit();
}
// Get filter parameters
$selectedEvent = $_GET['event_id'] ?? '';
$selectedDistrict = $_GET['district_id'] ?? '';
$selectedAssembly = $_GET['assembly_id'] ?? '';
// Get events for filter
$eventsStmt = $conn->prepare("SELECT id, title FROM events WHERE status = 'published' ORDER BY start_date DESC");
$eventsStmt->execute();
$events = $eventsStmt->fetchAll();
// Get districts for filter
$districtsStmt = $conn->prepare("SELECT id, name FROM districts WHERE status = 'active' ORDER BY name");
$districtsStmt->execute();
$districts = $districtsStmt->fetchAll();
// Get assemblies for filter
$assemblies = [];
if ($selectedDistrict) {
$assembliesStmt = $conn->prepare("SELECT id, name FROM assemblies WHERE district_id = ? AND status = 'active' ORDER BY name");
$assembliesStmt->execute([$selectedDistrict]);
$assemblies = $assembliesStmt->fetchAll();
}
// Get attendance records with filters
$sql = "
SELECT
'member' as type,
er.registration_code,
CONCAT(u.first_name, ' ', u.last_name) as attendee_name,
u.email as attendee_email,
e.title as event_title,
d.name as district_name,
a.name as assembly_name,
er.checked_in_at,
er.checked_out_at,
CASE
WHEN er.checked_out_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, er.checked_in_at, er.checked_out_at)
WHEN er.checked_in_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, er.checked_in_at, NOW())
ELSE NULL
END as duration_minutes,
CASE
WHEN er.checked_out_at IS NOT NULL THEN 'Completed'
WHEN er.checked_in_at IS NOT NULL THEN 'Checked In'
ELSE 'Registered'
END as attendance_status
FROM event_registrations er
JOIN users u ON er.user_id = u.id
JOIN events e ON er.event_id = e.id
LEFT JOIN districts d ON e.district_id = d.id
LEFT JOIN assemblies a ON e.assembly_id = a.id
WHERE er.status != 'cancelled'
UNION ALL
SELECT
'nonmember' as type,
nr.registration_code,
CONCAT(
COALESCE(JSON_UNQUOTE(JSON_EXTRACT(nr.form_data, '$.first_name')), ''),
' ',
COALESCE(JSON_UNQUOTE(JSON_EXTRACT(nr.form_data, '$.last_name')), '')
) as attendee_name,
JSON_UNQUOTE(JSON_EXTRACT(nr.form_data, '$.email')) as attendee_email,
e.title as event_title,
d.name as district_name,
a.name as assembly_name,
nr.checked_in_at,
nr.checked_out_at,
CASE
WHEN nr.checked_out_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, nr.checked_in_at, nr.checked_out_at)
WHEN nr.checked_in_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, nr.checked_in_at, NOW())
ELSE NULL
END as duration_minutes,
CASE
WHEN nr.checked_out_at IS NOT NULL THEN 'Completed'
WHEN nr.checked_in_at IS NOT NULL THEN 'Checked In'
ELSE 'Registered'
END as attendance_status
FROM nonmember_registrations nr
JOIN events e ON nr.event_id = e.id
LEFT JOIN districts d ON e.district_id = d.id
LEFT JOIN assemblies a ON e.assembly_id = a.id
WHERE nr.status != 'cancelled'
ORDER BY checked_in_at DESC, attendee_name
LIMIT 100
";
$stmt = $conn->prepare($sql);
$stmt->execute();
$attendanceRecords = $stmt->fetchAll();
// Get summary statistics
$statsStmt = $conn->prepare("
SELECT
COUNT(*) as total_registrations,
SUM(CASE WHEN checked_in_at IS NOT NULL THEN 1 ELSE 0 END) as total_checked_in,
SUM(CASE WHEN checked_out_at IS NOT NULL THEN 1 ELSE 0 END) as total_checked_out,
AVG(CASE WHEN checked_out_at IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, checked_in_at, checked_out_at) ELSE NULL END) as avg_duration_minutes
FROM (
SELECT checked_in_at, checked_out_at FROM event_registrations WHERE status != 'cancelled'
UNION ALL
SELECT checked_in_at, checked_out_at FROM nonmember_registrations WHERE status != 'cancelled'
) combined
");
$statsStmt->execute();
$stats = $statsStmt->fetch();
// Get notifications
$notifications = getNotifications($user_id);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Attendance Reports - Admin Panel</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
animation: {
'fade-in': 'fadeIn 0.5s ease-out',
'slide-up': 'slideUp 0.6s ease-out'
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' }
},
slideUp: {
'0%': { opacity: '0', transform: 'translateY(20px)' },
'100%': { opacity: '1', transform: 'translateY(0)' }
}
}
}
}
}
function exportData() {
const params = new URLSearchParams(window.location.search);
params.set('export', 'csv');
window.location.href = '?' + params.toString();
}
</script>
</head>
<body class="bg-gradient-to-br from-slate-50 to-blue-50 min-h-screen">
<div class="flex">
<!-- Sidebar -->
<?php include 'includes/admin_sidebar.php'; ?>
<!-- Main Content -->
<div class="flex-1 ml-72">
<!-- Header -->
<header class="bg-white/80 backdrop-blur-sm shadow-lg border-b border-slate-200/50 sticky top-0 z-40">
<div class="px-8 py-6">
<div class="flex items-center justify-between">
<div class="flex items-center space-x-4">
<div class="w-12 h-12 bg-gradient-to-br from-emerald-500 to-green-600 rounded-2xl flex items-center justify-center shadow-lg">
<i class="fas fa-chart-bar text-white text-xl"></i>
</div>
<div>
<h1 class="text-2xl font-bold bg-gradient-to-r from-emerald-600 to-green-600 bg-clip-text text-transparent">
Attendance Reports
</h1>
<p class="text-slate-600">Track check-in/check-out records and attendance duration</p>
</div>
</div>
<!-- Export Button -->
<button onclick="exportData()" class="bg-gradient-to-r from-emerald-600 to-green-600 hover:from-emerald-700 hover:to-green-700 text-white px-6 py-3 rounded-xl font-semibold transition-all duration-200 shadow-lg hover:shadow-xl transform hover:-translate-y-1">
<i class="fas fa-download mr-2"></i>Export CSV
</button>
</div>
</div>
</header>
<!-- Main Content Area -->
<main class="p-8">
<!-- Success/Error Messages -->
<?php if ($message): ?>
<div class="mb-6 p-4 rounded-xl <?php echo $messageType === 'success' ? 'bg-green-100 border border-green-200 text-green-800' : 'bg-red-100 border border-red-200 text-red-800'; ?> animate-fade-in">
<div class="flex items-center">
<i class="fas <?php echo $messageType === 'success' ? 'fa-check-circle' : 'fa-exclamation-triangle'; ?> mr-3"></i>
<span class="font-medium"><?php echo htmlspecialchars($message); ?></span>
</div>
</div>
<?php endif; ?>
<!-- Statistics Cards -->
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50 animate-fade-in">
<div class="flex items-center justify-between">
<div>
<p class="text-slate-600 text-sm font-medium">Total Registrations</p>
<p class="text-3xl font-bold text-slate-800"><?php echo number_format($stats['total_registrations'] ?? 0); ?></p>
</div>
<div class="w-12 h-12 bg-blue-100 rounded-xl flex items-center justify-center">
<i class="fas fa-users text-blue-600 text-xl"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50 animate-fade-in" style="animation-delay: 0.1s">
<div class="flex items-center justify-between">
<div>
<p class="text-slate-600 text-sm font-medium">Checked In</p>
<p class="text-3xl font-bold text-emerald-600"><?php echo number_format($stats['total_checked_in'] ?? 0); ?></p>
</div>
<div class="w-12 h-12 bg-emerald-100 rounded-xl flex items-center justify-center">
<i class="fas fa-sign-in-alt text-emerald-600 text-xl"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50 animate-fade-in" style="animation-delay: 0.2s">
<div class="flex items-center justify-between">
<div>
<p class="text-slate-600 text-sm font-medium">Checked Out</p>
<p class="text-3xl font-bold text-red-600"><?php echo number_format($stats['total_checked_out'] ?? 0); ?></p>
</div>
<div class="w-12 h-12 bg-red-100 rounded-xl flex items-center justify-center">
<i class="fas fa-sign-out-alt text-red-600 text-xl"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50 animate-fade-in" style="animation-delay: 0.3s">
<div class="flex items-center justify-between">
<div>
<p class="text-slate-600 text-sm font-medium">Avg Duration</p>
<p class="text-3xl font-bold text-purple-600">
<?php
$avgDuration = $stats['avg_duration_minutes'] ?? 0;
$hours = floor($avgDuration / 60);
$minutes = $avgDuration % 60;
echo ($hours > 0 ? $hours . 'h ' : '') . round($minutes) . 'm';
?>
</p>
</div>
<div class="w-12 h-12 bg-purple-100 rounded-xl flex items-center justify-center">
<i class="fas fa-clock text-purple-600 text-xl"></i>
</div>
</div>
</div>
</div>
<!-- Filters -->
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50 mb-8 animate-slide-up">
<h3 class="text-lg font-semibold text-slate-800 mb-4">
<i class="fas fa-filter mr-2 text-emerald-600"></i>Filter Records
</h3>
<form method="GET" class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Event</label>
<select name="event_id" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500">
<option value="">All Events</option>
<?php foreach ($events as $event): ?>
<option value="<?php echo $event['id']; ?>" <?php echo $selectedEvent == $event['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($event['title']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">District</label>
<select name="district_id" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500" onchange="this.form.submit()">
<option value="">All Districts</option>
<?php foreach ($districts as $district): ?>
<option value="<?php echo $district['id']; ?>" <?php echo $selectedDistrict == $district['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($district['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div>
<label class="block text-sm font-medium text-slate-700 mb-2">Assembly</label>
<select name="assembly_id" class="w-full px-4 py-2 border border-slate-300 rounded-lg focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500">
<option value="">All Assemblies</option>
<?php foreach ($assemblies as $assembly): ?>
<option value="<?php echo $assembly['id']; ?>" <?php echo $selectedAssembly == $assembly['id'] ? 'selected' : ''; ?>>
<?php echo htmlspecialchars($assembly['name']); ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="flex items-end">
<button type="submit" class="w-full bg-gradient-to-r from-emerald-600 to-green-600 hover:from-emerald-700 hover:to-green-700 text-white px-4 py-2 rounded-lg font-semibold transition-all duration-200">
<i class="fas fa-search mr-2"></i>Filter
</button>
</div>
</form>
</div>
<!-- Attendance Records Table -->
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg border border-slate-200/50 overflow-hidden animate-slide-up">
<div class="px-6 py-4 border-b border-slate-200/50">
<h3 class="text-lg font-semibold text-slate-800">
<i class="fas fa-list mr-2 text-emerald-600"></i>Attendance Records
<span class="text-sm font-normal text-slate-600 ml-2">(Latest 100 records)</span>
</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-gradient-to-r from-emerald-500 to-green-500 text-white">
<tr>
<th class="px-6 py-4 text-left font-semibold">Code</th>
<th class="px-6 py-4 text-left font-semibold">Name</th>
<th class="px-6 py-4 text-left font-semibold">Type</th>
<th class="px-6 py-4 text-left font-semibold">Event</th>
<th class="px-6 py-4 text-left font-semibold">Check-In</th>
<th class="px-6 py-4 text-left font-semibold">Check-Out</th>
<th class="px-6 py-4 text-left font-semibold">Duration</th>
<th class="px-6 py-4 text-left font-semibold">Status</th>
<th class="px-6 py-4 text-left font-semibold">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200">
<?php if (empty($attendanceRecords)): ?>
<tr>
<td colspan="9" class="px-6 py-12 text-center text-slate-500">
<i class="fas fa-inbox text-4xl mb-4"></i>
<p class="text-lg font-semibold">No attendance records found</p>
<p class="text-sm">Try adjusting your filters or check back later.</p>
</td>
</tr>
<?php else: ?>
<?php foreach ($attendanceRecords as $record): ?>
<tr class="hover:bg-slate-50 transition-colors">
<td class="px-6 py-4">
<span class="font-mono text-sm bg-slate-100 px-2 py-1 rounded">
<?php echo htmlspecialchars($record['registration_code']); ?>
</span>
</td>
<td class="px-6 py-4">
<div class="font-semibold text-slate-800">
<?php echo htmlspecialchars(trim($record['attendee_name'])); ?>
</div>
<?php if ($record['attendee_email']): ?>
<div class="text-sm text-slate-600">
<?php echo htmlspecialchars($record['attendee_email']); ?>
</div>
<?php endif; ?>
</td>
<td class="px-6 py-4">
<span class="px-3 py-1 rounded-full text-xs font-semibold <?php echo $record['type'] === 'member' ? 'bg-blue-100 text-blue-800' : 'bg-purple-100 text-purple-800'; ?>">
<?php echo ucfirst($record['type']); ?>
</span>
</td>
<td class="px-6 py-4 text-slate-600">
<?php echo htmlspecialchars($record['event_title']); ?>
</td>
<td class="px-6 py-4 text-slate-600">
<?php echo $record['checked_in_at'] ? date('M j, g:i A', strtotime($record['checked_in_at'])) : '-'; ?>
</td>
<td class="px-6 py-4 text-slate-600">
<?php echo $record['checked_out_at'] ? date('M j, g:i A', strtotime($record['checked_out_at'])) : '-'; ?>
</td>
<td class="px-6 py-4">
<?php if ($record['duration_minutes']): ?>
<?php
$hours = floor($record['duration_minutes'] / 60);
$minutes = $record['duration_minutes'] % 60;
$durationText = ($hours > 0 ? $hours . 'h ' : '') . $minutes . 'm';
?>
<span class="font-semibold text-emerald-600"><?php echo $durationText; ?></span>
<?php else: ?>
<span class="text-slate-400">-</span>
<?php endif; ?>
</td>
<td class="px-6 py-4">
<span class="px-3 py-1 rounded-full text-xs font-semibold
<?php
echo $record['attendance_status'] === 'Completed' ? 'bg-green-100 text-green-800' :
($record['attendance_status'] === 'Checked In' ? 'bg-blue-100 text-blue-800' : 'bg-yellow-100 text-yellow-800');
?>">
<?php echo $record['attendance_status']; ?>
</span>
</td>
<td class="px-6 py-4">
<?php if ($record['attendance_status'] === 'Checked In'): ?>
<form method="POST" class="inline-block" onsubmit="return confirm('Are you sure you want to check out this attendee?');">
<input type="hidden" name="action" value="admin_checkout">
<input type="hidden" name="registration_code" value="<?php echo htmlspecialchars($record['registration_code']); ?>">
<input type="hidden" name="registration_type" value="<?php echo htmlspecialchars($record['type']); ?>">
<button type="submit" class="bg-gradient-to-r from-red-500 to-orange-500 hover:from-red-600 hover:to-orange-600 text-white px-3 py-1 rounded-lg text-xs font-semibold transition-all duration-200 shadow-sm hover:shadow-md">
<i class="fas fa-sign-out-alt mr-1"></i>Check Out
</button>
</form>
<?php else: ?>
<span class="text-slate-400 text-xs">-</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</main>
</div>
</div>
</body>
</html>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists