38458-vm/ballot.php
2026-02-15 19:01:09 +00:00

125 lines
5.0 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 || $election['status'] !== 'Ongoing') {
die("Election is not currently ongoing.");
}
// Check if already voted
$check = $pdo->prepare("SELECT COUNT(*) FROM votes WHERE election_id = ? AND voter_id = ?");
$check->execute([$id, $user['id']]);
if ($check->fetchColumn() > 0) {
header("Location: view_results.php?id=$id&error=AlreadyVoted");
exit;
}
$positions = $pdo->prepare("SELECT * FROM positions WHERE election_id = ? ORDER BY sort_order ASC");
$positions->execute([$id]);
$positions = $positions->fetchAll();
?>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Vote: <?= htmlspecialchars($election['title']) ?></title>
<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() ?>">
<style>
.candidate-card {
border: 2px solid #e2e8f0;
border-radius: 8px;
padding: 1rem;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 1rem;
margin-bottom: 0.5rem;
}
.candidate-card:hover { border-color: #2563eb; background: #f0f9ff; }
input[type="radio"]:checked + .candidate-card {
border-color: #2563eb;
background: #eff6ff;
box-shadow: 0 0 0 1px #2563eb;
}
input[type="radio"] { display: none; }
.ballot-section { margin-bottom: 2rem; }
.ballot-header { border-bottom: 2px solid #1e293b; padding-bottom: 0.5rem; margin-bottom: 1.5rem; }
</style>
</head>
<body>
<nav class="navbar">
<a href="index.php" class="brand">E-Vote Pro</a>
<div>
<span>Logged in as <?= htmlspecialchars($user['name']) ?></span>
</div>
</nav>
<div class="container" style="max-width: 800px;">
<div class="text-center mb-5">
<h1 style="font-size: 2rem; font-weight: 800;"><?= htmlspecialchars($election['title']) ?></h1>
<p class="text-muted">Please select your candidates carefully. Your vote is immutable once cast.</p>
</div>
<form action="api/submit_vote.php" method="POST">
<input type="hidden" name="election_id" value="<?= $id ?>">
<?php foreach ($positions as $pos): ?>
<div class="ballot-section">
<div class="ballot-header">
<h2 style="margin: 0; font-size: 1.25rem;"><?= htmlspecialchars($pos['name']) ?></h2>
<small class="text-muted">Select <?= $pos['max_votes'] ?> candidate(s)</small>
</div>
<?php
$cStmt = $pdo->prepare("SELECT c.*, u.name FROM candidates c JOIN users u ON c.user_id = u.id WHERE c.position_id = ? AND c.approved = TRUE");
$cStmt->execute([$pos['id']]);
$candidates = $cStmt->fetchAll();
?>
<?php if (empty($candidates)): ?>
<p class="text-muted">No candidates for this position.</p>
<?php else: ?>
<div class="candidates-grid">
<?php foreach ($candidates as $cand): ?>
<label>
<input type="radio" name="votes[<?= $pos['id'] ?>]" value="<?= $cand['id'] ?>" required>
<div class="candidate-card">
<div style="width: 40px; height: 40px; background: #e2e8f0; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: bold; color: #64748b;">
<?= substr($cand['name'], 0, 1) ?>
</div>
<div>
<div style="font-weight: 700;"><?= htmlspecialchars($cand['name']) ?></div>
<div style="font-size: 0.75rem; color: #64748b;"><?= htmlspecialchars($cand['party_name'] ?: 'Independent') ?></div>
</div>
</div>
</label>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<div style="margin-top: 3rem; text-align: center; border-top: 1px solid #e2e8f0; padding-top: 2rem;">
<p style="font-size: 0.875rem; color: #64748b; margin-bottom: 1.5rem;">By clicking "Cast My Vote", I acknowledge that my selection is final.</p>
<button type="submit" class="btn btn-primary" style="padding: 1rem 3rem; font-size: 1.1rem; background: #1e293b;">Cast My Vote</button>
</div>
</form>
</div>
</body>
</html>