38458-vm/view_election.php
Flatlogic Bot 5ac812ef05 Final3
2026-02-16 03:29:05 +00:00

294 lines
18 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/auth_helper.php';
require_login();
$user = get_user();
$id = $_GET['id'] ?? '';
if (!$id) {
header("Location: index.php");
exit;
}
$pdo = db();
$stmt = $pdo->prepare("SELECT * FROM elections WHERE id = ?");
$stmt->execute([$id]);
$election = $stmt->fetch();
if (!$election) {
die("Election not found.");
}
$positions = $pdo->prepare("SELECT * FROM positions WHERE election_id = ? ORDER BY sort_order ASC");
$positions->execute([$id]);
$positions = $positions->fetchAll();
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System';
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title><?= htmlspecialchars($election['title']) ?> | Manage</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/dashboard.css?v=<?= time() ?>">
<script src="https://unpkg.com/lucide@latest"></script>
</head>
<body class="dashboard-body <?= ($user['theme'] ?? 'light') === 'dark' ? 'dark-theme' : '' ?>">
<?php require_once 'includes/sidebar.php'; ?>
<div class="main-wrapper">
<?php require_once 'includes/header.php'; ?>
<main class="dashboard-content animate-fade-in">
<div class="dashboard-header" style="align-items: center;">
<div>
<h1 style="margin: 0; font-size: 1.75rem; color: #1e293b;"><?= htmlspecialchars($election['title']) ?></h1>
<p class="welcome-msg" style="margin-top: 4px;"><?= htmlspecialchars($election['description']) ?></p>
</div>
<div style="display: flex; gap: 12px;">
<?php if (in_array($user['role'], ['Admin', 'Adviser', 'Officer'])): ?>
<button class="btn-action" style="background: #ffffff; border: 1px solid #e2e8f0; color: #4b5563; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 8px;" onclick="document.getElementById('editElectionModal').style.display='flex'">
<i data-lucide="edit-3" style="width: 16px;"></i>
Edit Info
</button>
<?php if ($election['status'] === 'Preparing'): ?>
<form action="api/update_election_status.php" method="POST">
<input type="hidden" name="id" value="<?= $election['id'] ?>">
<input type="hidden" name="status" value="Ongoing">
<button type="submit" class="btn-action" style="background: #166534; color: white; padding: 10px 20px; border: none; border-radius: 8px; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 8px;">
<i data-lucide="play" style="width: 16px;"></i>
Launch Election
</button>
</form>
<?php elseif ($election['status'] === 'Ongoing'): ?>
<form action="api/update_election_status.php" method="POST">
<input type="hidden" name="id" value="<?= $election['id'] ?>">
<input type="hidden" name="status" value="Finished">
<button type="submit" class="btn-action" style="background: #ef4444; color: white; padding: 10px 20px; border: none; border-radius: 8px; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 8px;">
<i data-lucide="square" style="width: 16px;"></i>
End Election
</button>
</form>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
<div class="stats-grid" style="grid-template-columns: repeat(3, 1fr); margin-bottom: 24px;">
<div class="stat-card">
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
<div style="background: #eef2ff; padding: 10px; border-radius: 10px; color: #4f46e5;">
<i data-lucide="check-square"></i>
</div>
<span style="font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em;">Status</span>
</div>
<div style="display: flex; align-items: center; gap: 8px;">
<span class="status-indicator <?= strtolower($election['status']) ?>" style="padding: 4px 12px; border-radius: 9999px; font-size: 0.875rem; font-weight: 600; background: <?= $election['status'] === 'Ongoing' ? '#dcfce7' : ($election['status'] === 'Preparing' ? '#fef9c3' : '#f1f5f9') ?>; color: <?= $election['status'] === 'Ongoing' ? '#166534' : ($election['status'] === 'Preparing' ? '#854d0e' : '#475569') ?>;">
<?= $election['status'] ?>
</span>
</div>
</div>
<div class="stat-card">
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
<div style="background: #fff7ed; padding: 10px; border-radius: 10px; color: #f97316;">
<i data-lucide="calendar"></i>
</div>
<span style="font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em;">Election Period</span>
</div>
<div style="font-size: 0.875rem; font-weight: 600; color: #1e293b;">
<?= date('M d, H:i', strtotime($election['start_date_and_time'])) ?> — <?= date('M d, H:i', strtotime($election['end_date_and_time'])) ?>
</div>
</div>
<div class="stat-card">
<div style="display: flex; align-items: center; gap: 12px; margin-bottom: 16px;">
<div style="background: #ecfdf5; padding: 10px; border-radius: 10px; color: #10b981;">
<i data-lucide="users"></i>
</div>
<span style="font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em;">Total Participation</span>
</div>
<?php
$vStmt = $pdo->prepare("SELECT COUNT(DISTINCT voter_id) FROM votes WHERE election_id = ?");
$vStmt->execute([$id]);
$votesCount = $vStmt->fetchColumn();
?>
<div style="font-size: 1.5rem; font-weight: 800; color: #1e293b;"><?= $votesCount ?> <small style="font-size: 0.875rem; color: #64748b; font-weight: 500;">Votes Cast</small></div>
</div>
</div>
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 24px;">
<div style="background: #ffffff; border: 1px solid #f3f4f6; border-radius: 16px; overflow: hidden;">
<div style="padding: 24px; border-bottom: 1px solid #f3f4f6; display: flex; justify-content: space-between; align-items: center;">
<h2 style="margin: 0; font-size: 1.1rem; color: #1e293b; font-weight: 700;">Positions & Structure</h2>
<?php if ($election['status'] === 'Preparing'): ?>
<button onclick="document.getElementById('addPositionForm').style.display='block'" style="background: #4f46e5; color: white; border: none; padding: 8px 16px; border-radius: 8px; font-size: 0.875rem; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 6px;">
<i data-lucide="plus" style="width: 14px;"></i>
Add Position
</button>
<?php endif; ?>
</div>
<div id="addPositionForm" style="display:none; margin: 24px; padding: 20px; background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 12px;">
<form action="api/add_position.php" method="POST">
<input type="hidden" name="election_id" value="<?= $election['id'] ?>">
<div style="display: grid; grid-template-columns: 2fr 1fr auto; gap: 16px; align-items: flex-end;">
<div>
<label style="display:block; font-size: 0.75rem; font-weight: 600; color: #64748b; margin-bottom: 6px;">Position Name</label>
<input type="text" name="name" style="width: 100%; padding: 10px; border: 1px solid #e2e8f0; border-radius: 8px; outline: none;" placeholder="e.g. President" required>
</div>
<div>
<label style="display:block; font-size: 0.75rem; font-weight: 600; color: #64748b; margin-bottom: 6px;">Max Votes</label>
<input type="number" name="max_votes" style="width: 100%; padding: 10px; border: 1px solid #e2e8f0; border-radius: 8px; outline: none;" value="1" min="1">
</div>
<div style="display: flex; gap: 8px;">
<button type="submit" style="background: #2563eb; color: white; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer;">Save</button>
<button type="button" onclick="document.getElementById('addPositionForm').style.display='none'" style="background: #f1f5f9; color: #475569; border: none; padding: 10px 20px; border-radius: 8px; font-weight: 600; cursor: pointer;">Cancel</button>
</div>
</div>
</form>
</div>
<div style="overflow-x: auto;">
<table style="width: 100%; border-collapse: collapse;">
<thead>
<tr style="background: #f9fafb; border-bottom: 1px solid #f3f4f6;">
<th style="padding: 12px 24px; text-align: left; font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase;">Position Name</th>
<th style="padding: 12px 24px; text-align: left; font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase;">Max Votes</th>
<th style="padding: 12px 24px; text-align: left; font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase;">Candidates</th>
<th style="padding: 12px 24px; text-align: right; font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase;">Actions</th>
</tr>
</thead>
<tbody>
<?php if (empty($positions)): ?>
<tr>
<td colspan="4" style="padding: 48px; text-align: center; color: #94a3b8;">
<div style="display: flex; flex-direction: column; align-items: center; gap: 12px;">
<i data-lucide="layers" style="width: 48px; height: 48px; color: #e2e8f0;"></i>
<span>No positions defined yet. Start by adding one.</span>
</div>
</td>
</tr>
<?php else: ?>
<?php foreach ($positions as $pos):
$cStmt = $pdo->prepare("SELECT COUNT(*) FROM candidates WHERE position_id = ?");
$cStmt->execute([$pos['id']]);
$cCount = $cStmt->fetchColumn();
?>
<tr style="border-bottom: 1px solid #f3f4f6; transition: background 0.2s;" onmouseover="this.style.background='#f8fafc'" onmouseout="this.style.background='transparent'">
<td style="padding: 16px 24px; font-weight: 600; color: #1e293b;"><?= htmlspecialchars($pos['name']) ?></td>
<td style="padding: 16px 24px; color: #4b5563;">
<span style="background: #f1f5f9; padding: 4px 10px; border-radius: 6px; font-size: 0.75rem; font-weight: 600;"><?= $pos['max_votes'] ?> Vote<?= $pos['max_votes'] > 1 ? 's' : '' ?></span>
</td>
<td style="padding: 16px 24px;">
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 8px; height: 8px; border-radius: 50%; background: #10b981;"></div>
<span style="font-weight: 600; color: #1e293b;"><?= $cCount ?></span>
</div>
</td>
<td style="padding: 16px 24px; text-align: right;">
<a href="manage_candidates.php?position_id=<?= $pos['id'] ?>" style="color: #4f46e5; text-decoration: none; font-size: 0.875rem; font-weight: 600; display: inline-flex; align-items: center; gap: 6px;">
Manage Candidates
<i data-lucide="arrow-right" style="width: 14px;"></i>
</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
<div style="display: flex; flex-direction: column; gap: 24px;">
<div style="background: #ffffff; border: 1px solid #f3f4f6; border-radius: 16px; padding: 24px;">
<h2 style="margin-top: 0; font-size: 1.1rem; color: #1e293b; font-weight: 700; margin-bottom: 20px;">Quick Stats</h2>
<div style="display: flex; flex-direction: column; gap: 20px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em;">Total Candidates</div>
<?php
$canStmt = $pdo->prepare("SELECT COUNT(*) FROM candidates WHERE election_id = ?");
$canStmt->execute([$id]);
$candidatesTotal = $canStmt->fetchColumn();
?>
<div style="font-size: 1.5rem; font-weight: 800; color: #1e293b;"><?= $candidatesTotal ?></div>
</div>
<div style="background: #fef2f2; padding: 12px; border-radius: 12px; color: #ef4444;">
<i data-lucide="user-check"></i>
</div>
</div>
<div style="display: flex; justify-content: space-between; align-items: center;">
<div>
<div style="font-size: 0.7rem; color: #64748b; text-transform: uppercase; font-weight: 700; letter-spacing: 0.05em;">Voter Turnout</div>
<div style="font-size: 1.5rem; font-weight: 800; color: #1e293b;"><?= $votesCount ?></div>
</div>
<div style="background: #f0fdf4; padding: 12px; border-radius: 12px; color: #22c55e;">
<i data-lucide="bar-chart-3"></i>
</div>
</div>
</div>
</div>
<div style="background: linear-gradient(135deg, #4f46e5 0%, #3730a3 100%); border-radius: 16px; padding: 24px; color: white;">
<h3 style="margin: 0; font-size: 1rem; font-weight: 700; margin-bottom: 12px;">Need Help?</h3>
<p style="font-size: 0.875rem; opacity: 0.9; margin-bottom: 20px;">Manage your election structure by adding positions and assigning candidates to them. Once ready, you can launch the election.</p>
<a href="reports_audit.php" style="display: block; width: 100%; text-align: center; background: white; color: #4f46e5; padding: 12px; border-radius: 8px; font-weight: 700; text-decoration: none; font-size: 0.875rem;">View Reports</a>
</div>
</div>
</div>
</main>
</div>
<div id="editElectionModal" class="modal">
<div class="modal-content animate-scale-in" style="max-width: 550px;">
<div class="modal-header">
<h2 style="font-weight: 800;">Edit Election Details</h2>
<button type="button" onclick="document.getElementById('editElectionModal').style.display='none'" class="close-btn">&times;</button>
</div>
<form action="api/update_election.php" method="POST">
<input type="hidden" name="id" value="<?= $election['id'] ?>">
<div class="form-group" style="margin-bottom: 20px;">
<label>Election Title</label>
<input type="text" name="title" value="<?= htmlspecialchars($election['title']) ?>" style="width: 100%; padding: 12px; border: 1px solid #e2e8f0; border-radius: 10px; outline: none;" required>
</div>
<div class="form-group" style="margin-bottom: 20px;">
<label>Description</label>
<textarea name="description" rows="3" style="width: 100%; padding: 12px; border: 1px solid #e2e8f0; border-radius: 10px; outline: none; font-family: inherit;"><?= htmlspecialchars($election['description']) ?></textarea>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 32px;">
<div class="form-group">
<label>Start Date & Time</label>
<input type="datetime-local" name="start_date" value="<?= date('Y-m-d\TH:i', strtotime($election['start_date_and_time'])) ?>" style="width: 100%; padding: 12px; border: 1px solid #e2e8f0; border-radius: 10px; outline: none;" required>
</div>
<div class="form-group">
<label>End Date & Time</label>
<input type="datetime-local" name="end_date" value="<?= date('Y-m-d\TH:i', strtotime($election['end_date_and_time'])) ?>" style="width: 100%; padding: 12px; border: 1px solid #e2e8f0; border-radius: 10px; outline: none;" required>
</div>
</div>
<div class="modal-footer">
<button type="button" onclick="document.getElementById('editElectionModal').style.display='none'" class="btn-cancel">Cancel</button>
<button type="submit" class="btn-submit" style="background: #4f46e5;">Save Changes</button>
</div>
</form>
</div>
</div>
<script>
lucide.createIcons();
window.onclick = function(event) {
if (event.target.id === 'editElectionModal') {
event.target.style.display = 'none';
}
}
</script>
</body>
</html>