feat: refine email routing logic, fix timezone + FK bugs, update DB schema & add full user dashboard

This commit is contained in:
2026-01-01 03:44:22 +05:30
Unverified
parent c28917ef49
commit 0de81cf56e
10 changed files with 115 additions and 92 deletions

View File

@@ -1,3 +1,49 @@
<?php
date_default_timezone_set('Asia/Kolkata');
$conn->query("SET time_zone = '+05:30'");
$totalResult = $conn->query("SELECT COUNT(*) FROM reports");
$totalReports = $totalResult->fetch_row()[0];
$activeResult = $conn->query("SELECT COUNT(*) FROM reports WHERE status IN ('Opened', 'In Progress')");
$activeReports = $activeResult->fetch_row()[0];
$resolvedResult = $conn->query("SELECT COUNT(*) FROM reports WHERE status = 'Resolved'");
$resolvedReports = $resolvedResult->fetch_row()[0];
$recentSql = "SELECT r.*, u.username
FROM reports r
JOIN users u ON r.user_id = u.id
ORDER BY r.updated_at DESC
LIMIT 5";
$recentResult = $conn->query($recentSql);
$recentActivity = $recentResult->fetch_all(MYSQLI_ASSOC);
if (!function_exists('time_elapsed_string')) {
function time_elapsed_string($datetime, $full = false) {
$now = new DateTime;
$ago = new DateTime($datetime);
$diff = $now->diff($ago);
$diff->w = floor($diff->d / 7);
$diff->d -= $diff->w * 7;
$string = array('y' => 'yr', 'm' => 'mo', 'w' => 'wk', 'd' => 'd', 'h' => 'h', 'i' => 'min', 's' => 'sec');
foreach ($string as $k => &$v) {
if ($diff->$k) {
$v = $diff->$k . '' . $v;
} else {
unset($string[$k]);
}
}
if (!$full) $string = array_slice($string, 0, 1);
return $string ? implode(', ', $string) . ' ago' : 'just now';
}
}
?>
<div class="max-w-6xl mx-auto w-full">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-4">
@@ -5,7 +51,7 @@
<div class="group bg-neutral-800 rounded-lg border border-neutral-700/50 p-4 shadow-sm hover:border-blue-500/30 transition-all duration-300 flex items-center justify-between">
<div>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-blue-400 transition-colors">Total Reports</h3>
<p class="text-2xl font-bold text-white mt-1">128</p>
<p class="text-2xl font-bold text-white mt-1"><?= $totalReports ?></p>
<p class="text-[10px] text-neutral-500 mt-1">All submissions overview</p>
</div>
<div class="p-3 bg-blue-500/10 rounded-lg group-hover:bg-blue-500/20 transition-colors">
@@ -17,8 +63,8 @@
<div class="group bg-neutral-800 rounded-lg border border-neutral-700/50 p-4 shadow-sm hover:border-yellow-500/30 transition-all duration-300 flex items-center justify-between">
<div>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-yellow-400 transition-colors">Active Issues</h3>
<p class="text-2xl font-bold text-white mt-1">42</p>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-yellow-400 transition-colors">Reports In Progress</h3>
<p class="text-2xl font-bold text-white mt-1"><?= $activeReports ?></p>
<p class="text-[10px] text-neutral-500 mt-1">In progress / Open</p>
</div>
<div class="p-3 bg-yellow-500/10 rounded-lg group-hover:bg-yellow-500/20 transition-colors">
@@ -30,8 +76,8 @@
<div class="group bg-neutral-800 rounded-lg border border-neutral-700/50 p-4 shadow-sm hover:border-green-500/30 transition-all duration-300 flex items-center justify-between">
<div>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-green-400 transition-colors">Resolved</h3>
<p class="text-2xl font-bold text-white mt-1">86</p>
<h3 class="text-xs font-semibold text-neutral-400 uppercase tracking-wider group-hover:text-green-400 transition-colors">Resolved Reports</h3>
<p class="text-2xl font-bold text-white mt-1"><?= $resolvedReports ?></p>
<p class="text-[10px] text-neutral-500 mt-1">Successfully closed</p>
</div>
<div class="p-3 bg-green-500/10 rounded-lg group-hover:bg-green-500/20 transition-colors">
@@ -44,52 +90,55 @@
<div class="bg-neutral-800 rounded-lg border border-neutral-700 overflow-hidden shadow-sm">
<div class="px-4 py-3 border-b border-neutral-700 flex items-center justify-between bg-neutral-900/30">
<h3 class="text-sm font-semibold text-white">Recent Activity</h3>
<button class="text-xs text-blue-400 hover:text-blue-300 font-medium transition-colors">View All</button>
<div class="flex items-center gap-2">
<h3 class="text-sm font-semibold text-white">Recents on reports:</h3>
</div>
</div>
<div class="divide-y divide-neutral-700/50">
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-green-500/10 border border-green-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/></svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">
Issue <span class="text-white hover:underline cursor-pointer">#1231</span> Resolved
</p>
<span class="text-[10px] text-neutral-500 whitespace-nowrap">2h ago</span>
</div>
<p class="text-xs text-neutral-500 truncate">Water leakage in park <span>23/v/kpc-cst/33</span></p>
</div>
</div>
<?php if (count($recentActivity) > 0): ?>
<?php foreach ($recentActivity as $row): ?>
<?php
$statusColor = 'blue';
$iconPath = 'M12 4v16m8-8H4';
if ($row['status'] === 'Resolved') {
$statusColor = 'green';
$iconPath = 'M5 13l4 4L19 7';
} elseif ($row['status'] === 'In Progress') {
$statusColor = 'yellow';
$iconPath = 'M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z';
}
?>
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-blue-500/10 border border-blue-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-blue-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"/></svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">Issue 1234 submitted</p>
<span class="text-[10px] text-neutral-500 whitespace-nowrap">5h ago</span>
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-<?= $statusColor ?>-500/10 border border-<?= $statusColor ?>-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-<?= $statusColor ?>-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="<?= $iconPath ?>"/>
</svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">
Issue <span class="text-white">#<?= $row['id'] ?></span> <?= htmlspecialchars($row['status']) ?>
</p>
<span class="text-[10px] text-neutral-400 whitespace-nowrap">
<?= time_elapsed_string($row['updated_at']) ?>
</span>
</div>
<p class="text-xs text-neutral-400 truncate">
<?= htmlspecialchars($row['title']) ?> • <span><?= htmlspecialchars($row['username']) ?></span>
</p>
</div>
</div>
<p class="text-xs text-neutral-500 truncate">Pothole on Main Street <span>23/v/kpc-cst/36</span></p>
<?php endforeach; ?>
<?php else: ?>
<div class="px-4 py-6 text-center text-sm text-neutral-500">
No recent activity found.
</div>
</div>
<div class="px-4 py-3 hover:bg-neutral-700/30 transition-colors flex items-center gap-3">
<div class="flex-shrink-0 w-8 h-8 rounded-full bg-yellow-500/10 border border-yellow-500/20 flex items-center justify-center">
<svg class="w-4 h-4 text-yellow-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
</div>
<div class="flex-1 min-w-0 grid gap-0.5">
<div class="flex items-center justify-between">
<p class="text-sm font-medium text-neutral-200 truncate">Status: In Progress</p>
<span class="text-[10px] text-neutral-500 whitespace-nowrap">1d ago</span>
</div>
<p class="text-xs text-neutral-500 truncate">Broken Street Light <span>23/v/kpc-cst/37</span></p>
</div>
</div>
<?php endif; ?>
</div>
</div>

View File

@@ -25,7 +25,7 @@ if (count($whereClauses) > 0) {
$whereSql = "WHERE " . implode(' AND ', $whereClauses);
}
$limit = 6;
$limit = 4;
$page = isset($_GET['p']) ? max(1, intval($_GET['p'])) : 1;
$offset = ($page - 1) * $limit;
@@ -34,7 +34,7 @@ $count_result = $conn->query($count_sql);
$total_rows = $count_result->fetch_assoc()['total'];
$total_pages = ceil($total_rows / $limit);
$sql = "SELECT r.*, u.username FROM reports r LEFT JOIN users u ON r.user_id = u.id $whereSql ORDER BY r.created_at DESC LIMIT $limit OFFSET $offset";
$sql = "SELECT r.*, u.username FROM reports r LEFT JOIN users u ON r.user_id = u.id $whereSql ORDER BY r.id DESC LIMIT $limit OFFSET $offset";
$result = $conn->query($sql);
?>
@@ -91,8 +91,8 @@ $result = $conn->query($sql);
?>
<button type="button" onclick="setStatusAndSubmit('')"
class="<?php echo getBtnClass($current_status === ''); ?>">All Reports</button>
<button type="button" onclick="setStatusAndSubmit('Open')"
class="<?php echo getBtnClass($current_status === 'Open'); ?>">Open</button>
<button type="button" onclick="setStatusAndSubmit('Opened')"
class="<?php echo getBtnClass($current_status === 'Opened'); ?>">Opened</button>
<button type="button" onclick="setStatusAndSubmit('In Progress')"
class="<?php echo getBtnClass($current_status === 'In Progress'); ?>">In Progress</button>
<button type="button" onclick="setStatusAndSubmit('Resolved')"