1187 lines
43 KiB
HTML
1187 lines
43 KiB
HTML
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Admin Panel - Lebanon Sports Hub</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<style>
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
}
|
|
|
|
:root {
|
|
--primary: #ed1c24;
|
|
--secondary: #00a651;
|
|
--dark: #1a1a1a;
|
|
--light: #f5f5f5;
|
|
--gray: #777;
|
|
--shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
--pending: #FFA726;
|
|
--approved: #4CAF50;
|
|
--rejected: #F44336;
|
|
}
|
|
|
|
body {
|
|
background-color: #f5f7fa;
|
|
color: var(--dark);
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.container {
|
|
width: 95%;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 0 15px;
|
|
}
|
|
|
|
/* Header */
|
|
header {
|
|
background: white;
|
|
box-shadow: var(--shadow);
|
|
padding: 15px 0;
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.header-content {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
|
|
.logo {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
font-size: 1.5rem;
|
|
font-weight: 700;
|
|
color: var(--primary);
|
|
}
|
|
|
|
.logo i {
|
|
color: var(--secondary);
|
|
}
|
|
|
|
.admin-info {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
}
|
|
|
|
.admin-name {
|
|
font-weight: 600;
|
|
color: var(--dark);
|
|
}
|
|
|
|
.logout-btn {
|
|
background: var(--primary);
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 20px;
|
|
border-radius: 4px;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.logout-btn:hover {
|
|
background: #c5161c;
|
|
}
|
|
|
|
/* Login Form */
|
|
.login-container {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
min-height: 100vh;
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
}
|
|
|
|
.login-form {
|
|
background: white;
|
|
padding: 40px;
|
|
border-radius: 15px;
|
|
width: 100%;
|
|
max-width: 400px;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.login-form h2 {
|
|
text-align: center;
|
|
margin-bottom: 30px;
|
|
color: var(--dark);
|
|
}
|
|
|
|
.form-group {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.form-group label {
|
|
display: block;
|
|
margin-bottom: 8px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.form-group input {
|
|
width: 100%;
|
|
padding: 12px 15px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 5px;
|
|
font-size: 1rem;
|
|
}
|
|
|
|
.login-btn {
|
|
width: 100%;
|
|
padding: 14px;
|
|
background: var(--primary);
|
|
color: white;
|
|
border: none;
|
|
border-radius: 5px;
|
|
font-weight: 600;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
margin-top: 10px;
|
|
}
|
|
|
|
.login-btn:hover {
|
|
background: #c5161c;
|
|
}
|
|
|
|
.error-message {
|
|
color: var(--rejected);
|
|
text-align: center;
|
|
margin-top: 10px;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Dashboard */
|
|
.dashboard {
|
|
padding: 30px 0;
|
|
}
|
|
|
|
.stats-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
gap: 20px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.stat-card {
|
|
background: white;
|
|
padding: 25px;
|
|
border-radius: 10px;
|
|
box-shadow: var(--shadow);
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 20px;
|
|
}
|
|
|
|
.stat-icon {
|
|
width: 60px;
|
|
height: 60px;
|
|
border-radius: 10px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 1.5rem;
|
|
color: white;
|
|
}
|
|
|
|
.stat-icon.pending {
|
|
background: var(--pending);
|
|
}
|
|
|
|
.stat-icon.approved {
|
|
background: var(--approved);
|
|
}
|
|
|
|
.stat-icon.rejected {
|
|
background: var(--rejected);
|
|
}
|
|
|
|
.stat-icon.total {
|
|
background: var(--primary);
|
|
}
|
|
|
|
.stat-info h3 {
|
|
font-size: 2rem;
|
|
margin-bottom: 5px;
|
|
color: var(--dark);
|
|
}
|
|
|
|
.stat-info p {
|
|
color: var(--gray);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Tabs */
|
|
.tabs {
|
|
display: flex;
|
|
gap: 10px;
|
|
margin-bottom: 30px;
|
|
border-bottom: 2px solid #eee;
|
|
padding-bottom: 10px;
|
|
}
|
|
|
|
.tab-btn {
|
|
background: none;
|
|
border: none;
|
|
padding: 10px 25px;
|
|
font-size: 1rem;
|
|
font-weight: 600;
|
|
color: var(--gray);
|
|
cursor: pointer;
|
|
border-radius: 5px 5px 0 0;
|
|
transition: all 0.3s;
|
|
}
|
|
|
|
.tab-btn.active {
|
|
color: var(--primary);
|
|
border-bottom: 3px solid var(--primary);
|
|
background: rgba(237, 28, 36, 0.1);
|
|
}
|
|
|
|
/* Tables */
|
|
.table-container {
|
|
background: white;
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow);
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
thead {
|
|
background: var(--primary);
|
|
color: white;
|
|
}
|
|
|
|
th {
|
|
padding: 15px;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
}
|
|
|
|
tbody tr {
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background: #f9f9f9;
|
|
}
|
|
|
|
td {
|
|
padding: 15px;
|
|
}
|
|
|
|
.status-badge {
|
|
display: inline-block;
|
|
padding: 5px 15px;
|
|
border-radius: 20px;
|
|
font-size: 0.85rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.status-pending {
|
|
background: #FFF3E0;
|
|
color: var(--pending);
|
|
}
|
|
|
|
.status-approved {
|
|
background: #E8F5E9;
|
|
color: var(--approved);
|
|
}
|
|
|
|
.status-rejected {
|
|
background: #FFEBEE;
|
|
color: var(--rejected);
|
|
}
|
|
|
|
.action-buttons {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
.btn-approve {
|
|
background: var(--approved);
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 15px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
transition: background 0.3s;
|
|
}
|
|
|
|
.btn-approve:hover {
|
|
background: #388e3c;
|
|
}
|
|
|
|
.btn-reject {
|
|
background: var(--rejected);
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 15px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
transition: background 0.3s;
|
|
}
|
|
|
|
.btn-reject:hover {
|
|
background: #d32f2f;
|
|
}
|
|
|
|
.btn-view {
|
|
background: var(--primary);
|
|
color: white;
|
|
border: none;
|
|
padding: 8px 15px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-weight: 600;
|
|
transition: background 0.3s;
|
|
}
|
|
|
|
.btn-view:hover {
|
|
background: #c5161c;
|
|
}
|
|
|
|
.user-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 5px;
|
|
}
|
|
|
|
.user-name {
|
|
font-weight: 600;
|
|
}
|
|
|
|
.user-email {
|
|
color: var(--gray);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Events List */
|
|
.events-container {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
|
|
gap: 25px;
|
|
margin-bottom: 30px;
|
|
}
|
|
|
|
.event-admin-card {
|
|
background: white;
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
box-shadow: var(--shadow);
|
|
}
|
|
|
|
.event-admin-header {
|
|
background: var(--primary);
|
|
color: white;
|
|
padding: 15px;
|
|
}
|
|
|
|
.event-admin-header h3 {
|
|
font-size: 1.2rem;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.event-category {
|
|
display: inline-block;
|
|
background: var(--secondary);
|
|
color: white;
|
|
padding: 3px 10px;
|
|
border-radius: 15px;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.event-admin-body {
|
|
padding: 20px;
|
|
}
|
|
|
|
.event-meta {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 15px;
|
|
margin-bottom: 15px;
|
|
color: var(--gray);
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.event-meta i {
|
|
color: var(--primary);
|
|
margin-right: 5px;
|
|
}
|
|
|
|
.event-price {
|
|
background: #f8f9fa;
|
|
padding: 10px 15px;
|
|
border-radius: 8px;
|
|
margin-bottom: 20px;
|
|
border-left: 3px solid var(--primary);
|
|
}
|
|
|
|
.registrations-list {
|
|
max-height: 200px;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.registration-item {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 10px;
|
|
border-bottom: 1px solid #eee;
|
|
}
|
|
|
|
.registration-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.registration-actions {
|
|
display: flex;
|
|
gap: 5px;
|
|
}
|
|
|
|
/* Modal */
|
|
.modal {
|
|
display: none;
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: rgba(0,0,0,0.7);
|
|
z-index: 2000;
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.modal-content {
|
|
background: white;
|
|
padding: 30px;
|
|
border-radius: 10px;
|
|
width: 90%;
|
|
max-width: 500px;
|
|
max-height: 80vh;
|
|
overflow-y: auto;
|
|
}
|
|
|
|
.modal-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.modal-header h2 {
|
|
color: var(--dark);
|
|
}
|
|
|
|
.close-modal {
|
|
font-size: 1.5rem;
|
|
cursor: pointer;
|
|
color: var(--gray);
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 768px) {
|
|
.stats-grid {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.tabs {
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
table {
|
|
display: block;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.events-container {
|
|
grid-template-columns: 1fr;
|
|
}
|
|
|
|
.action-buttons {
|
|
flex-direction: column;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<!-- Login Screen -->
|
|
<div id="loginScreen" class="login-container">
|
|
<div class="login-form">
|
|
<h2><i class="fas fa-user-shield"></i> Admin Login</h2>
|
|
<form id="adminLoginForm">
|
|
<div class="form-group">
|
|
<label>Email</label>
|
|
<input type="email" id="adminEmail" placeholder="Enter admin email" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Password</label>
|
|
<input type="password" id="adminPassword" placeholder="Enter password" required>
|
|
</div>
|
|
<button type="submit" class="login-btn">Login</button>
|
|
<div id="loginError" class="error-message"></div>
|
|
</form>
|
|
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Admin Dashboard (hidden until login) -->
|
|
<div id="adminDashboard" style="display: none;">
|
|
<!-- Header -->
|
|
<header>
|
|
<div class="container">
|
|
<div class="header-content">
|
|
<div class="logo">
|
|
<i class="fas fa-user-shield"></i>
|
|
<span>Lebanon Sports Hub - Admin Panel</span>
|
|
</div>
|
|
<div class="admin-info">
|
|
<div class="admin-name" id="adminName"></div>
|
|
<button class="logout-btn" id="logoutBtn">
|
|
<i class="fas fa-sign-out-alt"></i> Logout
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Dashboard Content -->
|
|
<div class="dashboard container">
|
|
<!-- Statistics -->
|
|
<div class="stats-grid">
|
|
<div class="stat-card">
|
|
<div class="stat-icon total">
|
|
<i class="fas fa-calendar-alt"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3 id="totalEvents">22</h3>
|
|
<p>Total Events</p>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon pending">
|
|
<i class="fas fa-clock"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3 id="pendingRegistrations">0</h3>
|
|
<p>Pending Approvals</p>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon approved">
|
|
<i class="fas fa-check-circle"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3 id="approvedRegistrations">0</h3>
|
|
<p>Approved Registrations</p>
|
|
</div>
|
|
</div>
|
|
<div class="stat-card">
|
|
<div class="stat-icon rejected">
|
|
<i class="fas fa-times-circle"></i>
|
|
</div>
|
|
<div class="stat-info">
|
|
<h3 id="rejectedRegistrations">0</h3>
|
|
<p>Rejected Registrations</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Tabs -->
|
|
<div class="tabs">
|
|
<button class="tab-btn active" data-tab="pending">Pending Approvals</button>
|
|
<button class="tab-btn" data-tab="all">All Registrations</button>
|
|
<button class="tab-btn" data-tab="events">Events Management</button>
|
|
</div>
|
|
|
|
<!-- Pending Approvals Tab -->
|
|
<div id="pendingTab" class="tab-content">
|
|
<div class="table-container">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>User</th>
|
|
<th>Event</th>
|
|
<th>Location</th>
|
|
<th>Date</th>
|
|
<th>Price</th>
|
|
<th>Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="pendingTableBody">
|
|
<!-- Pending registrations loaded here -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- All Registrations Tab -->
|
|
<div id="allTab" class="tab-content" style="display: none;">
|
|
<div class="table-container">
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>User</th>
|
|
<th>Event</th>
|
|
<th>Location</th>
|
|
<th>Date</th>
|
|
<th>Price</th>
|
|
<th>Status</th>
|
|
<th>Registration Date</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="allTableBody">
|
|
<!-- All registrations loaded here -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Events Management Tab -->
|
|
<div id="eventsTab" class="tab-content" style="display: none;">
|
|
<div class="events-container" id="eventsList">
|
|
<!-- Events loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Registration Details Modal -->
|
|
<div class="modal" id="registrationModal">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h2>Registration Details</h2>
|
|
<span class="close-modal" id="closeModal">×</span>
|
|
</div>
|
|
<div id="registrationDetails">
|
|
<!-- Details loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="data.js"></script>
|
|
|
|
<script>
|
|
// Admin credentials
|
|
const ADMIN_EMAIL = 'tamernasr1717@gmail.com';
|
|
const ADMIN_PASSWORD = 'TAML76';
|
|
|
|
// App State
|
|
let adminLoggedIn = false;
|
|
let pendingRegistrations = JSON.parse(localStorage.getItem('pendingRegistrations')) || [];
|
|
let allRegistrations = JSON.parse(localStorage.getItem('allRegistrations')) || [];
|
|
let eventsData = window.sportsEventsData || [];
|
|
|
|
// DOM Elements
|
|
const loginScreen = document.getElementById('loginScreen');
|
|
const adminDashboard = document.getElementById('adminDashboard');
|
|
const adminLoginForm = document.getElementById('adminLoginForm');
|
|
const adminEmail = document.getElementById('adminEmail');
|
|
const adminPassword = document.getElementById('adminPassword');
|
|
const loginError = document.getElementById('loginError');
|
|
const logoutBtn = document.getElementById('logoutBtn');
|
|
const adminName = document.getElementById('adminName');
|
|
const tabBtns = document.querySelectorAll('.tab-btn');
|
|
const tabContents = document.querySelectorAll('.tab-content');
|
|
const pendingTableBody = document.getElementById('pendingTableBody');
|
|
const allTableBody = document.getElementById('allTableBody');
|
|
const eventsList = document.getElementById('eventsList');
|
|
const totalEvents = document.getElementById('totalEvents');
|
|
const pendingRegistrationsCount = document.getElementById('pendingRegistrations');
|
|
const approvedRegistrationsCount = document.getElementById('approvedRegistrations');
|
|
const rejectedRegistrationsCount = document.getElementById('rejectedRegistrations');
|
|
const registrationModal = document.getElementById('registrationModal');
|
|
const closeModal = document.getElementById('closeModal');
|
|
const registrationDetails = document.getElementById('registrationDetails');
|
|
|
|
// Initialize Admin App
|
|
function initAdminApp() {
|
|
loadEventsData();
|
|
setupEventListeners();
|
|
|
|
// Check if already logged in
|
|
if (localStorage.getItem('adminLoggedIn') === 'true') {
|
|
adminLoggedIn = true;
|
|
showDashboard();
|
|
}
|
|
}
|
|
|
|
// Load events data
|
|
function loadEventsData() {
|
|
// Get events from shared data.js file
|
|
if (typeof sportsEventsData !== 'undefined' && sportsEventsData.length > 0) {
|
|
eventsData = sportsEventsData;
|
|
} else {
|
|
// Fallback: get from localStorage
|
|
eventsData = JSON.parse(localStorage.getItem('sportsEvents')) || [];
|
|
}
|
|
|
|
// Load pending and all registrations
|
|
pendingRegistrations = JSON.parse(localStorage.getItem('pendingRegistrations')) || [];
|
|
allRegistrations = JSON.parse(localStorage.getItem('allRegistrations')) || [];
|
|
|
|
// Update total events count
|
|
totalEvents.textContent = eventsData.length;
|
|
|
|
updateStats();
|
|
}
|
|
|
|
// Update Statistics
|
|
function updateStats() {
|
|
totalEvents.textContent = eventsData.length || 0;
|
|
pendingRegistrationsCount.textContent = pendingRegistrations.length;
|
|
|
|
const approved = allRegistrations.filter(r => r.status === 'approved').length;
|
|
const rejected = allRegistrations.filter(r => r.status === 'rejected').length;
|
|
|
|
approvedRegistrationsCount.textContent = approved;
|
|
rejectedRegistrationsCount.textContent = rejected;
|
|
}
|
|
|
|
// Show Pending Registrations
|
|
function showPendingRegistrations() {
|
|
pendingTableBody.innerHTML = '';
|
|
|
|
if (pendingRegistrations.length === 0) {
|
|
pendingTableBody.innerHTML = `
|
|
<tr>
|
|
<td colspan="7" style="text-align: center; padding: 40px; color: var(--gray);">
|
|
<i class="fas fa-check-circle" style="font-size: 2rem; margin-bottom: 10px; display: block; color: #ddd;"></i>
|
|
No pending registrations
|
|
</td>
|
|
</tr>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
pendingRegistrations.forEach(reg => {
|
|
const event = eventsData.find(e => e.id === reg.eventId);
|
|
if (!event) return;
|
|
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td>
|
|
<div class="user-info">
|
|
<div class="user-name">${reg.userName || 'Unknown User'}</div>
|
|
<div class="user-email">${reg.userEmail || 'No email'}</div>
|
|
</div>
|
|
</td>
|
|
<td>${event.title}</td>
|
|
<td>${event.location}</td>
|
|
<td>${event.date}</td>
|
|
<td>${event.price === 0 ? 'FREE' : '$' + event.price}</td>
|
|
<td><span class="status-badge status-pending">PENDING</span></td>
|
|
<td>
|
|
<div class="action-buttons">
|
|
<button class="btn-approve" onclick="approveRegistration('${reg.registrationId}')">
|
|
<i class="fas fa-check"></i> Approve
|
|
</button>
|
|
<button class="btn-reject" onclick="rejectRegistration('${reg.registrationId}')">
|
|
<i class="fas fa-times"></i> Reject
|
|
</button>
|
|
<button class="btn-view" onclick="viewRegistrationDetails('${reg.registrationId}')">
|
|
<i class="fas fa-eye"></i> View
|
|
</button>
|
|
</div>
|
|
</td>
|
|
`;
|
|
pendingTableBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
// Show All Registrations
|
|
function showAllRegistrations() {
|
|
allTableBody.innerHTML = '';
|
|
|
|
if (allRegistrations.length === 0) {
|
|
allTableBody.innerHTML = `
|
|
<tr>
|
|
<td colspan="7" style="text-align: center; padding: 40px; color: var(--gray);">
|
|
<i class="fas fa-users" style="font-size: 2rem; margin-bottom: 10px; display: block; color: #ddd;"></i>
|
|
No registrations yet
|
|
</td>
|
|
</tr>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
allRegistrations.forEach(reg => {
|
|
const event = eventsData.find(e => e.id === reg.eventId);
|
|
if (!event) return;
|
|
|
|
let statusClass = 'status-pending';
|
|
let statusText = 'PENDING';
|
|
|
|
if (reg.status === 'approved') {
|
|
statusClass = 'status-approved';
|
|
statusText = 'APPROVED';
|
|
} else if (reg.status === 'rejected') {
|
|
statusClass = 'status-rejected';
|
|
statusText = 'REJECTED';
|
|
}
|
|
|
|
const row = document.createElement('tr');
|
|
row.innerHTML = `
|
|
<td>
|
|
<div class="user-info">
|
|
<div class="user-name">${reg.userName || 'Unknown User'}</div>
|
|
<div class="user-email">${reg.userEmail || 'No email'}</div>
|
|
</div>
|
|
</td>
|
|
<td>${event.title}</td>
|
|
<td>${event.location}</td>
|
|
<td>${event.date}</td>
|
|
<td>${event.price === 0 ? 'FREE' : '$' + event.price}</td>
|
|
<td><span class="status-badge ${statusClass}">${statusText}</span></td>
|
|
<td>${reg.registrationDate || 'Unknown'}</td>
|
|
`;
|
|
allTableBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
// Show Events Management
|
|
function showEventsManagement() {
|
|
eventsList.innerHTML = '';
|
|
|
|
console.log('Total events:', eventsData.length);
|
|
|
|
if (eventsData.length === 0) {
|
|
eventsList.innerHTML = `
|
|
<div style="grid-column: 1/-1; text-align: center; padding: 40px; color: var(--gray);">
|
|
<i class="fas fa-calendar-times" style="font-size: 3rem; margin-bottom: 20px; display: block;"></i>
|
|
<h3>No events found</h3>
|
|
<p>Make sure data.js file is loaded correctly.</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
eventsData.forEach(event => {
|
|
const eventRegistrations = allRegistrations.filter(r => r.eventId === event.id);
|
|
const pendingCount = eventRegistrations.filter(r => r.status === 'pending').length;
|
|
const approvedCount = eventRegistrations.filter(r => r.status === 'approved').length;
|
|
|
|
const card = document.createElement('div');
|
|
card.className = 'event-admin-card';
|
|
card.innerHTML = `
|
|
<div class="event-admin-header">
|
|
<h3>${event.title}</h3>
|
|
<span class="event-category">${event.category}</span>
|
|
</div>
|
|
<div class="event-admin-body">
|
|
<div class="event-meta">
|
|
<div><i class="fas fa-map-marker-alt"></i> ${event.location}</div>
|
|
<div><i class="fas fa-calendar-alt"></i> ${event.date}</div>
|
|
<div><i class="fas fa-clock"></i> ${event.time}</div>
|
|
</div>
|
|
<div class="event-price">
|
|
<i class="fas fa-tag"></i> Price: ${event.price === 0 ? 'FREE' : '$' + event.price}
|
|
</div>
|
|
|
|
<div style="display: flex; justify-content: space-between; margin-bottom: 15px; padding: 10px; background: #f8f9fa; border-radius: 5px;">
|
|
<div>
|
|
<small>Total Registrations</small>
|
|
<div style="font-weight: 600; font-size: 1.2rem;">${eventRegistrations.length}</div>
|
|
</div>
|
|
<div>
|
|
<small>Pending</small>
|
|
<div style="font-weight: 600; color: var(--pending);">${pendingCount}</div>
|
|
</div>
|
|
<div>
|
|
<small>Approved</small>
|
|
<div style="font-weight: 600; color: var(--approved);">${approvedCount}</div>
|
|
</div>
|
|
</div>
|
|
|
|
${eventRegistrations.length > 0 ? `
|
|
<h4 style="margin-bottom: 10px; font-size: 1rem;">Recent Registrations:</h4>
|
|
<div class="registrations-list">
|
|
${eventRegistrations.slice(0, 3).map(reg => `
|
|
<div class="registration-item">
|
|
<div>
|
|
<div style="font-weight: 600;">${reg.userName || 'Unknown'}</div>
|
|
<small>${reg.registrationDate || 'Unknown date'}</small>
|
|
</div>
|
|
<div>
|
|
${reg.status === 'pending' ?
|
|
'<span style="color: var(--pending); font-weight: 600;">Pending</span>' :
|
|
reg.status === 'approved' ?
|
|
'<span style="color: var(--approved); font-weight: 600;">Approved</span>' :
|
|
'<span style="color: var(--rejected); font-weight: 600;">Rejected</span>'
|
|
}
|
|
</div>
|
|
</div>
|
|
`).join('')}
|
|
</div>
|
|
` : `
|
|
<div style="text-align: center; color: var(--gray); padding: 20px;">
|
|
<i class="fas fa-users" style="font-size: 2rem; margin-bottom: 10px; display: block;"></i>
|
|
No registrations yet
|
|
</div>
|
|
`}
|
|
</div>
|
|
`;
|
|
eventsList.appendChild(card);
|
|
});
|
|
}
|
|
|
|
// Approve Registration
|
|
function approveRegistration(registrationId) {
|
|
const regIndex = pendingRegistrations.findIndex(r => r.registrationId === registrationId);
|
|
if (regIndex === -1) return;
|
|
|
|
const registration = pendingRegistrations[regIndex];
|
|
|
|
// Update registration status
|
|
registration.status = 'approved';
|
|
registration.approvedDate = new Date().toLocaleString();
|
|
|
|
// Move to all registrations
|
|
const existingIndex = allRegistrations.findIndex(r => r.registrationId === registrationId);
|
|
if (existingIndex === -1) {
|
|
allRegistrations.push(registration);
|
|
} else {
|
|
allRegistrations[existingIndex] = registration;
|
|
}
|
|
|
|
// Remove from pending
|
|
pendingRegistrations.splice(regIndex, 1);
|
|
|
|
// Update localStorage
|
|
localStorage.setItem('pendingRegistrations', JSON.stringify(pendingRegistrations));
|
|
localStorage.setItem('allRegistrations', JSON.stringify(allRegistrations));
|
|
|
|
// Update user's localStorage (to notify them)
|
|
notifyUserRegistration(registration.userId, registration.eventId, 'approved');
|
|
|
|
// Update UI
|
|
updateStats();
|
|
showPendingRegistrations();
|
|
showAllRegistrations();
|
|
|
|
alert('Registration approved successfully!');
|
|
}
|
|
|
|
// Reject Registration
|
|
function rejectRegistration(registrationId) {
|
|
const regIndex = pendingRegistrations.findIndex(r => r.registrationId === registrationId);
|
|
if (regIndex === -1) return;
|
|
|
|
const registration = pendingRegistrations[regIndex];
|
|
|
|
// Update registration status
|
|
registration.status = 'rejected';
|
|
registration.rejectedDate = new Date().toLocaleString();
|
|
|
|
// Move to all registrations
|
|
const existingIndex = allRegistrations.findIndex(r => r.registrationId === registrationId);
|
|
if (existingIndex === -1) {
|
|
allRegistrations.push(registration);
|
|
} else {
|
|
allRegistrations[existingIndex] = registration;
|
|
}
|
|
|
|
// Remove from pending
|
|
pendingRegistrations.splice(regIndex, 1);
|
|
|
|
// Update localStorage
|
|
localStorage.setItem('pendingRegistrations', JSON.stringify(pendingRegistrations));
|
|
localStorage.setItem('allRegistrations', JSON.stringify(allRegistrations));
|
|
|
|
// Update user's localStorage (to notify them)
|
|
notifyUserRegistration(registration.userId, registration.eventId, 'rejected');
|
|
|
|
// Update UI
|
|
updateStats();
|
|
showPendingRegistrations();
|
|
showAllRegistrations();
|
|
|
|
alert('Registration rejected!');
|
|
}
|
|
|
|
// View Registration Details
|
|
function viewRegistrationDetails(registrationId) {
|
|
const registration = [...pendingRegistrations, ...allRegistrations].find(r => r.registrationId === registrationId);
|
|
if (!registration) return;
|
|
|
|
const event = eventsData.find(e => e.id === registration.eventId);
|
|
|
|
registrationDetails.innerHTML = `
|
|
<div style="margin-bottom: 20px;">
|
|
<h3 style="color: var(--dark); margin-bottom: 10px;">${event ? event.title : 'Event not found'}</h3>
|
|
<p><strong>Registration ID:</strong> ${registration.registrationId}</p>
|
|
<p><strong>Registration Date:</strong> ${registration.registrationDate}</p>
|
|
</div>
|
|
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
|
<h4 style="margin-bottom: 10px; color: var(--dark);">User Information</h4>
|
|
<p><strong>Name:</strong> ${registration.userName || 'Not provided'}</p>
|
|
<p><strong>Email:</strong> ${registration.userEmail || 'Not provided'}</p>
|
|
<p><strong>User ID:</strong> ${registration.userId || 'Not available'}</p>
|
|
</div>
|
|
|
|
${event ? `
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px; margin-bottom: 20px;">
|
|
<h4 style="margin-bottom: 10px; color: var(--dark);">Event Details</h4>
|
|
<p><strong>Location:</strong> ${event.location}</p>
|
|
<p><strong>Date:</strong> ${event.date} at ${event.time}</p>
|
|
<p><strong>Venue:</strong> ${event.venue}</p>
|
|
<p><strong>Price:</strong> ${event.price === 0 ? 'FREE' : '$' + event.price}</p>
|
|
</div>
|
|
` : ''}
|
|
|
|
<div style="background: #f8f9fa; padding: 15px; border-radius: 8px;">
|
|
<h4 style="margin-bottom: 10px; color: var(--dark);">Registration Status</h4>
|
|
<p><strong>Status:</strong> <span style="color: ${
|
|
registration.status === 'approved' ? 'var(--approved)' :
|
|
registration.status === 'rejected' ? 'var(--rejected)' :
|
|
'var(--pending)'
|
|
}; font-weight: 600;">${registration.status ? registration.status.toUpperCase() : 'PENDING'}</span></p>
|
|
${registration.approvedDate ? `<p><strong>Approved Date:</strong> ${registration.approvedDate}</p>` : ''}
|
|
${registration.rejectedDate ? `<p><strong>Rejected Date:</strong> ${registration.rejectedDate}</p>` : ''}
|
|
</div>
|
|
|
|
${registration.status === 'pending' ? `
|
|
<div style="display: flex; gap: 10px; margin-top: 20px;">
|
|
<button class="btn-approve" style="flex: 1;" onclick="approveRegistration('${registration.registrationId}')">
|
|
<i class="fas fa-check"></i> Approve Registration
|
|
</button>
|
|
<button class="btn-reject" style="flex: 1;" onclick="rejectRegistration('${registration.registrationId}')">
|
|
<i class="fas fa-times"></i> Reject Registration
|
|
</button>
|
|
</div>
|
|
` : ''}
|
|
`;
|
|
|
|
registrationModal.style.display = 'flex';
|
|
}
|
|
|
|
// Notify User about Registration Status
|
|
function notifyUserRegistration(userId, eventId, status) {
|
|
// Create notification for user
|
|
const notification = {
|
|
userId: userId,
|
|
eventId: eventId,
|
|
status: status,
|
|
notificationDate: new Date().toLocaleString(),
|
|
read: false
|
|
};
|
|
|
|
// Get existing notifications
|
|
let userNotifications = JSON.parse(localStorage.getItem('userNotifications')) || [];
|
|
userNotifications.push(notification);
|
|
|
|
// Save notifications
|
|
localStorage.setItem('userNotifications', JSON.stringify(userNotifications));
|
|
}
|
|
|
|
// Setup Event Listeners
|
|
function setupEventListeners() {
|
|
// Admin Login
|
|
adminLoginForm.addEventListener('submit', function(e) {
|
|
e.preventDefault();
|
|
|
|
const email = adminEmail.value.trim();
|
|
const password = adminPassword.value.trim();
|
|
|
|
if (email === ADMIN_EMAIL && password === ADMIN_PASSWORD) {
|
|
adminLoggedIn = true;
|
|
localStorage.setItem('adminLoggedIn', 'true');
|
|
showDashboard();
|
|
loginError.textContent = '';
|
|
} else {
|
|
loginError.textContent = 'Invalid email or password';
|
|
}
|
|
});
|
|
|
|
// Logout
|
|
logoutBtn.addEventListener('click', function() {
|
|
adminLoggedIn = false;
|
|
localStorage.removeItem('adminLoggedIn');
|
|
showLoginScreen();
|
|
});
|
|
|
|
// Tab Navigation
|
|
tabBtns.forEach(btn => {
|
|
btn.addEventListener('click', function() {
|
|
const tabId = this.getAttribute('data-tab');
|
|
|
|
// Update active tab button
|
|
tabBtns.forEach(b => b.classList.remove('active'));
|
|
this.classList.add('active');
|
|
|
|
// Show corresponding tab content
|
|
tabContents.forEach(content => {
|
|
content.style.display = 'none';
|
|
});
|
|
|
|
document.getElementById(tabId + 'Tab').style.display = 'block';
|
|
|
|
// Load appropriate data
|
|
if (tabId === 'pending') {
|
|
showPendingRegistrations();
|
|
} else if (tabId === 'all') {
|
|
showAllRegistrations();
|
|
} else if (tabId === 'events') {
|
|
showEventsManagement();
|
|
}
|
|
});
|
|
});
|
|
|
|
// Close modal
|
|
closeModal.addEventListener('click', () => {
|
|
registrationModal.style.display = 'none';
|
|
});
|
|
|
|
// Close modal on outside click
|
|
window.addEventListener('click', (e) => {
|
|
if (e.target === registrationModal) {
|
|
registrationModal.style.display = 'none';
|
|
}
|
|
});
|
|
}
|
|
|
|
// Show Dashboard
|
|
function showDashboard() {
|
|
loginScreen.style.display = 'none';
|
|
adminDashboard.style.display = 'block';
|
|
adminName.textContent = 'Admin: tamernasr1717@gmail.com';
|
|
|
|
// Load initial data
|
|
updateStats();
|
|
showPendingRegistrations();
|
|
showAllRegistrations();
|
|
showEventsManagement();
|
|
}
|
|
|
|
// Show Login Screen
|
|
function showLoginScreen() {
|
|
loginScreen.style.display = 'flex';
|
|
adminDashboard.style.display = 'none';
|
|
adminLoginForm.reset();
|
|
}
|
|
|
|
// Initialize on load
|
|
document.addEventListener('DOMContentLoaded', initAdminApp);
|
|
</script>
|
|
</body>
|
|
</html> |