Sindbad~EG File Manager
<?php
require_once '../includes/functions.php';
// Check if user is logged in and has admin privileges
if (!isLoggedIn()) {
header('Location: ' . BASE_URL . 'login.php');
exit();
}
$user_id = $_SESSION['user_id'] ?? null;
$user_role = $_SESSION['user_role'] ?? null;
if (!$user_id || !in_array($user_role, ['superuser', 'area_admin', 'district_admin', 'assembly_admin'])) {
header('Location: ../dashboard.php');
exit();
}
$message = '';
$messageType = '';
$db = new CopMadinaDB();
$conn = $db->getConnection();
// Handle form submissions
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$action = $_POST['action'] ?? '';
if ($action === 'update_status') {
$id = $_POST['id'];
$status = $_POST['status'];
// Determine which table to update based on registration type
$registrationType = $_POST['registration_type'] ?? 'member';
if ($registrationType === 'member') {
$stmt = $conn->prepare("UPDATE event_registrations SET status = ? WHERE id = ?");
} else {
$stmt = $conn->prepare("UPDATE nonmember_registrations SET status = ? WHERE id = ?");
}
$result = $stmt->execute([$status, $id]);
if ($result) {
logActivity($_SESSION['user_id'], 'update_registration_status', "Updated registration ID {$id} status to {$status}");
$message = 'Registration status updated successfully!';
$messageType = 'success';
} else {
$message = 'Failed to update registration status.';
$messageType = 'error';
}
} elseif ($action === 'delete') {
$id = $_POST['id'];
$registrationType = $_POST['registration_type'] ?? 'member';
if ($registrationType === 'member') {
$stmt = $conn->prepare("DELETE FROM event_registrations WHERE id = ?");
} else {
$stmt = $conn->prepare("DELETE FROM nonmember_registrations WHERE id = ?");
}
$result = $stmt->execute([$id]);
if ($result) {
logActivity($_SESSION['user_id'], 'delete_registration', "Deleted registration ID {$id} ({$registrationType})");
$message = 'Registration deleted successfully!';
$messageType = 'success';
} else {
$message = 'Failed to delete registration.';
$messageType = 'error';
}
}
header('Location: registrations.php');
exit();
}
// Get combined registrations from both member and non-member tables
$registrations_query = "
SELECT
er.id,
er.event_id,
er.registration_code,
er.status,
er.payment_status,
er.amount_paid,
er.created_at,
e.title as event_title,
e.start_date as event_date,
e.registration_fee,
u.first_name,
u.last_name,
u.email,
u.phone,
'member' as registration_type,
a.name as area_name,
d.name as district_name,
ass.name as assembly_name
FROM event_registrations er
LEFT JOIN events e ON er.event_id = e.id
LEFT JOIN users u ON er.user_id = u.id
LEFT JOIN areas a ON e.area_id = a.id
LEFT JOIN districts d ON e.district_id = d.id
LEFT JOIN assemblies ass ON e.assembly_id = ass.id
UNION ALL
SELECT
nr.id,
nr.event_id,
nr.registration_code,
nr.status,
nr.payment_status,
nr.amount_paid,
nr.created_at,
e.title as event_title,
e.start_date as event_date,
e.registration_fee,
nr.first_name,
nr.last_name,
nr.email,
nr.phone,
'non-member' as registration_type,
a.name as area_name,
d.name as district_name,
ass.name as assembly_name
FROM nonmember_registrations nr
LEFT JOIN events e ON nr.event_id = e.id
LEFT JOIN areas a ON e.area_id = a.id
LEFT JOIN districts d ON e.district_id = d.id
LEFT JOIN assemblies ass ON e.assembly_id = ass.id
";
$params = [];
$whereClause = "";
// Role-based filtering would need user details from database
// For now, show all registrations for admin users
// Apply WHERE clause to both parts of UNION
if ($whereClause) {
$registrations_query = str_replace(
"FROM event_registrations er",
"FROM event_registrations er" . $whereClause,
$registrations_query
);
$registrations_query = str_replace(
"FROM nonmember_registrations nr",
"FROM nonmember_registrations nr" . str_replace("e.area_id", "e.area_id", $whereClause),
$registrations_query
);
// Duplicate params for second part of UNION
$params = array_merge($params, $params);
}
$registrations_query .= " ORDER BY created_at DESC";
$stmt = $conn->prepare($registrations_query);
$stmt->execute($params);
$registrations = $stmt->fetchAll();
// Get registration statistics from both tables
$stats_query = "
SELECT
COUNT(*) as total_registrations,
COUNT(CASE WHEN status = 'confirmed' THEN 1 END) as confirmed,
COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending,
COUNT(CASE WHEN status = 'cancelled' THEN 1 END) as cancelled,
SUM(CASE WHEN status = 'confirmed' THEN amount_paid ELSE 0 END) as total_revenue
FROM (
SELECT er.status, er.amount_paid, e.area_id, e.district_id, e.assembly_id
FROM event_registrations er
LEFT JOIN events e ON er.event_id = e.id
UNION ALL
SELECT nr.status, nr.amount_paid, e.area_id, e.district_id, e.assembly_id
FROM nonmember_registrations nr
LEFT JOIN events e ON nr.event_id = e.id
) combined_registrations
";
$stmt = $conn->prepare($stats_query);
$stmt->execute();
$stats = $stmt->fetch() ?: ['total_registrations' => 0, 'confirmed' => 0, 'pending' => 0, 'cancelled' => 0, 'total_revenue' => 0];
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registrations Management - COP Madina Conference</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://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body class="bg-gradient-to-br from-slate-50 to-blue-50 min-h-screen">
<div id="app" class="flex h-screen">
<!-- Sidebar -->
<?php include 'includes/admin_sidebar.php'; ?>
<!-- Main Content -->
<div class="flex-1 flex flex-col overflow-hidden ml-72">
<!-- Header -->
<header class="bg-white/80 backdrop-blur-sm shadow-lg border-b border-slate-200/50">
<div class="flex items-center justify-between px-8 py-6">
<div>
<h1 class="text-3xl font-bold bg-gradient-to-r from-teal-600 to-green-600 bg-clip-text text-transparent flex items-center">
<div class="p-2 rounded-xl bg-gradient-to-br from-teal-500 to-green-600 mr-3">
<i class="fas fa-clipboard-list text-white"></i>
</div>
Registrations Management
</h1>
<p class="text-slate-600 mt-1">Manage event registrations and attendees</p>
</div>
</div>
</header>
<!-- Content -->
<main class="flex-1 overflow-y-auto 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-2 lg:grid-cols-5 gap-6 mb-8">
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-slate-600 uppercase tracking-wider">Total</p>
<p class="text-2xl font-bold text-slate-800"><?php echo $stats['total_registrations']; ?></p>
</div>
<div class="p-3 rounded-xl bg-gradient-to-br from-slate-500 to-slate-600">
<i class="fas fa-users text-white"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-slate-600 uppercase tracking-wider">Confirmed</p>
<p class="text-2xl font-bold text-emerald-600"><?php echo $stats['confirmed']; ?></p>
</div>
<div class="p-3 rounded-xl bg-gradient-to-br from-emerald-500 to-emerald-600">
<i class="fas fa-check text-white"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-slate-600 uppercase tracking-wider">Pending</p>
<p class="text-2xl font-bold text-yellow-600"><?php echo $stats['pending']; ?></p>
</div>
<div class="p-3 rounded-xl bg-gradient-to-br from-yellow-500 to-yellow-600">
<i class="fas fa-clock text-white"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-slate-600 uppercase tracking-wider">Cancelled</p>
<p class="text-2xl font-bold text-red-600"><?php echo $stats['cancelled']; ?></p>
</div>
<div class="p-3 rounded-xl bg-gradient-to-br from-red-500 to-red-600">
<i class="fas fa-times text-white"></i>
</div>
</div>
</div>
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg p-6 border border-slate-200/50">
<div class="flex items-center justify-between">
<div>
<p class="text-sm font-semibold text-slate-600 uppercase tracking-wider">Revenue</p>
<p class="text-2xl font-bold text-teal-600">GH₵<?php echo number_format($stats['total_revenue'], 2); ?></p>
</div>
<div class="p-3 rounded-xl bg-gradient-to-br from-teal-500 to-teal-600">
<i class="fas fa-dollar-sign text-white"></i>
</div>
</div>
</div>
</div>
<!-- Registrations Table -->
<div class="bg-white/70 backdrop-blur-sm rounded-2xl shadow-lg border border-slate-200/50">
<div class="p-6 border-b border-slate-200/50">
<h3 class="text-lg font-semibold text-slate-800">Recent Registrations</h3>
</div>
<div class="overflow-x-auto">
<table class="w-full">
<thead class="bg-slate-50/50 border-b border-slate-200/50">
<tr>
<th class="px-6 py-4 text-left text-sm font-semibold text-slate-700">Registrant</th>
<th class="px-6 py-4 text-left text-sm font-semibold text-slate-700">Event</th>
<th class="px-6 py-4 text-left text-sm font-semibold text-slate-700">Date</th>
<th class="px-6 py-4 text-left text-sm font-semibold text-slate-700">Fee</th>
<th class="px-6 py-4 text-left text-sm font-semibold text-slate-700">Status</th>
<th class="px-6 py-4 text-left text-sm font-semibold text-slate-700">Registered</th>
<th class="px-6 py-4 text-center text-sm font-semibold text-slate-700">Actions</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-200/50">
<?php foreach ($registrations as $registration): ?>
<tr class="hover:bg-slate-50/50 transition-colors">
<td class="px-6 py-4">
<div>
<div class="font-semibold text-slate-800">
<?php echo htmlspecialchars(($registration['first_name'] ?? 'Guest') . ' ' . ($registration['last_name'] ?? 'User')); ?>
<span class="ml-2 inline-flex px-2 py-1 text-xs font-medium rounded-full
<?php echo $registration['registration_type'] === 'member' ? 'bg-blue-100 text-blue-800' : 'bg-gray-100 text-gray-800'; ?>">
<?php echo ucfirst($registration['registration_type']); ?>
</span>
</div>
<div class="text-sm text-slate-600"><?php echo htmlspecialchars($registration['email'] ?? 'N/A'); ?></div>
<?php if (!empty($registration['phone'])): ?>
<div class="text-sm text-slate-500"><?php echo htmlspecialchars($registration['phone']); ?></div>
<?php endif; ?>
<?php if (!empty($registration['registration_code'])): ?>
<div class="text-xs text-slate-400">Code: <?php echo htmlspecialchars($registration['registration_code']); ?></div>
<?php endif; ?>
</div>
</td>
<td class="px-6 py-4">
<div>
<div class="font-semibold text-slate-800"><?php echo htmlspecialchars($registration['event_title']); ?></div>
<div class="text-sm text-slate-600">
<?php
if ($registration['area_name']) echo htmlspecialchars($registration['area_name']);
if ($registration['district_name']) echo ($registration['area_name'] ? ' > ' : '') . htmlspecialchars($registration['district_name']);
if ($registration['assembly_name']) echo ($registration['district_name'] ? ' > ' : '') . htmlspecialchars($registration['assembly_name']);
?>
</div>
</div>
</td>
<td class="px-6 py-4 text-sm text-slate-600">
<?php echo date('M j, Y', strtotime($registration['event_date'])); ?>
</td>
<td class="px-6 py-4 text-sm text-slate-600">
GH₵<?php echo number_format($registration['registration_fee'], 2); ?>
</td>
<td class="px-6 py-4">
<span class="px-3 py-1 text-xs font-semibold rounded-full <?php
echo $registration['status'] === 'confirmed' ? 'bg-emerald-100 text-emerald-800' :
($registration['status'] === 'pending' ? 'bg-yellow-100 text-yellow-800' : 'bg-red-100 text-red-800');
?>">
<?php echo ucfirst($registration['status']); ?>
</span>
</td>
<td class="px-6 py-4 text-sm text-slate-600">
<?php echo date('M j, Y g:i A', strtotime($registration['created_at'])); ?>
</td>
<td class="px-6 py-4 text-center">
<div class="flex justify-center space-x-2">
<button @click="updateStatus(<?php echo $registration['id']; ?>, '<?php echo $registration['status']; ?>', '<?php echo $registration['registration_type']; ?>')"
class="px-3 py-1 bg-teal-100 hover:bg-teal-200 text-teal-700 rounded-lg text-sm transition-colors">
<i class="fas fa-edit"></i>
</button>
<button @click="confirmDelete(<?php echo $registration['id']; ?>, '<?php echo htmlspecialchars($registration['event_title']); ?>', '<?php echo $registration['registration_type']; ?>')"
class="px-3 py-1 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg text-sm transition-colors">
<i class="fas fa-trash"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<!-- Empty State -->
<?php if (empty($registrations)): ?>
<div class="text-center py-16">
<div class="mx-auto w-24 h-24 bg-slate-100 rounded-full flex items-center justify-center mb-6">
<i class="fas fa-clipboard-list text-3xl text-slate-400"></i>
</div>
<h3 class="text-xl font-semibold text-slate-700 mb-2">No Registrations Found</h3>
<p class="text-slate-500">Registrations will appear here once users start signing up for events.</p>
</div>
<?php endif; ?>
</main>
</div>
<!-- Status Update Modal -->
<div v-if="showStatusModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div class="bg-white/95 backdrop-blur-sm rounded-2xl shadow-2xl w-full max-w-md border border-slate-200/50">
<div class="p-6">
<h3 class="text-xl font-bold text-slate-800 mb-4">Update Registration Status</h3>
<form method="POST">
<input type="hidden" name="action" value="update_status">
<input type="hidden" name="id" :value="updatingRegistrationId">
<input type="hidden" name="registration_type" :value="updatingRegistrationType">
<div class="mb-6">
<label class="block text-sm font-semibold text-slate-700 mb-2">Status</label>
<select name="status" v-model="newStatus" required
class="w-full px-4 py-3 border border-slate-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-teal-500 focus:border-transparent transition-all duration-200">
<option value="pending">Pending</option>
<option value="confirmed">Confirmed</option>
<option value="cancelled">Cancelled</option>
</select>
</div>
<div class="flex justify-end space-x-3">
<button type="button" @click="showStatusModal = false"
class="px-6 py-3 bg-slate-100 hover:bg-slate-200 text-slate-700 font-medium rounded-xl transition-colors">
Cancel
</button>
<button type="submit"
class="px-6 py-3 bg-gradient-to-r from-teal-600 to-green-600 hover:from-teal-700 hover:to-green-700 text-white font-medium rounded-xl transition-all duration-200">
Update Status
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Delete Confirmation Modal -->
<div v-if="showDeleteModal" class="fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div class="bg-white/95 backdrop-blur-sm rounded-2xl shadow-2xl w-full max-w-md border border-slate-200/50">
<div class="p-6 text-center">
<div class="mx-auto w-16 h-16 bg-red-100 rounded-full flex items-center justify-center mb-4">
<i class="fas fa-exclamation-triangle text-red-600 text-2xl"></i>
</div>
<h3 class="text-xl font-bold text-slate-800 mb-2">Delete Registration</h3>
<p class="text-slate-600 mb-6">
Are you sure you want to delete this registration for <strong>"{{ deletingEventName }}"</strong>? This action cannot be undone.
</p>
<div class="flex justify-center space-x-3">
<form method="POST" class="flex space-x-3">
<input type="hidden" name="action" value="delete">
<input type="hidden" name="id" :value="deletingRegistrationId">
<input type="hidden" name="registration_type" :value="deletingRegistrationType">
<button type="button" @click="showDeleteModal = false"
class="px-6 py-3 bg-slate-100 hover:bg-slate-200 text-slate-700 font-medium rounded-xl transition-colors">
Cancel
</button>
<button type="submit"
class="px-6 py-3 bg-red-600 hover:bg-red-700 text-white font-medium rounded-xl transition-colors">
Delete
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
showStatusModal: false,
showDeleteModal: false,
updatingRegistrationId: null,
updatingRegistrationType: '',
newStatus: '',
deletingRegistrationId: null,
deletingRegistrationType: '',
deletingEventName: ''
}
},
methods: {
updateStatus(id, currentStatus, registrationType) {
this.updatingRegistrationId = id;
this.updatingRegistrationType = registrationType;
this.newStatus = currentStatus;
this.showStatusModal = true;
},
confirmDelete(id, eventName, registrationType) {
this.deletingRegistrationId = id;
this.deletingRegistrationType = registrationType;
this.deletingEventName = eventName;
this.showDeleteModal = true;
}
}
}).mount('#app');
</script>
</body>
</html>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists