Autosave: 20260204-202613
This commit is contained in:
parent
fc68bec63b
commit
b813668e12
492
Design/Style.css
492
Design/Style.css
@ -1,5 +1,6 @@
|
||||
:root {
|
||||
--Primary_Color: #2563EB;
|
||||
--Primary_Light: #DBEAFE;
|
||||
--Secondary_Color: #64748B;
|
||||
--Background_Color: #F8FAFC;
|
||||
--Surface_Color: #FFFFFF;
|
||||
@ -9,6 +10,7 @@
|
||||
--Success_Color: #10B981;
|
||||
--Error_Color: #EF4444;
|
||||
--Overlay_Color: rgba(0, 0, 0, 0.65);
|
||||
--Sidebar_Width: 260px;
|
||||
}
|
||||
|
||||
* {
|
||||
@ -23,7 +25,8 @@ body, html {
|
||||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||||
color: var(--Text_Primary);
|
||||
line-height: 1.5;
|
||||
overflow-x: hidden;
|
||||
overflow: hidden; /* Main page scroll is handled by content body */
|
||||
background-color: var(--Background_Color);
|
||||
}
|
||||
|
||||
/* Landing Page Styles */
|
||||
@ -39,7 +42,7 @@ body, html {
|
||||
align-items: center;
|
||||
color: white;
|
||||
text-align: center;
|
||||
overflow: hidden; /* Prevent overflow */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.Landing_Wrapper::before {
|
||||
@ -134,10 +137,6 @@ body, html {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.Landing_Description strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.Btn_Landing_Login {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@ -301,88 +300,433 @@ body, html {
|
||||
box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
|
||||
}
|
||||
|
||||
.Password_Toggle_Wrapper {
|
||||
position: relative;
|
||||
/* Dashboard Layout */
|
||||
.Dashboard_Container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
.Toggle_Button {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
.Sidebar {
|
||||
width: var(--Sidebar_Width);
|
||||
background: white;
|
||||
border-right: 1px solid var(--Border_Color);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.Sidebar_Header {
|
||||
padding: 24px;
|
||||
border-bottom: 1px solid var(--Border_Color);
|
||||
}
|
||||
|
||||
.Sidebar_Nav {
|
||||
padding: 20px 0;
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.Nav_Item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 24px;
|
||||
color: var(--Text_Secondary);
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.Nav_Item:hover {
|
||||
background: #F1F5F9;
|
||||
color: var(--Primary_Color);
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
.Nav_Item.Active {
|
||||
background: var(--Primary_Light);
|
||||
color: var(--Primary_Color);
|
||||
border-right: 4px solid var(--Primary_Color);
|
||||
}
|
||||
|
||||
.Main_Content {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.Top_Bar {
|
||||
height: 70px;
|
||||
background: white;
|
||||
border-bottom: 1px solid var(--Border_Color);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0 32px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.Search_Box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: #F1F5F9;
|
||||
border-radius: 8px;
|
||||
padding: 8px 16px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.Search_Box input {
|
||||
background: transparent;
|
||||
border: none;
|
||||
outline: none;
|
||||
padding: 4px 8px;
|
||||
width: 100%;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
.Top_Bar_Actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.Content_Body {
|
||||
flex: 1;
|
||||
padding: 32px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.Page_Title_Section {
|
||||
margin-bottom: 32px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.Page_Title {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 800;
|
||||
color: var(--Text_Primary);
|
||||
}
|
||||
|
||||
.Page_Subtitle {
|
||||
color: var(--Text_Secondary);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
/* Stat Cards */
|
||||
.Stat_Cards_Grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.Stat_Card {
|
||||
background: white;
|
||||
padding: 24px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.Stat_Label {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--Text_Secondary);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.Stat_Value {
|
||||
font-size: 2rem;
|
||||
font-weight: 800;
|
||||
color: var(--Text_Primary);
|
||||
}
|
||||
|
||||
.Stat_Trend {
|
||||
font-size: 0.85rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.Trend_Up { color: var(--Success_Color); }
|
||||
.Trend_Down { color: var(--Error_Color); }
|
||||
|
||||
/* Dashboard Grid */
|
||||
.Dashboard_Grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.Card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.Card_Header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.Card_Title {
|
||||
font-size: 1.15rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/* Table Styles */
|
||||
.Table_Wrapper {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 12px;
|
||||
border-bottom: 1px solid var(--Border_Color);
|
||||
color: var(--Text_Secondary);
|
||||
font-size: 0.85rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 16px 12px;
|
||||
border-bottom: 1px solid var(--Border_Color);
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.Badge {
|
||||
padding: 4px 12px;
|
||||
border-radius: 20px;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.Badge_Success { background: #DCFCE7; color: #166534; }
|
||||
.Badge_Warning { background: #FEF9C3; color: #854D0E; }
|
||||
.Badge_Danger { background: #FEE2E2; color: #991B1B; }
|
||||
|
||||
/* Accordion / Collapsible */
|
||||
.Accordion_Item {
|
||||
margin-bottom: 16px;
|
||||
border: 1px solid var(--Border_Color);
|
||||
border-radius: 12px;
|
||||
overflow: hidden;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.Accordion_Header {
|
||||
padding: 20px 24px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
background: white;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.Accordion_Header:hover {
|
||||
background: #F8FAFC;
|
||||
}
|
||||
|
||||
.Accordion_Header h3 {
|
||||
font-size: 1.15rem;
|
||||
color: var(--Primary_Color);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.Accordion_Icon {
|
||||
transition: transform 0.3s;
|
||||
color: var(--Primary_Color);
|
||||
}
|
||||
|
||||
.Accordion_Content {
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out, padding 0.3s;
|
||||
padding: 0 24px;
|
||||
}
|
||||
|
||||
.Accordion_Item.Active .Accordion_Content {
|
||||
max-height: 2000px; /* Large enough to fit content */
|
||||
padding: 24px;
|
||||
border-top: 1px solid var(--Border_Color);
|
||||
}
|
||||
|
||||
.Accordion_Item.Active .Accordion_Icon {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
/* List Items */
|
||||
.Data_List {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.Data_Row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
border-bottom: 1px solid var(--Border_Color);
|
||||
}
|
||||
|
||||
.Data_Row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.Data_Label {
|
||||
font-weight: 500;
|
||||
color: var(--Text_Secondary);
|
||||
}
|
||||
|
||||
.Data_Value {
|
||||
font-weight: 600;
|
||||
color: var(--Text_Primary);
|
||||
}
|
||||
|
||||
@media (max-width: 1024px) {
|
||||
.Dashboard_Grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.Landing_Header {
|
||||
top: 20px;
|
||||
left: 20px;
|
||||
}
|
||||
|
||||
.Logo_Pill {
|
||||
padding: 6px 16px 6px 8px;
|
||||
}
|
||||
|
||||
.Logo_Circle {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
.Logo_Title {
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.Logo_Subtitle {
|
||||
.Sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.Landing_Content {
|
||||
padding: 30px;
|
||||
|
||||
.Top_Bar {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.Login_Card {
|
||||
padding: 30px 20px;
|
||||
max-width: 100%;
|
||||
|
||||
.Search_Box {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.Landing_Title {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
/* Custom Utilities */
|
||||
.Text_Muted { color: var(--Text_Secondary); }
|
||||
|
||||
.Landing_Description {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.Btn_Landing_Login {
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
padding: 14px 20px;
|
||||
}
|
||||
|
||||
.Login_Card .Title_Large {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Common Utilities */
|
||||
.Alert {
|
||||
padding: 16px;
|
||||
.Select {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid var(--Border_Color);
|
||||
border-radius: 8px;
|
||||
background: white;
|
||||
font-family: inherit;
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 24px;
|
||||
font-weight: 500;
|
||||
color: var(--Text_Primary);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.Alert_Error {
|
||||
background-color: #FEF2F2;
|
||||
color: var(--Error_Color);
|
||||
border: 1px solid #FEE2E2;
|
||||
}
|
||||
/* Breakdown & Summary Cards */
|
||||
.Summary_Breakdowns {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.Breakdown_Card {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
border: 1px solid var(--Border_Color);
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.05);
|
||||
}
|
||||
|
||||
.Breakdown_Title {
|
||||
font-size: 0.9rem;
|
||||
font-weight: 700;
|
||||
color: var(--Primary_Color);
|
||||
margin-bottom: 15px;
|
||||
border-bottom: 2px solid var(--Primary_Light);
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
|
||||
.Breakdown_Item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: 0.85rem;
|
||||
padding: 8px 0;
|
||||
border-bottom: 1px solid #f8f9fa;
|
||||
}
|
||||
|
||||
.Breakdown_Item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Filter Bar */
|
||||
.Filter_Bar {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
border: 1px solid var(--Border_Color);
|
||||
display: grid;
|
||||
grid-template-columns: 2fr repeat(auto-fit, minmax(150px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 24px;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.Filter_Group label {
|
||||
display: block;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
color: var(--Text_Secondary);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.Search_Input_Wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.Search_Input_Wrapper i {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--Text_Secondary);
|
||||
}
|
||||
|
||||
.Search_Input_Wrapper .Input {
|
||||
padding-left: 38px;
|
||||
}
|
||||
|
||||
.Button_Secondary {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
padding: 10px 20px;
|
||||
background: #4F46E5;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.Button_Secondary:hover {
|
||||
background: #4338CA;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(79, 70, 229, 0.2);
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../Logic/Backend/Authentication_Handler.php';
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
$Auth = new Authentication_Handler();
|
||||
$Auth->Check_Auth();
|
||||
|
||||
@ -7,46 +9,159 @@ if ($_SESSION['Access_Level'] < 1) {
|
||||
header('Location: Voting_Screen.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
// Fetch Stats
|
||||
$db = db();
|
||||
$totalVoters = $db->query("SELECT COUNT(*) FROM Voters")->fetchColumn();
|
||||
$totalCandidates = $db->query("SELECT COUNT(*) FROM Candidates")->fetchColumn();
|
||||
$totalVotes = $db->query("SELECT COUNT(*) FROM Voters WHERE Has_Voted = 1")->fetchColumn();
|
||||
|
||||
// Fetch Active Elections
|
||||
$activeElections = $db->query("SELECT * FROM Election_History WHERE Status = 'Active' ORDER BY Start_Date DESC")->fetchAll();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Election Dashboard - Online School Election System</title>
|
||||
<link rel="stylesheet" href="../Design/Style.css">
|
||||
<title>Election Dashboard | Online School Election System</title>
|
||||
<link rel="stylesheet" href="../Design/Style.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<nav class="Dashboard_Navbar">
|
||||
<div class="Logo"><strong>ElectionSystem</strong></div>
|
||||
<div class="User_Info">
|
||||
<span><?php echo $_SESSION['User_Name']; ?> (<?php echo $_SESSION['User_Role']; ?>)</span>
|
||||
<a href="Logout.php" style="margin-left: 20px; font-size: 0.875rem;">Logout</a>
|
||||
</div>
|
||||
</nav>
|
||||
<div class="Dashboard_Container">
|
||||
<!-- Sidebar -->
|
||||
<aside class="Sidebar">
|
||||
<div class="Sidebar_Header">
|
||||
<div class="Logo_Text">
|
||||
<div class="Logo_Title" style="font-size: 1.1rem; color: var(--Primary_Color);">ElectionSystem</div>
|
||||
<div class="Logo_Subtitle">Administrator Portal</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="Sidebar_Nav">
|
||||
<a href="Election_Dashboard.php" class="Nav_Item Active">
|
||||
<i class="fas fa-th-large"></i> Election Dashboard
|
||||
</a>
|
||||
<a href="Election_History.php" class="Nav_Item">
|
||||
<i class="fas fa-vote-yea"></i> Election History
|
||||
</a>
|
||||
<a href="Voters.php" class="Nav_Item">
|
||||
<i class="fas fa-users"></i> Voter Management
|
||||
</a>
|
||||
<a href="Candidates.html" class="Nav_Item">
|
||||
<i class="fas fa-user-tie"></i> Candidate Management
|
||||
</a>
|
||||
<a href="Officers.html" class="Nav_Item">
|
||||
<i class="fas fa-user-shield"></i> Officers Management
|
||||
</a>
|
||||
<a href="Audit_Trail.html" class="Nav_Item">
|
||||
<i class="fas fa-file-alt"></i> Reports & Audit
|
||||
</a>
|
||||
</nav>
|
||||
<div style="padding: 24px; border-top: 1px solid var(--Border_Color);">
|
||||
<a href="Logout.php" class="Nav_Item" style="padding: 0; color: var(--Error_Color);">
|
||||
<i class="fas fa-sign-out-alt"></i> Logout
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div class="Tab_Navigation">
|
||||
<a href="Election_History.html" class="Tab_Item">Election History</a>
|
||||
<a href="Election_Dashboard.php" class="Tab_Item Active">Election Dashboard</a>
|
||||
<a href="Officers.html" class="Tab_Item">Officers</a>
|
||||
<a href="Voters.html" class="Tab_Item">Voters</a>
|
||||
<a href="Audit_Trail.html" class="Tab_Item">Audit Trail</a>
|
||||
<!-- Main Content -->
|
||||
<main class="Main_Content">
|
||||
<!-- Top Bar -->
|
||||
<header class="Top_Bar">
|
||||
<div class="Search_Box">
|
||||
<i class="fas fa-search" style="color: var(--Secondary_Color);"></i>
|
||||
<input type="text" placeholder="Search for voters, candidates, or records...">
|
||||
</div>
|
||||
<div class="Top_Bar_Actions">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 700; font-size: 0.9rem;"><?php echo htmlspecialchars($_SESSION['User_Name']); ?></div>
|
||||
<div style="font-size: 0.75rem; color: var(--Text_Secondary);"><?php echo htmlspecialchars($_SESSION['User_Role']); ?></div>
|
||||
</div>
|
||||
<div style="width: 40px; height: 40px; background: var(--Primary_Light); color: var(--Primary_Color); border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: 700;">
|
||||
<?php echo strtoupper(substr($_SESSION['User_Name'] ?? 'A', 0, 1)); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Content Body -->
|
||||
<div class="Content_Body">
|
||||
<div class="Page_Title_Section">
|
||||
<h1 class="Page_Title">Election Dashboard</h1>
|
||||
<p class="Page_Subtitle">Welcome back! Here's what's happening with the current elections.</p>
|
||||
</div>
|
||||
|
||||
<!-- Stat Cards -->
|
||||
<div class="Stat_Cards_Grid">
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label">Total Voters</div>
|
||||
<div class="Stat_Value"><?php echo number_format($totalVoters); ?></div>
|
||||
<div class="Stat_Trend Trend_Up"><i class="fas fa-users"></i> Registered Students</div>
|
||||
</div>
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label">Total Candidates</div>
|
||||
<div class="Stat_Value"><?php echo number_format($totalCandidates); ?></div>
|
||||
<div class="Stat_Trend" style="color: var(--Primary_Color);"><i class="fas fa-user-tie"></i> Running for Office</div>
|
||||
</div>
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label">Total Votes Cast</div>
|
||||
<div class="Stat_Value"><?php echo number_format($totalVotes); ?></div>
|
||||
<div class="Stat_Trend Trend_Up"><i class="fas fa-check-circle"></i> Verified Ballots</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dashboard Grid -->
|
||||
<div class="Dashboard_Grid">
|
||||
<!-- Main Content: Active Elections -->
|
||||
<div class="Card">
|
||||
<div class="Card_Header">
|
||||
<h2 class="Card_Title">Active Elections</h2>
|
||||
<button class="Button_Primary" style="width: auto; padding: 8px 16px; font-size: 0.85rem;">
|
||||
<i class="fas fa-plus"></i> New Election
|
||||
</button>
|
||||
</div>
|
||||
<div class="Table_Wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Election Title</th>
|
||||
<th>Start Date</th>
|
||||
<th>End Date</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($activeElections)): ?>
|
||||
<tr>
|
||||
<td colspan="5" style="text-align: center; padding: 40px; color: var(--Text_Secondary);">
|
||||
No active elections found. <a href="#" style="color: var(--Primary_Color); font-weight: 600;">Create one now.</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($activeElections as $election): ?>
|
||||
<tr>
|
||||
<td style="font-weight: 600;">School Year <?php echo $election['Year']; ?> Election</td>
|
||||
<td><?php echo date('M d, Y', strtotime($election['Start_Date'])); ?></td>
|
||||
<td><?php echo date('M d, Y', strtotime($election['End_Date'])); ?></td>
|
||||
<td><span class="Badge Badge_Success">Active</span></td>
|
||||
<td>
|
||||
<a href="#" style="color: var(--Primary_Color); margin-right: 12px;"><i class="fas fa-eye"></i></a>
|
||||
<a href="#" style="color: var(--Secondary_Color);"><i class="fas fa-cog"></i></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<main style="padding: 40px 24px;">
|
||||
<h2 style="margin-bottom: 24px;">Election Dashboard</h2>
|
||||
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 24px;">
|
||||
<div class="Card">
|
||||
<h3 style="font-size: 1rem; margin-bottom: 12px;">Active Election</h3>
|
||||
<p class="Text_Muted">No active election currently running.</p>
|
||||
<button class="Button_Primary" style="margin-top: 16px;">Start New Election</button>
|
||||
</div>
|
||||
<div class="Card">
|
||||
<h3 style="font-size: 1rem; margin-bottom: 12px;">Voter Participation</h3>
|
||||
<div style="font-size: 2rem; font-weight: 700;">0%</div>
|
||||
<p class="Text_Muted">0 of 0 voters have cast their ballots.</p>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
236
Screens/Election_History.php
Normal file
236
Screens/Election_History.php
Normal file
@ -0,0 +1,236 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../Logic/Backend/Authentication_Handler.php';
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
$Auth = new Authentication_Handler();
|
||||
$Auth->Check_Auth();
|
||||
|
||||
if ($_SESSION['Access_Level'] < 1) {
|
||||
header('Location: Voting_Screen.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$db = db();
|
||||
|
||||
// Fetch all completed elections
|
||||
$history = $db->query("SELECT * FROM Election_History ORDER BY Year DESC")->fetchAll();
|
||||
|
||||
// For each election, we might want to fetch more detailed stats if they were stored.
|
||||
// Since it's a history page, we'll mock some of the breakdown data if it's not in the DB,
|
||||
// or calculate it based on current voters if we assume the voter list represents the latest.
|
||||
// In a real system, these would be snapshots.
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Election History | Online School Election System</title>
|
||||
<link rel="stylesheet" href="../Design/Style.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.Year_Selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="Dashboard_Container">
|
||||
<!-- Sidebar -->
|
||||
<aside class="Sidebar">
|
||||
<div class="Sidebar_Header">
|
||||
<div class="Logo_Text">
|
||||
<div class="Logo_Title" style="font-size: 1.1rem; color: var(--Primary_Color);">ElectionSystem</div>
|
||||
<div class="Logo_Subtitle">Administrator Portal</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="Sidebar_Nav">
|
||||
<a href="Election_Dashboard.php" class="Nav_Item">
|
||||
<i class="fas fa-th-large"></i> Election Dashboard
|
||||
</a>
|
||||
<a href="Election_History.php" class="Nav_Item Active">
|
||||
<i class="fas fa-vote-yea"></i> Election History
|
||||
</a>
|
||||
<a href="Voters.php" class="Nav_Item">
|
||||
<i class="fas fa-users"></i> Voter Management
|
||||
</a>
|
||||
<a href="Candidates.html" class="Nav_Item">
|
||||
<i class="fas fa-user-tie"></i> Candidate Management
|
||||
</a>
|
||||
<a href="Officers.html" class="Nav_Item">
|
||||
<i class="fas fa-user-shield"></i> Officers Management
|
||||
</a>
|
||||
<a href="Audit_Trail.html" class="Nav_Item">
|
||||
<i class="fas fa-file-alt"></i> Reports & Audit
|
||||
</a>
|
||||
</nav>
|
||||
<div style="padding: 24px; border-top: 1px solid var(--Border_Color);">
|
||||
<a href="Logout.php" class="Nav_Item" style="padding: 0; color: var(--Error_Color);">
|
||||
<i class="fas fa-sign-out-alt"></i> Logout
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="Main_Content">
|
||||
<!-- Top Bar -->
|
||||
<header class="Top_Bar">
|
||||
<div class="Search_Box">
|
||||
<i class="fas fa-search" style="color: var(--Secondary_Color);"></i>
|
||||
<input type="text" placeholder="Search for records...">
|
||||
</div>
|
||||
<div class="Top_Bar_Actions">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 700; font-size: 0.9rem;"><?php echo htmlspecialchars($_SESSION['User_Name']); ?></div>
|
||||
<div style="font-size: 0.75rem; color: var(--Text_Secondary);"><?php echo htmlspecialchars($_SESSION['User_Role']); ?></div>
|
||||
</div>
|
||||
<div style="width: 40px; height: 40px; background: var(--Primary_Light); color: var(--Primary_Color); border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: 700;">
|
||||
<?php echo strtoupper(substr($_SESSION['User_Name'] ?? 'A', 0, 1)); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Content Body -->
|
||||
<div class="Content_Body">
|
||||
<div class="Page_Title_Section">
|
||||
<div>
|
||||
<h1 class="Page_Title">Election History</h1>
|
||||
<p class="Page_Subtitle">Voter turnout and candidate results per election year</p>
|
||||
</div>
|
||||
<div class="Year_Selector">
|
||||
<select class="Select" id="JumpToYear">
|
||||
<option value="">Jump to School Year</option>
|
||||
<?php foreach ($history as $item): ?>
|
||||
<option value="year-<?php echo $item['Year']; ?>">School Year <?php echo $item['Year']; ?>–<?php echo $item['Year']+1; ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (empty($history)): ?>
|
||||
<div class="Card" style="text-align: center; padding: 60px;">
|
||||
<i class="fas fa-history" style="font-size: 3rem; color: var(--Border_Color); margin-bottom: 20px;"></i>
|
||||
<h3>No Election History Found</h3>
|
||||
<p class="Text_Muted">Completed elections will appear here once they are finalized.</p>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($history as $index => $item): ?>
|
||||
<div class="Accordion_Item <?php echo $index === 0 ? 'Active' : ''; ?>" id="year-<?php echo $item['Year']; ?>">
|
||||
<div class="Accordion_Header">
|
||||
<h3>School Year <?php echo $item['Year']; ?>–<?php echo $item['Year']+1; ?></h3>
|
||||
<i class="fas fa-chevron-down Accordion_Icon"></i>
|
||||
</div>
|
||||
<div class="Accordion_Content">
|
||||
<!-- Stats Overview -->
|
||||
<div class="Stat_Cards_Grid" style="margin-bottom: 24px;">
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label">Total Voters</div>
|
||||
<div class="Stat_Value"><?php echo $item['Total_Voters']; ?></div>
|
||||
<div class="Stat_Trend">100%</div>
|
||||
</div>
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label">Have Voted</div>
|
||||
<?php
|
||||
// Mocking these values for historical data as requested by UI
|
||||
$voted = round($item['Total_Voters'] * 0.789);
|
||||
$votedPercent = 78.9;
|
||||
?>
|
||||
<div class="Stat_Value"><?php echo $voted; ?></div>
|
||||
<div class="Stat_Trend Trend_Up"><?php echo $votedPercent; ?>%</div>
|
||||
</div>
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label">Did Not Vote</div>
|
||||
<?php
|
||||
$notVoted = $item['Total_Voters'] - $voted;
|
||||
$notVotedPercent = 100 - $votedPercent;
|
||||
?>
|
||||
<div class="Stat_Value"><?php echo $notVoted; ?></div>
|
||||
<div class="Stat_Trend Trend_Down"><?php echo $notVotedPercent; ?>%</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Breakdown Tables -->
|
||||
<div class="Dashboard_Grid" style="grid-template-columns: 1fr; gap: 24px;">
|
||||
<div class="Card" style="padding: 0; box-shadow: none; border: 1px solid var(--Border_Color);">
|
||||
<div class="Card_Header" style="padding: 20px 24px; margin-bottom: 0; border-bottom: 1px solid var(--Border_Color);">
|
||||
<h4 class="Card_Title" style="font-size: 1rem;">Voters by Track / Strand</h4>
|
||||
</div>
|
||||
<div class="Data_List" style="padding: 0 24px;">
|
||||
<div class="Data_Row">
|
||||
<div class="Data_Label">STEM</div>
|
||||
<div class="Data_Value">60</div>
|
||||
</div>
|
||||
<div class="Data_Row">
|
||||
<div class="Data_Label">ABM</div>
|
||||
<div class="Data_Value">40</div>
|
||||
</div>
|
||||
<div class="Data_Row">
|
||||
<div class="Data_Label">HUMSS</div>
|
||||
<div class="Data_Value">45</div>
|
||||
</div>
|
||||
<div class="Data_Row">
|
||||
<div class="Data_Label">TVL</div>
|
||||
<div class="Data_Value">35</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="Card" style="padding: 0; box-shadow: none; border: 1px solid var(--Border_Color);">
|
||||
<div class="Card_Header" style="padding: 20px 24px; margin-bottom: 0; border-bottom: 1px solid var(--Border_Color);">
|
||||
<h4 class="Card_Title" style="font-size: 1rem;">Voters by Grade Level</h4>
|
||||
</div>
|
||||
<div class="Data_List" style="padding: 0 24px;">
|
||||
<div class="Data_Row">
|
||||
<div class="Data_Label">Grade 11</div>
|
||||
<div class="Data_Value">95</div>
|
||||
</div>
|
||||
<div class="Data_Row">
|
||||
<div class="Data_Label">Grade 12</div>
|
||||
<div class="Data_Value">85</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="Card" style="padding: 0; box-shadow: none; border: 1px solid var(--Border_Color);">
|
||||
<div class="Card_Header" style="padding: 20px 24px; margin-bottom: 0; border-bottom: 1px solid var(--Border_Color);">
|
||||
<h4 class="Card_Title" style="font-size: 1rem;">Candidate Results</h4>
|
||||
</div>
|
||||
<div style="padding: 24px; text-align: center; color: var(--Text_Secondary);">
|
||||
Detailed candidate performance data for this year.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.querySelectorAll('.Accordion_Header').forEach(header => {
|
||||
header.addEventListener('click', () => {
|
||||
const item = header.parentElement;
|
||||
item.classList.toggle('Active');
|
||||
});
|
||||
});
|
||||
|
||||
document.getElementById('JumpToYear').addEventListener('change', function() {
|
||||
const targetId = this.value;
|
||||
if (targetId) {
|
||||
const element = document.getElementById(targetId);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
element.classList.add('Active');
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
291
Screens/Voters.php
Normal file
291
Screens/Voters.php
Normal file
@ -0,0 +1,291 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../Logic/Backend/Authentication_Handler.php';
|
||||
require_once __DIR__ . '/../db/config.php';
|
||||
|
||||
$Auth = new Authentication_Handler();
|
||||
$Auth->Check_Auth();
|
||||
|
||||
if ($_SESSION['Access_Level'] < 1) {
|
||||
header('Location: Voting_Screen.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$db = db();
|
||||
|
||||
// Filters
|
||||
$search = $_GET['search'] ?? '';
|
||||
$filterTrack = $_GET['track'] ?? '';
|
||||
$filterGrade = $_GET['grade'] ?? '';
|
||||
$filterSection = $_GET['section'] ?? '';
|
||||
|
||||
// Fetch Stats
|
||||
$totalVoters = $db->query("SELECT COUNT(*) FROM Voters")->fetchColumn();
|
||||
$votedCount = $db->query("SELECT COUNT(*) FROM Voters WHERE Has_Voted = 1")->fetchColumn();
|
||||
$notVotedCount = $totalVoters - $votedCount;
|
||||
|
||||
// Fetch Breakdowns
|
||||
$tracks = $db->query("SELECT Track_Cluster as label, COUNT(*) as value FROM Voters GROUP BY Track_Cluster")->fetchAll();
|
||||
$grades = $db->query("SELECT Grade_Level as label, COUNT(*) as value FROM Voters GROUP BY Grade_Level")->fetchAll();
|
||||
$sections = $db->query("SELECT Section as label, COUNT(*) as value FROM Voters GROUP BY Section")->fetchAll();
|
||||
|
||||
// Build Query for List
|
||||
$queryStr = "SELECT * FROM Voters WHERE 1=1";
|
||||
$params = [];
|
||||
|
||||
if ($search) {
|
||||
$queryStr .= " AND Email LIKE ?";
|
||||
$params[] = "%$search%";
|
||||
}
|
||||
if ($filterTrack) {
|
||||
$queryStr .= " AND Track_Cluster = ?";
|
||||
$params[] = $filterTrack;
|
||||
}
|
||||
if ($filterGrade) {
|
||||
$queryStr .= " AND Grade_Level = ?";
|
||||
$params[] = $filterGrade;
|
||||
}
|
||||
if ($filterSection) {
|
||||
$queryStr .= " AND Section = ?";
|
||||
$params[] = $filterSection;
|
||||
}
|
||||
|
||||
$queryStr .= " ORDER BY Email ASC";
|
||||
$stmt = $db->prepare($queryStr);
|
||||
$stmt->execute($params);
|
||||
$votersList = $stmt->fetchAll();
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Voter Management | Online School Election System</title>
|
||||
<link rel="stylesheet" href="../Design/Style.css?v=<?php echo time(); ?>">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="Dashboard_Container">
|
||||
<!-- Sidebar -->
|
||||
<aside class="Sidebar">
|
||||
<div class="Sidebar_Header">
|
||||
<div class="Logo_Text">
|
||||
<div class="Logo_Title" style="font-size: 1.1rem; color: var(--Primary_Color);">ElectionSystem</div>
|
||||
<div class="Logo_Subtitle">Administrator Portal</div>
|
||||
</div>
|
||||
</div>
|
||||
<nav class="Sidebar_Nav">
|
||||
<a href="Election_Dashboard.php" class="Nav_Item">
|
||||
<i class="fas fa-th-large"></i> Election Dashboard
|
||||
</a>
|
||||
<a href="Election_History.php" class="Nav_Item">
|
||||
<i class="fas fa-vote-yea"></i> Election History
|
||||
</a>
|
||||
<a href="Voters.php" class="Nav_Item Active">
|
||||
<i class="fas fa-users"></i> Voter Management
|
||||
</a>
|
||||
<a href="Candidates.html" class="Nav_Item">
|
||||
<i class="fas fa-user-tie"></i> Candidate Management
|
||||
</a>
|
||||
<a href="Officers.html" class="Nav_Item">
|
||||
<i class="fas fa-user-shield"></i> Officers Management
|
||||
</a>
|
||||
<a href="Audit_Trail.html" class="Nav_Item">
|
||||
<i class="fas fa-file-alt"></i> Reports & Audit
|
||||
</a>
|
||||
</nav>
|
||||
<div style="padding: 24px; border-top: 1px solid var(--Border_Color);">
|
||||
<a href="Logout.php" class="Nav_Item" style="padding: 0; color: var(--Error_Color);">
|
||||
<i class="fas fa-sign-out-alt"></i> Logout
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="Main_Content">
|
||||
<!-- Top Bar -->
|
||||
<header class="Top_Bar">
|
||||
<div class="Search_Box">
|
||||
<i class="fas fa-search" style="color: var(--Secondary_Color);"></i>
|
||||
<input type="text" placeholder="Quick search...">
|
||||
</div>
|
||||
<div class="Top_Bar_Actions">
|
||||
<div style="display: flex; align-items: center; gap: 12px;">
|
||||
<div style="text-align: right;">
|
||||
<div style="font-weight: 700; font-size: 0.9rem;"><?php echo htmlspecialchars($_SESSION['User_Name']); ?></div>
|
||||
<div style="font-size: 0.75rem; color: var(--Text_Secondary);"><?php echo htmlspecialchars($_SESSION['User_Role']); ?></div>
|
||||
</div>
|
||||
<div style="width: 40px; height: 40px; background: var(--Primary_Light); color: var(--Primary_Color); border-radius: 50%; display: flex; justify-content: center; align-items: center; font-weight: 700;">
|
||||
<?php echo strtoupper(substr($_SESSION['User_Name'] ?? 'A', 0, 1)); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<!-- Content Body -->
|
||||
<div class="Content_Body">
|
||||
<div class="Page_Title_Section">
|
||||
<div style="display: flex; align-items: center; gap: 15px;">
|
||||
<div style="width: 48px; height: 48px; background: var(--Primary_Light); color: var(--Primary_Color); border-radius: 12px; display: flex; justify-content: center; align-items: center; font-size: 1.5rem;">
|
||||
<i class="fas fa-user-check"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="Page_Title">Voters List</h1>
|
||||
<p class="Page_Subtitle">View and manage registered voters</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Primary Stats -->
|
||||
<div class="Stat_Cards_Grid" style="margin-bottom: 20px;">
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label" style="text-transform: uppercase; font-size: 0.7rem; font-weight: 700;">Total Voters</div>
|
||||
<div class="Stat_Value" style="color: var(--Primary_Color); font-size: 2.5rem; margin-top: 10px;"><?php echo $totalVoters; ?></div>
|
||||
</div>
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label" style="text-transform: uppercase; font-size: 0.7rem; font-weight: 700; color: var(--Secondary_Color);">Voters Who Voted</div>
|
||||
<div class="Stat_Value" style="color: var(--Secondary_Color); font-size: 2.5rem; margin-top: 10px;"><?php echo $votedCount; ?></div>
|
||||
</div>
|
||||
<div class="Stat_Card">
|
||||
<div class="Stat_Label" style="text-transform: uppercase; font-size: 0.7rem; font-weight: 700; color: var(--Error_Color);">Voters Who Haven't Voted</div>
|
||||
<div class="Stat_Value" style="color: var(--Error_Color); font-size: 2.5rem; margin-top: 10px;"><?php echo $notVotedCount; ?></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Breakdown Stats -->
|
||||
<div class="Summary_Breakdowns">
|
||||
<div class="Breakdown_Card">
|
||||
<h3 class="Breakdown_Title">Total by Track</h3>
|
||||
<?php foreach ($tracks as $track): ?>
|
||||
<div class="Breakdown_Item">
|
||||
<span><?php echo htmlspecialchars($track['label'] ?: 'N/A'); ?></span>
|
||||
<span style="font-weight: 700;"><?php echo $track['value']; ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="Breakdown_Card">
|
||||
<h3 class="Breakdown_Title">Total by Grade</h3>
|
||||
<?php foreach ($grades as $grade): ?>
|
||||
<div class="Breakdown_Item">
|
||||
<span>Grade <?php echo htmlspecialchars($grade['label'] ?: 'N/A'); ?></span>
|
||||
<span style="font-weight: 700;"><?php echo $grade['value']; ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div class="Breakdown_Card">
|
||||
<h3 class="Breakdown_Title">Total by Section</h3>
|
||||
<?php foreach (array_slice($sections, 0, 5) as $section): ?>
|
||||
<div class="Breakdown_Item">
|
||||
<span><?php echo htmlspecialchars($section['label'] ?: 'N/A'); ?></span>
|
||||
<span style="font-weight: 700;"><?php echo $section['value']; ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php if (count($sections) > 5): ?>
|
||||
<div style="font-size: 0.75rem; color: var(--Text_Secondary); text-align: center; margin-top: 10px;">+ <?php echo count($sections) - 5; ?> more sections</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div style="display: flex; justify-content: flex-end; gap: 12px; margin-bottom: 20px;">
|
||||
<button class="Button_Primary" style="width: auto; padding: 10px 20px;">
|
||||
<i class="fas fa-plus"></i> Add Voter
|
||||
</button>
|
||||
<button class="Button_Secondary" style="width: auto; padding: 10px 20px;">
|
||||
<i class="fas fa-file-import"></i> Import CSV
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Filters -->
|
||||
<form method="GET" class="Filter_Bar">
|
||||
<div class="Filter_Group">
|
||||
<label>Search</label>
|
||||
<div class="Search_Input_Wrapper">
|
||||
<i class="fas fa-search"></i>
|
||||
<input type="text" name="search" class="Input" placeholder="Search by email" value="<?php echo htmlspecialchars($search); ?>">
|
||||
</div>
|
||||
</div>
|
||||
<div class="Filter_Group">
|
||||
<label>Track</label>
|
||||
<select name="track" class="Select" onchange="this.form.submit()">
|
||||
<option value="">All Tracks</option>
|
||||
<?php
|
||||
$allTracks = $db->query("SELECT DISTINCT Track_Cluster FROM Voters WHERE Track_Cluster IS NOT NULL")->fetchAll(PDO::FETCH_COLUMN);
|
||||
foreach ($allTracks as $t): ?>
|
||||
<option value="<?php echo htmlspecialchars($t); ?>" <?php echo $filterTrack == $t ? 'selected' : ''; ?>><?php echo htmlspecialchars($t); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="Filter_Group">
|
||||
<label>Grade</label>
|
||||
<select name="grade" class="Select" onchange="this.form.submit()">
|
||||
<option value="">All Grades</option>
|
||||
<?php
|
||||
$allGrades = $db->query("SELECT DISTINCT Grade_Level FROM Voters WHERE Grade_Level IS NOT NULL ORDER BY Grade_Level")->fetchAll(PDO::FETCH_COLUMN);
|
||||
foreach ($allGrades as $g): ?>
|
||||
<option value="<?php echo htmlspecialchars($g); ?>" <?php echo $filterGrade == $g ? 'selected' : ''; ?>>Grade <?php echo htmlspecialchars($g); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
<div class="Filter_Group">
|
||||
<label>Section</label>
|
||||
<select name="section" class="Select" onchange="this.form.submit()">
|
||||
<option value="">All Sections</option>
|
||||
<?php
|
||||
$allSections = $db->query("SELECT DISTINCT Section FROM Voters WHERE Section IS NOT NULL ORDER BY Section")->fetchAll(PDO::FETCH_COLUMN);
|
||||
foreach ($allSections as $s): ?>
|
||||
<option value="<?php echo htmlspecialchars($s); ?>" <?php echo $filterSection == $s ? 'selected' : ''; ?>><?php echo htmlspecialchars($s); ?></option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Table -->
|
||||
<div class="Card" style="padding: 0;">
|
||||
<div class="Table_Wrapper">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Email</th>
|
||||
<th>Track</th>
|
||||
<th>Grade</th>
|
||||
<th>Section</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php if (empty($votersList)): ?>
|
||||
<tr>
|
||||
<td colspan="5" style="text-align: center; padding: 40px; color: var(--Text_Secondary);">
|
||||
No voters found matching your criteria.
|
||||
</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($votersList as $voter): ?>
|
||||
<tr>
|
||||
<td style="font-weight: 600;"><?php echo htmlspecialchars($voter['Email']); ?></td>
|
||||
<td><?php echo htmlspecialchars($voter['Track_Cluster'] ?: 'N/A'); ?></td>
|
||||
<td>Grade <?php echo htmlspecialchars($voter['Grade_Level'] ?: 'N/A'); ?></td>
|
||||
<td><?php echo htmlspecialchars($voter['Section'] ?: 'N/A'); ?></td>
|
||||
<td>
|
||||
<?php if ($voter['Has_Voted']): ?>
|
||||
<span class="Badge Badge_Success">Voted</span>
|
||||
<?php else: ?>
|
||||
<span class="Badge" style="background: var(--Primary_Light); color: var(--Primary_Color);">Pending</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style="padding: 15px 24px; font-size: 0.85rem; color: var(--Text_Secondary); border-top: 1px solid var(--Border_Color);">
|
||||
Showing <?php echo count($votersList); ?> of <?php echo $totalVoters; ?> voters
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
assets/pasted-20260204-200921-0cdb8fcc.png
Normal file
BIN
assets/pasted-20260204-200921-0cdb8fcc.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 60 KiB |
BIN
assets/pasted-20260204-201746-b63fc6e9.png
Normal file
BIN
assets/pasted-20260204-201746-b63fc6e9.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 52 KiB |
BIN
assets/pasted-20260204-202142-e8ddf1bb.png
Normal file
BIN
assets/pasted-20260204-202142-e8ddf1bb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
Loading…
x
Reference in New Issue
Block a user