From 660d41fb31ba1d665fff72220ab7b77196c55a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gestor=C3=ADa=20LP?= Date: Mon, 2 Mar 2026 00:21:58 +0000 Subject: [PATCH] feat: admin dashboard with stats and recent activity Co-Authored-By: Claude Opus 4.6 --- admin/index.php | 192 +++++++++++++++++++++++++++++++++++++++++++ assets/css/admin.css | 138 ++++++++++++++++++++++++++++++- 2 files changed, 329 insertions(+), 1 deletion(-) create mode 100644 admin/index.php diff --git a/admin/index.php b/admin/index.php new file mode 100644 index 0000000..b01220e --- /dev/null +++ b/admin/index.php @@ -0,0 +1,192 @@ +query("SELECT COUNT(*) FROM solicitudes WHERE estado='nueva'")->fetchColumn(); +$tramitesEnProceso = $db->query("SELECT COUNT(*) FROM tramites WHERE estado='en_proceso'")->fetchColumn(); +$tramitesCompletados = $db->query("SELECT COUNT(*) FROM tramites WHERE estado='completado'")->fetchColumn(); +$totalClientes = $db->query("SELECT COUNT(*) FROM clientes")->fetchColumn(); + +// Latest requests +$ultimasSolicitudes = $db->query("SELECT * FROM solicitudes WHERE estado='nueva' ORDER BY created_at DESC LIMIT 5")->fetchAll(); + +// Upcoming reminders +$recordatorios = $db->query("SELECT r.*, c.nombre as cliente_nombre FROM recordatorios r LEFT JOIN clientes c ON r.cliente_id = c.id WHERE r.completado=0 AND r.fecha <= DATE_ADD(CURDATE(), INTERVAL 7 DAY) ORDER BY r.fecha ASC LIMIT 5")->fetchAll(); + +// Recent processes +$tramitesRecientes = $db->query("SELECT t.*, c.nombre as cliente_nombre FROM tramites t JOIN clientes c ON t.cliente_id = c.id ORDER BY t.updated_at DESC LIMIT 5")->fetchAll(); + +$tipoLabels = [ + 'visa' => 'Visa', + 'sentri' => 'Sentri/Global', + 'pasaporte' => 'Pasaporte', + 'adelanto_cita' => 'Adelanto Cita', + 'doble_nacionalidad' => 'Doble Nacionalidad', +]; + +$estadoLabels = [ + 'nuevo' => 'Nuevo', + 'en_proceso' => 'En Proceso', + 'en_revision' => 'En Revisión', + 'completado' => 'Completado', + 'cancelado' => 'Cancelado', +]; +?> + +
+

Dashboard

+

Bienvenido,

+
+ + +
+
+
+ +
+
+ + Solicitudes Nuevas +
+
+
+
+ +
+
+ + Trámites en Proceso +
+
+
+
+ +
+
+ + Completados +
+
+
+
+ +
+
+ + Total Clientes +
+
+
+ + +
+ +
+
+

Solicitudes Recientes

+ Ver todas +
+
+ +

No hay solicitudes nuevas

+ +
+ + + + + + + + + + + + + + + + + + + +
NombreServicioFechaAcción
Ver
+
+ +
+
+ + +
+
+

Recordatorios Próximos

+ Ver todos +
+
+ +

No hay recordatorios pendientes

+ +
    + +
  • +
    + + +
    +
    + + + + +
    +
  • + +
+ +
+
+
+ + +
+
+

Trámites Recientes

+ Ver todos +
+
+ +

No hay trámites registrados

+ +
+ + + + + + + + + + + + + + + + + + + + + +
ClienteTipoEstadoFecha SolicitudAcción
Ver
+
+ +
+
+ + diff --git a/assets/css/admin.css b/assets/css/admin.css index 11fc365..cfe749d 100644 --- a/assets/css/admin.css +++ b/assets/css/admin.css @@ -1625,7 +1625,143 @@ textarea.form-control { } /* ========================================================== - 23. PRINT STYLES + 23. DASHBOARD + ========================================================== */ + +/* stat-card__number — alias for stat-card__value used on dashboard */ +.stat-card__number { + font-size: var(--admin-font-2xl); + font-weight: 700; + color: var(--admin-gray-900); + line-height: 1.2; + display: block; +} + +/* Card body (generic content area inside .card) */ +.card__body { + /* inherits padding from .card; no extra padding needed */ +} + +/* Card header headings */ +.card__header h2 { + font-size: var(--admin-font-md); + font-weight: 600; + color: var(--admin-gray-900); + display: flex; + align-items: center; + gap: 0.5rem; +} + +.card__header h2 i { + color: var(--admin-primary); + font-size: var(--admin-font-base); +} + +/* Dashboard two-column grid */ +.dashboard-grid { + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 1.5rem; +} + +@media (max-width: 992px) { + .dashboard-grid { + grid-template-columns: 1fr; + } +} + +/* Reminder list */ +.reminder-list { + list-style: none; + padding: 0; + margin: 0; + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.reminder-item { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.75rem; + border-radius: var(--admin-radius); + background: var(--admin-gray-100); + transition: var(--admin-transition); +} + +.reminder-item:hover { + background: var(--admin-gray-200); +} + +.reminder-item--overdue { + background: var(--admin-danger-light); + border-left: 3px solid var(--admin-danger); +} + +.reminder-item--overdue:hover { + background: #f5c6cb; +} + +.reminder-item--today { + background: var(--admin-warning-light); + border-left: 3px solid var(--admin-warning); +} + +.reminder-item--today:hover { + background: #ffe8a1; +} + +.reminder-item__date { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + min-width: 48px; + height: 48px; + background: var(--admin-white); + border-radius: var(--admin-radius-sm); + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08); + flex-shrink: 0; +} + +.reminder-item__day { + font-size: var(--admin-font-lg); + font-weight: 700; + color: var(--admin-gray-900); + line-height: 1.1; +} + +.reminder-item__month { + font-size: var(--admin-font-xs); + color: var(--admin-gray-600); + text-transform: uppercase; + font-weight: 600; + letter-spacing: 0.05em; +} + +.reminder-item__info { + display: flex; + flex-direction: column; + gap: 0.125rem; + min-width: 0; +} + +.reminder-item__info strong { + font-size: var(--admin-font-sm); + color: var(--admin-gray-800); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.reminder-item__info small { + font-size: var(--admin-font-xs); + color: var(--admin-gray-600); +} + +/* ========================================================== + 24. PRINT STYLES ========================================================== */ @media print { .sidebar,