215 lines
10 KiB
PHP
215 lines
10 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/style.css?v=<?= time() ?>">
|
|
</head>
|
|
<body>
|
|
<nav class="navbar">
|
|
<a href="index.php" class="brand">E-Vote Pro</a>
|
|
<div>
|
|
<span style="margin-right: 1rem; color: var(--text-muted);"><?= htmlspecialchars($user['name']) ?></span>
|
|
<a href="index.php" class="btn btn-outline">Back to Dashboard</a>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container">
|
|
<div class="card">
|
|
<div style="display: flex; justify-content: space-between; align-items: flex-start;">
|
|
<div>
|
|
<h1 style="margin: 0; font-size: 1.5rem;"><?= htmlspecialchars($election['title']) ?></h1>
|
|
<p style="margin: 0.5rem 0; color: var(--text-muted);"><?= htmlspecialchars($election['description']) ?></p>
|
|
<div style="margin-top: 1rem; font-size: 0.875rem;">
|
|
<strong>Status:</strong> <span class="badge badge-<?= strtolower($election['status']) ?>"><?= $election['status'] ?></span> |
|
|
<strong>Period:</strong> <?= date('M d, H:i', strtotime($election['start_date_and_time'])) ?> to <?= date('M d, H:i', strtotime($election['end_date_and_time'])) ?>
|
|
</div>
|
|
</div>
|
|
<div style="display: flex; gap: 0.5rem;">
|
|
<?php if (in_array($user['role'], ['Admin', 'Adviser', 'Officer'])): ?>
|
|
<button class="btn btn-outline" onclick="document.getElementById('editElectionModal').style.display='flex'">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 btn-primary" style="background: #166534;">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 btn-primary" style="background: #ef4444;">End Election</button>
|
|
</form>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="display: grid; grid-template-columns: 2fr 1fr; gap: 1.5rem;">
|
|
<div>
|
|
<div class="card">
|
|
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
|
|
<h2 style="margin: 0; font-size: 1.1rem;">Positions</h2>
|
|
<?php if ($election['status'] === 'Preparing'): ?>
|
|
<button onclick="document.getElementById('addPositionForm').style.display='block'" class="btn btn-outline" style="padding: 0.25rem 0.5rem; font-size: 0.75rem;">+ Add Position</button>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div id="addPositionForm" style="display:none; margin-bottom: 1.5rem; padding: 1rem; background: #f8fafc; border-radius: 8px;">
|
|
<form action="api/add_position.php" method="POST">
|
|
<input type="hidden" name="election_id" value="<?= $election['id'] ?>">
|
|
<div style="display: flex; gap: 0.5rem; align-items: flex-end;">
|
|
<div style="flex: 2;">
|
|
<label style="display:block; font-size: 0.75rem;">Position Name</label>
|
|
<input type="text" name="name" class="form-control" placeholder="e.g. President" required>
|
|
</div>
|
|
<div style="flex: 1;">
|
|
<label style="display:block; font-size: 0.75rem;">Max Votes</label>
|
|
<input type="number" name="max_votes" class="form-control" value="1" min="1">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary">Save</button>
|
|
<button type="button" onclick="document.getElementById('addPositionForm').style.display='none'" class="btn btn-outline">Cancel</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<?php if (empty($positions)): ?>
|
|
<div style="text-align: center; padding: 1.5rem; border: 1px dashed var(--border-color); border-radius: var(--radius);">
|
|
<p style="color: var(--text-muted); margin: 0;">No positions defined yet.</p>
|
|
</div>
|
|
<?php else: ?>
|
|
<table class="table">
|
|
<thead>
|
|
<tr>
|
|
<th>Position Name</th>
|
|
<th>Max Votes</th>
|
|
<th>Candidates</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($positions as $pos):
|
|
$cStmt = $pdo->prepare("SELECT COUNT(*) FROM candidates WHERE position_id = ?");
|
|
$cStmt->execute([$pos['id']]);
|
|
$cCount = $cStmt->fetchColumn();
|
|
?>
|
|
<tr>
|
|
<td><?= htmlspecialchars($pos['name']) ?></td>
|
|
<td><?= $pos['max_votes'] ?></td>
|
|
<td><?= $cCount ?></td>
|
|
<td>
|
|
<a href="manage_candidates.php?position_id=<?= $pos['id'] ?>" class="btn btn-outline" style="padding: 0.25rem 0.5rem; font-size: 0.75rem;">Candidates</a>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div class="card">
|
|
<h2 style="margin-top: 0; font-size: 1.1rem;">Quick Stats</h2>
|
|
<?php
|
|
$vStmt = $pdo->prepare("SELECT COUNT(DISTINCT voter_id) FROM votes WHERE election_id = ?");
|
|
$vStmt->execute([$id]);
|
|
$votesCount = $vStmt->fetchColumn();
|
|
?>
|
|
<div style="margin-bottom: 1rem;">
|
|
<div style="font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; font-weight: 600;">Total Votes Cast</div>
|
|
<div style="font-size: 1.5rem; font-weight: 700;"><?= $votesCount ?></div>
|
|
</div>
|
|
<div style="margin-bottom: 1rem;">
|
|
<?php
|
|
$canStmt = $pdo->prepare("SELECT COUNT(*) FROM candidates WHERE election_id = ?");
|
|
$canStmt->execute([$id]);
|
|
$candidatesTotal = $canStmt->fetchColumn();
|
|
?>
|
|
<div style="font-size: 0.75rem; color: var(--text-muted); text-transform: uppercase; font-weight: 600;">Total Candidates</div>
|
|
<div style="font-size: 1.5rem; font-weight: 700;"><?= $candidatesTotal ?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div id="editElectionModal" class="modal" style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.5); z-index:1000; align-items:center; justify-content:center;">
|
|
<div class="card" style="width: 100%; max-width: 500px; padding: 2rem;">
|
|
<h2 style="margin-top: 0; font-size: 1.25rem;">Edit Election</h2>
|
|
<form action="api/update_election.php" method="POST">
|
|
<input type="hidden" name="id" value="<?= $election['id'] ?>">
|
|
<div class="form-group">
|
|
<label class="form-label">Election Title</label>
|
|
<input type="text" name="title" class="form-control" value="<?= htmlspecialchars($election['title']) ?>" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">Description</label>
|
|
<textarea name="description" class="form-control" rows="3"><?= htmlspecialchars($election['description']) ?></textarea>
|
|
</div>
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-bottom: 1.5rem;">
|
|
<div class="form-group">
|
|
<label class="form-label">Start Date</label>
|
|
<input type="datetime-local" name="start_date" class="form-control" value="<?= date('Y-m-d\TH:i', strtotime($election['start_date_and_time'])) ?>" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="form-label">End Date</label>
|
|
<input type="datetime-local" name="end_date" class="form-control" value="<?= date('Y-m-d\TH:i', strtotime($election['end_date_and_time'])) ?>" required>
|
|
</div>
|
|
</div>
|
|
<div style="display: flex; gap: 1rem;">
|
|
<button type="submit" class="btn btn-primary" style="flex: 1;">Update</button>
|
|
<button type="button" onclick="document.getElementById('editElectionModal').style.display='none'" class="btn btn-outline" style="flex: 1;">Cancel</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<style>
|
|
.modal { display: flex; }
|
|
.form-control { width: 100%; padding: 0.5rem; border: 1px solid var(--border-color); border-radius: var(--radius); margin-top: 0.25rem; }
|
|
.form-group { margin-bottom: 1rem; }
|
|
.form-label { font-size: 0.75rem; font-weight: 600; color: var(--text-muted); }
|
|
</style>
|
|
|
|
<script>
|
|
window.onclick = function(event) {
|
|
if (event.target.id === 'editElectionModal') {
|
|
event.target.style.display = 'none';
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|