This commit is contained in:
Flatlogic Bot 2026-02-15 22:06:09 +00:00
parent a36cb738cd
commit 3aa07f42ec
13 changed files with 633 additions and 261 deletions

View File

@ -12,6 +12,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$password = $_POST["password"] ?? "iloilohns";
$track = $_POST["track"] ?? "";
$grade_level = $_POST["grade_level"] ?? "";
$section = $_POST["section"] ?? "";
if (!$election_id || !$student_id || !$name || !$email) {
die("Missing fields");
@ -28,9 +29,9 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
if ($existing) {
$user_id = $existing["id"];
// Update track/grade if needed
$upd = $pdo->prepare("UPDATE users SET track = ?, grade_level = ? WHERE id = ?");
$upd->execute([$track, $grade_level, $user_id]);
// Update track/grade/section if needed
$upd = $pdo->prepare("UPDATE users SET track = ?, grade_level = ?, section = ? WHERE id = ?");
$upd->execute([$track, $grade_level, $section, $user_id]);
} else {
// 1a. Create user in Supabase
$supabaseUser = SupabaseAuth::createUser($email, $password);
@ -49,8 +50,8 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
// Create new user locally
$user_id = uuid();
$stmt = $pdo->prepare("INSERT INTO users (id, supabase_uid, student_id, name, email, track, grade_level, role) VALUES (?, ?, ?, ?, ?, ?, ?, 'Voter')");
$stmt->execute([$user_id, $supabase_uid, $student_id, $name, $email, $track, $grade_level]);
$stmt = $pdo->prepare("INSERT INTO users (id, supabase_uid, student_id, name, email, track, grade_level, section, role) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'Voter')");
$stmt->execute([$user_id, $supabase_uid, $student_id, $name, $email, $track, $grade_level, $section]);
}
// 2. Assign to election

View File

@ -42,6 +42,7 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
$email = trim($data[2]);
$track = trim($data[3]);
$grade_level = trim($data[4]);
$section = trim($data[5] ?? "");
if (!$student_id || !$name || !$email) continue;
@ -52,9 +53,9 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
if ($existing) {
$user_id = $existing["id"];
// Update track/grade if needed
$upd = $pdo->prepare("UPDATE users SET track = ?, grade_level = ? WHERE id = ?");
$upd->execute([$track, $grade_level, $user_id]);
// Update track/grade/section if needed
$upd = $pdo->prepare("UPDATE users SET track = ?, grade_level = ?, section = ? WHERE id = ?");
$upd->execute([$track, $grade_level, $section, $user_id]);
$updated++;
} else {
// 1a. Create user in Supabase
@ -75,8 +76,8 @@ if ($_SERVER["REQUEST_METHOD"] === "POST") {
// Create new user locally
$user_id = uuid();
$stmt = $pdo->prepare("INSERT INTO users (id, supabase_uid, student_id, name, email, track, grade_level, role) VALUES (?, ?, ?, ?, ?, ?, ?, 'Voter')");
$stmt->execute([$user_id, $supabase_uid, $student_id, $name, $email, $track, $grade_level]);
$stmt = $pdo->prepare("INSERT INTO users (id, supabase_uid, student_id, name, email, track, grade_level, section, role) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'Voter')");
$stmt->execute([$user_id, $supabase_uid, $student_id, $name, $email, $track, $grade_level, $section]);
$imported++;
}

View File

@ -9,6 +9,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['id'])) {
$email = $_POST['email'];
$track = $_POST['track'];
$gradeLevel = $_POST['grade_level'];
$section = $_POST['section'] ?? '';
$password = $_POST['password'] ?? '';
$pdo = db();
@ -23,11 +24,11 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['id'])) {
SupabaseAuth::updateUserPassword($userRecord['supabase_uid'], $password);
}
$stmt = $pdo->prepare("UPDATE users SET name = ?, student_id = ?, email = ?, track = ?, grade_level = ? WHERE id = ?");
$stmt->execute([$name, $studentId, $email, $track, $gradeLevel, $userId]);
$stmt = $pdo->prepare("UPDATE users SET name = ?, student_id = ?, email = ?, track = ?, grade_level = ?, section = ? WHERE id = ?");
$stmt->execute([$name, $studentId, $email, $track, $gradeLevel, $section, $userId]);
} else {
$stmt = $pdo->prepare("UPDATE users SET name = ?, student_id = ?, email = ?, track = ?, grade_level = ? WHERE id = ?");
$stmt->execute([$name, $studentId, $email, $track, $gradeLevel, $userId]);
$stmt = $pdo->prepare("UPDATE users SET name = ?, student_id = ?, email = ?, track = ?, grade_level = ?, section = ? WHERE id = ?");
$stmt->execute([$name, $studentId, $email, $track, $gradeLevel, $section, $userId]);
}
// Log the action

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

View File

@ -43,102 +43,115 @@ $endTime = strtotime($election['end_date_and_time']) * 1000;
<script src="https://unpkg.com/lucide@latest"></script>
<style>
:root {
--primary: #6366f1;
--primary-hover: #4f46e5;
--primary: #4f46e5;
--primary-light: #eef2ff;
--bg: #f8fafc;
--text: #0f172a;
--text: #1e293b;
--text-muted: #64748b;
--glass: rgba(255, 255, 255, 0.7);
--glass-border: rgba(255, 255, 255, 0.5);
--border: #e2e8f0;
}
body {
background: linear-gradient(135deg, #f8fafc 0%, #e2e8f0 100%);
background-color: var(--bg);
color: var(--text);
font-family: 'Plus Jakarta Sans', sans-serif;
font-family: 'Inter', sans-serif;
margin: 0;
min-height: 100vh;
line-height: 1.5;
}
.ballot-container {
max-width: 800px;
max-width: 900px;
margin: 0 auto;
padding: 40px 20px 100px;
padding: 40px 20px 120px;
}
.timer-banner {
background: var(--text);
color: white;
padding: 12px 24px;
border-radius: 100px;
display: inline-flex;
.ballot-title-area {
margin-bottom: 40px;
}
.ballot-title-area h1 {
font-size: 1.875rem;
font-weight: 700;
margin: 0 0 8px 0;
color: #1e293b;
}
.ballot-title-area p {
color: #64748b;
margin: 0;
font-size: 1rem;
}
.voter-info-card {
background: white;
border: 1px solid var(--border);
border-radius: 12px;
padding: 24px;
margin-bottom: 32px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.voter-info-title {
font-size: 1rem;
font-weight: 600;
color: #475569;
margin-bottom: 16px;
}
.voter-info-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 20px;
}
.info-item label {
display: block;
font-size: 0.75rem;
font-weight: 500;
color: #94a3b8;
text-transform: uppercase;
margin-bottom: 4px;
}
.info-item span {
font-size: 0.875rem;
font-weight: 600;
color: #1e293b;
}
.timer-container {
display: flex;
align-items: center;
gap: 12px;
gap: 8px;
color: #ef4444;
font-weight: 700;
font-size: 0.875rem;
margin-bottom: 32px;
box-shadow: 0 10px 25px -5px rgba(15, 23, 42, 0.2);
}
#countdown {
color: #fbbf24;
font-variant-numeric: tabular-nums;
}
.ballot-header {
margin-bottom: 64px;
}
.ballot-header h1 {
font-size: 3rem;
font-weight: 800;
color: var(--text);
margin: 0 0 16px 0;
letter-spacing: -0.05em;
line-height: 1;
}
.ballot-header p {
color: var(--text-muted);
font-size: 1.25rem;
max-width: 500px;
margin: 0;
line-height: 1.6;
background: #fef2f2;
padding: 8px 16px;
border-radius: 8px;
border: 1px solid #fee2e2;
}
.position-group {
margin-bottom: 48px;
background: var(--glass);
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-radius: 32px;
border: 1px solid var(--glass-border);
padding: 40px;
box-shadow: 0 20px 40px -15px rgba(0,0,0,0.05);
background: white;
border: 1px solid var(--border);
border-radius: 12px;
padding: 32px;
margin-bottom: 24px;
box-shadow: 0 1px 3px rgba(0,0,0,0.05);
}
.position-title {
font-size: 1.5rem;
font-weight: 800;
color: var(--text);
margin-bottom: 32px;
display: flex;
align-items: center;
gap: 16px;
font-size: 1.25rem;
font-weight: 700;
color: #1e293b;
margin-bottom: 24px;
}
.position-title i {
padding: 10px;
background: white;
border-radius: 14px;
color: var(--primary);
box-shadow: 0 4px 6px -1px rgba(0,0,0,0.05);
}
.candidates-grid {
display: grid;
grid-template-columns: 1fr;
gap: 16px;
.candidates-list {
display: flex;
flex-direction: column;
gap: 12px;
}
.candidate-label {
@ -147,142 +160,212 @@ $endTime = strtotime($election['end_date_and_time']) * 1000;
}
.candidate-card {
border: 2px solid transparent;
border-radius: 24px;
padding: 24px;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: 1px solid var(--border);
border-radius: 12px;
padding: 16px 20px;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 20px;
gap: 16px;
background: white;
position: relative;
}
.candidate-card:hover {
transform: translateY(-2px);
box-shadow: 0 12px 20px -8px rgba(0,0,0,0.1);
border-color: #cbd5e1;
background: #f8fafc;
}
input[type="radio"]:checked + .candidate-card,
input[type="checkbox"]:checked + .candidate-card {
input[type="radio"]:checked + .candidate-card {
border-color: var(--primary);
background: #f5f3ff;
background: white;
box-shadow: 0 0 0 1px var(--primary);
}
input[type="radio"]:checked + .candidate-card .check-icon,
input[type="checkbox"]:checked + .candidate-card .check-icon {
background: var(--primary);
color: white;
border-color: var(--primary);
}
input[type="radio"]:checked + .candidate-card .avatar-placeholder {
background: var(--primary);
color: white;
}
input[type="radio"], input[type="checkbox"] { display: none; }
.avatar-placeholder {
width: 64px;
height: 64px;
background: #f1f5f9;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
font-weight: 800;
color: var(--primary);
font-size: 1.5rem;
transition: all 0.3s;
}
.candidate-info h3 {
margin: 0;
font-size: 1.25rem;
font-weight: 800;
color: var(--text);
}
.candidate-info p {
margin: 4px 0 0 0;
font-size: 1rem;
color: var(--text-muted);
font-weight: 600;
}
.check-icon {
margin-left: auto;
width: 28px;
height: 28px;
border: 2px solid #e2e8f0;
.radio-circle {
width: 20px;
height: 20px;
border: 2px solid #cbd5e1;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
color: transparent;
transition: all 0.3s;
transition: all 0.2s;
}
input[type="radio"]:checked + .candidate-card .radio-circle {
border-color: var(--primary);
}
input[type="radio"]:checked + .candidate-card .radio-circle::after {
content: '';
width: 10px;
height: 10px;
background: var(--primary);
border-radius: 50%;
}
.candidate-avatar {
width: 48px;
height: 48px;
background: #f1f5f9;
border-radius: 50%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
color: #64748b;
}
.candidate-avatar img {
width: 100%;
height: 100%;
object-fit: cover;
}
.candidate-info h3 {
margin: 0;
font-size: 1rem;
font-weight: 600;
color: #1e293b;
}
.candidate-info p {
margin: 2px 0 0 0;
font-size: 0.875rem;
color: #64748b;
}
.submit-bar {
position: fixed;
bottom: 32px;
left: 50%;
transform: translateX(-50%);
width: calc(100% - 40px);
max-width: 800px;
background: var(--text);
padding: 20px 40px;
border-radius: 24px;
bottom: 0;
left: 0;
right: 0;
background: white;
padding: 20px;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
color: white;
box-shadow: 0 25px 50px -12px rgba(0,0,0,0.5);
justify-content: center;
z-index: 100;
backdrop-filter: blur(12px);
box-shadow: 0 -4px 6px -1px rgba(0,0,0,0.05);
}
.submit-bar p { margin: 0; font-size: 0.875rem; color: #94a3b8; }
.submit-bar h4 { margin: 4px 0 0 0; font-size: 1.125rem; font-weight: 700; }
.btn-submit {
background: var(--primary);
color: white;
border: none;
padding: 14px 32px;
border-radius: 16px;
padding: 12px 48px;
border-radius: 8px;
font-size: 1rem;
font-weight: 800;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
transition: background 0.2s;
}
.btn-submit:hover {
background: var(--primary-hover);
transform: scale(1.05);
}
@media (max-width: 640px) {
.submit-bar {
flex-direction: column;
gap: 16px;
text-align: center;
padding: 24px;
input[type="radio"] { display: none; }
@media (max-width: 768px) {
.voter-info-grid {
grid-template-columns: 1fr 1fr;
}
.btn-submit { width: 100%; }
.ballot-header h1 { font-size: 2.25rem; }
}
</style>
</head>
<body>
<div class="ballot-container">
<div style="text-align: center;">
<div class="timer-banner">
<i data-lucide="clock" style="width: 18px;"></i>
<span>TIME REMAINING:</span>
<span id="countdown">00:00:00</span>
<div class="ballot-title-area">
<h1>Cast Your Vote</h1>
<p>Select one candidate for each position</p>
</div>
<div class="voter-info-card">
<div style="display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 20px;">
<div class="voter-info-title">Voter Information</div>
<div class="timer-container">
<i data-lucide="clock" style="width: 16px;"></i>
<span id="countdown">00:00:00</span>
</div>
</div>
<div class="voter-info-grid">
<div class="info-item">
<label>Email</label>
<span><?= htmlspecialchars($user['email']) ?></span>
</div>
<div class="info-item">
<label>Grade Level</label>
<span>Grade <?= htmlspecialchars((string)($user['grade_level'] ?? 'N/A')) ?></span>
</div>
<div class="info-item">
<label>Track/Cluster</label>
<span><?= htmlspecialchars($user['track'] ?? 'N/A') ?></span>
</div>
<div class="info-item">
<label>Section</label>
<span><?= htmlspecialchars($user['section'] ?? 'N/A') ?></span>
</div>
</div>
</div>
<form id="ballotForm" action="api/submit_vote.php" method="POST">
<input type="hidden" name="election_id" value="<?= $id ?>">
<?php foreach ($positions as $index => $pos): ?>
<div class="position-group">
<div class="position-title">
<?= htmlspecialchars($pos['name']) ?>
</div>
<?php
$sql = "SELECT c.*, u.name, u.track FROM candidates c JOIN users u ON c.user_id = u.id WHERE c.position_id = ? AND c.approved = TRUE";
$params = [$pos['id']];
if ($pos['type'] === 'Track Specific') {
$sql .= " AND u.track = ?";
$params[] = $user['track'];
}
$cStmt = $pdo->prepare($sql);
$cStmt->execute($params);
$candidates = $cStmt->fetchAll();
?>
<?php if (empty($candidates)): ?>
<div style="padding: 24px; background: #f8fafc; border-radius: 12px; text-align: center; border: 1px dashed #cbd5e1;">
<p style="margin: 0; color: #64748b; font-size: 0.875rem;">No candidates available for your track.</p>
</div>
<?php else: ?>
<div class="candidates-list">
<?php foreach ($candidates as $cand): ?>
<label class="candidate-label">
<input type="radio" name="votes[<?= $pos['id'] ?>]" value="<?= $cand['id'] ?>" required>
<div class="candidate-card">
<div class="radio-circle"></div>
<div class="candidate-avatar">
<?= substr($cand['name'], 0, 1) ?>
</div>
<div class="candidate-info">
<h3><?= htmlspecialchars($cand['name']) ?></h3>
<p><?= htmlspecialchars($cand['party_name'] ?: 'Independent') ?></p>
</div>
</div>
</label>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
<div class="submit-bar">
<button type="submit" class="btn-submit">
Cast My Vote
</button>
</div>
</form>
</div>
</div>
<div class="ballot-header">

View File

@ -21,7 +21,9 @@ $totalVotes->execute([$electionId]);
$totalVotes = $totalVotes->fetchColumn();
// Chart Data: Participation per Grade Level
$gradeStats = $pdo->prepare("SELECT COALESCE(u.grade_level::TEXT, 'Unknown') as label, COUNT(DISTINCT v.voter_id) as count
$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
$gradeCol = ($driver === 'pgsql') ? "u.grade_level::TEXT" : "CAST(u.grade_level AS CHAR)";
$gradeStats = $pdo->prepare("SELECT COALESCE($gradeCol, 'Unknown') as label, COUNT(DISTINCT v.voter_id) as count
FROM users u JOIN votes v ON u.id = v.voter_id
WHERE v.election_id = ?
GROUP BY u.grade_level ORDER BY u.grade_level");

137
db/mock_data.php Normal file
View File

@ -0,0 +1,137 @@
<?php
require_once __DIR__ . '/config.php';
function generate_uuid() {
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
}
$pdo = db();
$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);
echo "Connected using driver: $driver\n";
try {
$pdo->beginTransaction();
echo "Clearing existing data (preserving Admin)...\n";
// Order matters for foreign keys
$pdo->exec("DELETE FROM audit_logs");
$pdo->exec("DELETE FROM votes");
$pdo->exec("DELETE FROM candidates");
$pdo->exec("DELETE FROM positions");
$pdo->exec("DELETE FROM election_assignments");
$pdo->exec("DELETE FROM elections");
$pdo->exec("DELETE FROM users WHERE role != 'Admin'");
// Ensure admin exists
$admin = $pdo->query("SELECT id FROM users WHERE role = 'Admin' LIMIT 1")->fetch();
if (!$admin) {
$adminId = generate_uuid();
$stmt = $pdo->prepare("INSERT INTO users (id, student_id, name, email, password_hash, role, access_level) VALUES (?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([$adminId, '00-0000', 'Admin User', 'Admin@iloilonhs.edu.ph', password_hash('Testing', PASSWORD_DEFAULT), 'Admin', 4]);
echo "Created default admin.\n";
} else {
$adminId = $admin['id'];
echo "Preserved existing admin: " . $adminId . "\n";
}
echo "Adding mock elections and positions...\n";
$electionId = generate_uuid();
$stmt = $pdo->prepare("INSERT INTO elections (id, title, description, status, start_date_and_time, end_date_and_time, created_by) VALUES (?, ?, ?, ?, ?, ?, ?)");
$stmt->execute([
$electionId,
'SSG General Elections 2026',
'Annual election for Supreme Student Government.',
'Ongoing',
date('Y-m-d H:i:s', strtotime('-1 day')),
date('Y-m-d H:i:s', strtotime('+7 days')),
$adminId
]);
$positions = [
['President', 1, 1],
['Vice President', 1, 2],
['Secretary', 1, 3],
['Treasurer', 1, 4]
];
$posIds = [];
$stmt = $pdo->prepare("INSERT INTO positions (id, election_id, name, max_votes, sort_order) VALUES (?, ?, ?, ?, ?)");
foreach ($positions as $p) {
$id = generate_uuid();
$stmt->execute([$id, $electionId, $p[0], $p[1], $p[2]]);
$posIds[$p[0]] = $id;
}
echo "Adding mock students (voters)...\n";
$tracks = ['STEM', 'ABM', 'HUMSS', 'GAS', 'TVL'];
$sections = ['A', 'B', 'C', 'D'];
$voters = [];
$stmt = $pdo->prepare("INSERT INTO users (id, student_id, name, email, password_hash, grade_level, track, section, role) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)");
$assignStmt = $pdo->prepare("INSERT INTO election_assignments (id, election_id, user_id, role_in_election, assigned_by) VALUES (?, ?, ?, ?, ?)");
for ($i = 1; $i <= 40; $i++) {
$id = generate_uuid();
$studentId = sprintf('26-%04d', $i);
$track = $tracks[array_rand($tracks)];
$grade = rand(11, 12);
$section = $sections[array_rand($sections)];
$stmt->execute([
$id,
$studentId,
"Student $i",
"student$i@iloilonhs.edu.ph",
password_hash('password', PASSWORD_DEFAULT),
$grade,
$track,
$section,
'Voter'
]);
$assignStmt->execute([generate_uuid(), $electionId, $id, 'Voter', $adminId]);
$voters[] = ['id' => $id, 'grade' => $grade, 'track' => $track];
}
echo "Adding candidates...\n";
$candidateIds = [];
foreach ($posIds as $posName => $posId) {
for ($c = 1; $c <= 2; $c++) {
$voter = array_shift($voters);
$userId = $voter['id'];
$candId = generate_uuid();
$candStmt = $pdo->prepare("INSERT INTO candidates (id, election_id, position_id, user_id, party_name, approved) VALUES (?, ?, ?, ?, ?, ?)");
$candStmt->execute([$candId, $electionId, $posId, $userId, ($c == 1 ? 'Alpha Party' : 'Beta Party'), true]);
$candidateIds[$posId][] = $candId;
$updStmt = $pdo->prepare("UPDATE election_assignments SET role_in_election = 'Candidate' WHERE election_id = ? AND user_id = ?");
$updStmt->execute([$electionId, $userId]);
}
}
echo "Generating mock votes...\n";
$voteStmt = $pdo->prepare("INSERT INTO votes (id, election_id, position_id, candidate_id, voter_id) VALUES (?, ?, ?, ?, ?)");
foreach ($voters as $v) {
// 85% turnout
if (rand(1, 100) <= 85) {
foreach ($posIds as $posId) {
$candId = $candidateIds[$posId][array_rand($candidateIds[$posId])];
$voteStmt->execute([generate_uuid(), $electionId, $posId, $candId, $v['id']]);
}
}
}
$pdo->commit();
echo "Done! Mock data successfully generated.\n";
} catch (Exception $e) {
if ($pdo->inTransaction()) $pdo->rollBack();
echo "FATAL ERROR: " . $e->getMessage() . "\n";
exit(1);
}

View File

@ -235,6 +235,10 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
<div class="election-item-header" onclick="toggleAccordion(this)">
<div class="election-item-title"><?= htmlspecialchars($election['title']) ?></div>
<div class="election-item-right">
<a href="view_results.php?id=<?= $election['id'] ?>" class="btn-generate" onclick="event.stopPropagation()" style="background: #4f46e5; color: white; padding: 6px 12px; border-radius: 6px; font-size: 0.75rem; font-weight: 600; text-decoration: none; display: flex; align-items: center; gap: 6px;">
<i data-lucide="file-text" style="width: 14px;"></i>
GENERATE RESULTS
</a>
<span class="status-badge status-<?= strtolower($election['status']) ?>">
<?= htmlspecialchars($election['status']) ?>
</span>

138
login.php
View File

@ -47,7 +47,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$error = 'Invalid Credentials. Please check your UID, Email, and Role.';
}
if ($error && isset($_POST['role'])) { // Redirect back to landing if coming from modal
if ($error && isset($_POST['role']) && str_contains($_SERVER['HTTP_REFERER'] ?? '', 'index.php')) {
// Only redirect back if we actually came from landing page modal
header('Location: index.php?error=' . urlencode($error));
exit;
}
@ -57,46 +58,113 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Login - Online Election System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login - Iloilo National High School</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;800;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/landing.css?v=<?= time() ?>">
<style>
body { background-color: #f8fafc; font-family: 'Inter', sans-serif; }
.login-card { max-width: 400px; margin: 100px auto; border-radius: 8px; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); }
.login-page-container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
position: relative;
}
</style>
</head>
<body>
<div class="card login-card p-4">
<h2 class="text-center mb-4" style="color: #1e293b;">Election Login</h2>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST">
<div class="mb-3">
<label class="form-label">Student ID (XX-XXXX)</label>
<input type="text" name="student_id" class="form-control" placeholder="00-0000" required pattern="\d{2}-\d{4}">
<body class="landing-page" style="background-image: url('assets/images/background.jpg?v=<?= filemtime('assets/images/background.jpg') ?>');">
<div class="login-page-container">
<div class="login-modal" style="display: block; position: static; animation: none;">
<div class="modal-header">
<div class="modal-header-content">
<div class="header-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M23 21v-2a4 4 0 0 0-3-3.87"></path><path d="M16 3.13a4 4 0 0 1 0 7.75"></path></svg>
</div>
<h2>Election Login</h2>
</div>
</div>
<div class="mb-3">
<label class="form-label">Email Account</label>
<input type="email" name="email" class="form-control" required>
<div class="modal-body">
<?php if ($error): ?>
<div style="background: #fee2e2; color: #b91c1c; padding: 0.75rem; border-radius: 10px; margin-bottom: 1.5rem; font-size: 0.85rem; border: 1px solid #fecaca; text-align: center;">
<?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
<form method="POST">
<div class="form-group">
<label>User Type</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
</i>
<select name="role">
<option value="Voter">Voter</option>
<option value="Officer">Officer</option>
<option value="Adviser">Adviser</option>
<option value="Admin">Admin</option>
</select>
</div>
</div>
<div class="form-group">
<label>UID</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"></rect><line x1="7" y1="8" x2="17" y2="8"></line><line x1="7" y1="12" x2="17" y2="12"></line><line x1="7" y1="16" x2="12" y2="16"></line></svg>
</i>
<input type="text" name="student_id" placeholder="00-0000" required pattern="\d{2}-\d{4}">
</div>
</div>
<div class="form-group">
<label>Email Account</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
</i>
<input type="email" name="email" placeholder="firstname.lastname@iloilonhs.edu.ph" required>
</div>
</div>
<div class="form-group">
<label>Password</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
</i>
<input type="password" id="passwordInput" name="password" placeholder="Enter your password" required>
<i class="password-toggle" onclick="togglePassword()">
<svg id="eyeIcon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>
</i>
</div>
</div>
<button type="submit" class="modal-btn-login">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4"></path><polyline points="10 17 15 12 10 7"></polyline><line x1="15" y1="12" x2="3" y2="12"></line></svg>
LOGIN
</button>
</form>
<div class="text-center mt-3">
<small style="color: var(--landing-text-muted); font-size: 0.8rem;">Don't have an account? <a href="signup.php" style="color: var(--landing-primary); font-weight: 600; text-decoration: none;">Register here</a></small>
</div>
</div>
<div class="mb-3">
<label class="form-label">Role</label>
<select name="role" class="form-select">
<option value="Voter">Voter</option>
<option value="Officer">Officer</option>
<option value="Adviser">Adviser</option>
<option value="Admin">Admin</option>
</select>
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input type="password" name="password" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary w-100" style="background-color: #2563eb;">Login</button>
</form>
<div class="mt-3 text-center">
<small>Don't have an account? <a href="signup.php">Register</a></small>
</div>
</div>
<script>
function togglePassword() {
const input = document.getElementById('passwordInput');
const icon = document.getElementById('eyeIcon');
if (input.type === 'password') {
input.type = 'text';
icon.innerHTML = '<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line>';
} else {
input.type = 'password';
icon.innerHTML = '<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle>';
}
}
</script>
</body>
</html>

View File

@ -43,6 +43,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
} else {
$error = 'An error occurred: ' . $e->getMessage();
}
} catch (Exception $e) {
$error = $e->getMessage();
}
}
}
@ -51,49 +53,105 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Signup - Online Election System</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Registration - Iloilo National High School</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;800;900&display=swap" rel="stylesheet">
<link rel="stylesheet" href="assets/css/landing.css?v=<?= time() ?>">
<style>
body { background-color: #f8fafc; font-family: 'Inter', sans-serif; }
.signup-card { max-width: 500px; margin: 50px auto; border-radius: 8px; box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1); }
.signup-page-container {
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
z-index: 2;
position: relative;
padding: 2rem 0;
}
</style>
</head>
<body>
<div class="card signup-card p-4">
<h2 class="text-center mb-4" style="color: #1e293b;">Voter Registration</h2>
<?php if ($error): ?>
<div class="alert alert-danger"><?php echo $error; ?></div>
<?php endif; ?>
<form method="POST">
<div class="mb-3">
<label class="form-label">Full Name</label>
<input type="text" name="name" class="form-control" required>
<body class="landing-page" style="background-image: url('assets/images/background.jpg?v=<?= filemtime('assets/images/background.jpg') ?>');">
<div class="signup-page-container">
<div class="login-modal" style="display: block; position: static; animation: none; max-width: 500px;">
<div class="modal-header">
<div class="modal-header-content">
<div class="header-icon">
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M16 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"></path><circle cx="8.5" cy="7" r="4"></circle><polyline points="17 11 19 13 23 9"></polyline></svg>
</div>
<h2>Voter Registration</h2>
</div>
</div>
<div class="mb-3">
<label class="form-label">Student ID (XX-XXXX)</label>
<input type="text" name="student_id" class="form-control" placeholder="00-0000" required pattern="\d{2}-\d{4}">
<div class="modal-body">
<?php if ($error): ?>
<div style="background: #fee2e2; color: #b91c1c; padding: 0.75rem; border-radius: 10px; margin-bottom: 1.5rem; font-size: 0.85rem; border: 1px solid #fecaca; text-align: center;">
<?= htmlspecialchars($error) ?>
</div>
<?php endif; ?>
<form method="POST">
<div class="form-group">
<label>Full Name</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
</i>
<input type="text" name="name" placeholder="Juan Dela Cruz" required>
</div>
</div>
<div class="form-group">
<label>UID</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="16" rx="2"></rect><line x1="7" y1="8" x2="17" y2="8"></line><line x1="7" y1="12" x2="17" y2="12"></line><line x1="7" y1="16" x2="12" y2="16"></line></svg>
</i>
<input type="text" name="student_id" placeholder="00-0000" required pattern="\d{2}-\d{4}">
</div>
</div>
<div class="form-group">
<label>Email Account</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"></path><polyline points="22,6 12,13 2,6"></polyline></svg>
</i>
<input type="email" name="email" placeholder="firstname.lastname@iloilonhs.edu.ph" required>
</div>
</div>
<div class="form-group">
<label>Password</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 10 0v4"></path></svg>
</i>
<input type="password" id="passwordInput" name="password" placeholder="Create a password" required>
</div>
</div>
<div class="form-group">
<label>User Type</label>
<div class="input-container">
<i>
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
</i>
<select name="role">
<option value="Voter">Voter</option>
<option value="Officer">Officer</option>
<option value="Adviser">Adviser</option>
<option value="Admin">Admin</option>
</select>
</div>
</div>
<button type="submit" class="modal-btn-login">
REGISTER
</button>
</form>
<div class="text-center mt-3">
<small style="color: var(--landing-text-muted); font-size: 0.8rem;">Already have an account? <a href="login.php" style="color: var(--landing-primary); font-weight: 600; text-decoration: none;">Login here</a></small>
</div>
</div>
<div class="mb-3">
<label class="form-label">Email Address</label>
<input type="email" name="email" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Password</label>
<input type="password" name="password" class="form-control" required>
</div>
<div class="mb-3">
<label class="form-label">Role</label>
<select name="role" class="form-select">
<option value="Voter">Voter</option>
<option value="Officer">Officer</option>
<option value="Adviser">Adviser</option>
<option value="Admin">Admin</option>
</select>
</div>
<button type="submit" class="btn btn-primary w-100" style="background-color: #2563eb;">Register</button>
</form>
<div class="mt-3 text-center">
<small>Already have an account? <a href="login.php">Login</a></small>
</div>
</div>
</body>

View File

@ -85,16 +85,22 @@ $positions = $positions->fetchAll();
$posTotal = array_sum(array_column($results, 'vote_count'));
?>
<?php foreach ($results as $res):
<?php foreach ($results as $index => $res):
$percent = $posTotal > 0 ? round(($res['vote_count'] / $posTotal) * 100, 1) : 0;
$isWinner = ($index === 0 && $res['vote_count'] > 0);
?>
<div class="candidate-result">
<div class="candidate-result" style="<?= $isWinner ? 'border-color: #10b981; background: #f0fdf4;' : '' ?>">
<div style="display: flex; justify-content: space-between; font-weight: 600;">
<span><?= htmlspecialchars($res['name']) ?> (<?= htmlspecialchars($res['party_name'] ?: 'Ind.') ?>)</span>
<span style="display: flex; align-items: center; gap: 8px;">
<?= htmlspecialchars($res['name']) ?> (<?= htmlspecialchars($res['party_name'] ?: 'Ind.') ?>)
<?php if ($isWinner): ?>
<span style="background: #10b981; color: white; font-size: 0.65rem; padding: 2px 8px; border-radius: 4px; text-transform: uppercase;">Winner</span>
<?php endif; ?>
</span>
<span><?= $res['vote_count'] ?> votes (<?= $percent ?>%)</span>
</div>
<div class="result-bar-container">
<div class="result-bar" style="width: <?= $percent ?>%"></div>
<div class="result-bar" style="width: <?= $percent ?>%; <?= $isWinner ? 'background: #10b981;' : '' ?>"></div>
</div>
</div>
<?php endforeach; ?>

View File

@ -187,6 +187,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
<th>EMAIL</th>
<th>TRACK</th>
<th>GRADE</th>
<th>SECTION</th>
<th>STATUS</th>
<th>ACTIONS</th>
</tr>
@ -194,7 +195,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
<tbody>
<?php if (empty($voters)): ?>
<tr>
<td colspan="7" style="text-align: center; color: #94a3b8; padding: 32px;">No voters assigned to this election.</td>
<td colspan="8" style="text-align: center; color: #94a3b8; padding: 32px;">No voters assigned to this election.</td>
</tr>
<?php else: ?>
<?php foreach ($voters as $voter): ?>
@ -204,6 +205,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
<td><?= htmlspecialchars($voter['email']) ?></td>
<td><?= htmlspecialchars($voter['track']) ?></td>
<td>Grade <?= htmlspecialchars($voter['grade_level']) ?></td>
<td><?= htmlspecialchars($voter['section'] ?? 'N/A') ?></td>
<td>
<span class="status-indicator <?= $voter['has_voted'] ? 'voted' : 'pending' ?>">
<?= $voter['has_voted'] ? 'Voted' : 'Pending' ?>
@ -267,6 +269,10 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
</select>
</div>
</div>
<div class="form-group" style="margin-bottom:24px;">
<label style="display:block; font-size:12px; font-weight:600; color:#64748b; margin-bottom:6px;">SECTION</label>
<input type="text" name="section" placeholder="Enter section (e.g. Einstein, Newton)" required style="width:100%; padding:10px; border-radius:8px; border:1px solid #e2e8f0;">
</div>
<div class="modal-footer" style="display:flex; justify-content:flex-end; gap:12px;">
<button type="button" onclick="closeModal('addVoterModal')" class="btn-cancel" style="padding:10px 20px; border-radius:8px; border:1px solid #e2e8f0; background:white; cursor:pointer;">Cancel</button>
<button type="submit" class="btn-action btn-add" style="padding:10px 24px; border-radius:8px; border:none; background:#4f46e5; color:white; cursor:pointer; font-weight:600;">Register Voter</button>
@ -318,6 +324,10 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
</select>
</div>
</div>
<div class="form-group" style="margin-bottom:24px;">
<label style="display:block; font-size:12px; font-weight:600; color:#64748b; margin-bottom:6px;">SECTION</label>
<input type="text" name="section" id="edit_voter_section" placeholder="Enter section" required style="width:100%; padding:10px; border-radius:8px; border:1px solid #e2e8f0;">
</div>
<div class="modal-footer" style="display:flex; justify-content:flex-end; gap:12px;">
<button type="button" onclick="closeModal('editVoterModal')" class="btn-cancel" style="padding:10px 20px; border-radius:8px; border:1px solid #e2e8f0; background:white; cursor:pointer;">Cancel</button>
<button type="submit" class="btn-action btn-add" style="padding:10px 24px; border-radius:8px; border:none; background:#4f46e5; color:white; cursor:pointer; font-weight:600;">Update Voter</button>
@ -348,8 +358,8 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
<div style="background: #f8fafc; padding: 16px; border-radius: 8px; margin-bottom: 24px;">
<p style="margin: 0 0 8px 0; font-size: 0.75rem; font-weight: 600; color: #64748b;">CSV FORMAT REQUIREMENTS:</p>
<p style="margin: 0; font-size: 0.75rem; color: #64748b; line-height: 1.5;">
Columns: <code>student_id, name, email, track, grade_level</code><br>
Example: <code>20-1234, John Doe, john@example.com, STEM, 12</code>
Columns: <code>student_id, name, email, track, grade_level, section</code><br>
Example: <code>20-1234, John Doe, john@example.com, STEM, 12, Einstein</code>
</p>
</div>
@ -388,6 +398,7 @@ $projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? 'Online Election System
document.getElementById('edit_voter_email').value = voter.email;
document.getElementById('edit_voter_track').value = voter.track;
document.getElementById('edit_voter_grade_level').value = voter.grade_level;
document.getElementById('edit_voter_section').value = voter.section || '';
openModal('editVoterModal');
}