feat: admin panel login, layout, and styles
Add the admin CRM panel foundation including: - Login/logout authentication flow with CSRF protection - Sidebar layout with navigation for all CRM modules - Comprehensive admin.css (1680+ lines) with components for cards, tables, badges, forms, buttons, alerts, modals, pagination, search, responsive breakpoints, and print styles - admin.js with sidebar toggle, confirm dialogs, auto-dismiss alerts, and table search filtering Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
7
admin/includes/admin-footer.php
Normal file
7
admin/includes/admin-footer.php
Normal file
@@ -0,0 +1,7 @@
|
||||
</div><!-- /.admin-content -->
|
||||
</div><!-- /.admin-main -->
|
||||
|
||||
<div class="sidebar-overlay" id="sidebarOverlay"></div>
|
||||
<script src="../assets/js/admin.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
68
admin/includes/admin-header.php
Normal file
68
admin/includes/admin-header.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../../includes/auth.php';
|
||||
require_once __DIR__ . '/../../includes/csrf.php';
|
||||
authRequire();
|
||||
authStart();
|
||||
$currentPage = basename($_SERVER['PHP_SELF'], '.php');
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title><?= isset($pageTitle) ? htmlspecialchars($pageTitle) : 'Admin' ?> - Gestoría LP</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="../assets/css/admin.css">
|
||||
</head>
|
||||
<body class="admin-body">
|
||||
<!-- Sidebar -->
|
||||
<aside class="sidebar" id="sidebar">
|
||||
<div class="sidebar__brand">
|
||||
<i class="fas fa-balance-scale"></i>
|
||||
<span>Gestoría LP</span>
|
||||
</div>
|
||||
<nav class="sidebar__nav">
|
||||
<a href="index.php" class="sidebar__link <?= $currentPage === 'index' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-tachometer-alt"></i> <span>Dashboard</span>
|
||||
</a>
|
||||
<a href="clientes.php" class="sidebar__link <?= $currentPage === 'clientes' || $currentPage === 'cliente-detalle' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-users"></i> <span>Clientes</span>
|
||||
</a>
|
||||
<a href="tramites.php" class="sidebar__link <?= $currentPage === 'tramites' || $currentPage === 'tramite-detalle' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-file-alt"></i> <span>Trámites</span>
|
||||
</a>
|
||||
<a href="solicitudes.php" class="sidebar__link <?= $currentPage === 'solicitudes' || $currentPage === 'solicitud-detalle' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-inbox"></i> <span>Solicitudes</span>
|
||||
</a>
|
||||
<a href="recordatorios.php" class="sidebar__link <?= $currentPage === 'recordatorios' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-bell"></i> <span>Recordatorios</span>
|
||||
</a>
|
||||
<a href="testimonios.php" class="sidebar__link <?= $currentPage === 'testimonios' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-star"></i> <span>Testimonios</span>
|
||||
</a>
|
||||
<a href="carga-historial.php" class="sidebar__link <?= $currentPage === 'carga-historial' ? 'sidebar__link--active' : '' ?>">
|
||||
<i class="fas fa-upload"></i> <span>Carga Historial</span>
|
||||
</a>
|
||||
</nav>
|
||||
<div class="sidebar__footer">
|
||||
<a href="logout.php" class="sidebar__link sidebar__link--logout">
|
||||
<i class="fas fa-sign-out-alt"></i> <span>Cerrar Sesión</span>
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<!-- Main Content -->
|
||||
<div class="admin-main">
|
||||
<header class="admin-topbar">
|
||||
<button class="sidebar-toggle" id="sidebarToggle">
|
||||
<i class="fas fa-bars"></i>
|
||||
</button>
|
||||
<div class="admin-topbar__right">
|
||||
<span class="admin-topbar__user">
|
||||
<i class="fas fa-user-circle"></i> <?= htmlspecialchars($_SESSION['username'] ?? 'Admin') ?>
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<div class="admin-content">
|
||||
68
admin/login.php
Normal file
68
admin/login.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
require_once __DIR__ . '/../includes/csrf.php';
|
||||
|
||||
authStart();
|
||||
|
||||
// Already logged in?
|
||||
if (authCheck()) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
}
|
||||
|
||||
$error = '';
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (!csrfValidate()) {
|
||||
$error = 'Token de seguridad inválido.';
|
||||
} else {
|
||||
$username = trim($_POST['username'] ?? '');
|
||||
$password = $_POST['password'] ?? '';
|
||||
if (authLogin($username, $password)) {
|
||||
header('Location: index.php');
|
||||
exit;
|
||||
} else {
|
||||
$error = 'Usuario o contraseña incorrectos.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="es">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - Gestoría LP Admin</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
<link rel="stylesheet" href="../assets/css/admin.css">
|
||||
</head>
|
||||
<body class="login-page">
|
||||
<div class="login-container">
|
||||
<div class="login-card">
|
||||
<div class="login-card__header">
|
||||
<i class="fas fa-balance-scale"></i>
|
||||
<h1>Gestoría LP</h1>
|
||||
<p>Panel de Administración</p>
|
||||
</div>
|
||||
<?php if ($error): ?>
|
||||
<div class="alert alert--danger"><?= htmlspecialchars($error) ?></div>
|
||||
<?php endif; ?>
|
||||
<form method="POST" class="login-form">
|
||||
<?= csrfField() ?>
|
||||
<div class="form-group">
|
||||
<label for="username"><i class="fas fa-user"></i> Usuario</label>
|
||||
<input type="text" id="username" name="username" required autofocus placeholder="Ingresa tu usuario">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password"><i class="fas fa-lock"></i> Contraseña</label>
|
||||
<input type="password" id="password" name="password" required placeholder="Ingresa tu contraseña">
|
||||
</div>
|
||||
<button type="submit" class="btn btn--primary btn--block">
|
||||
<i class="fas fa-sign-in-alt"></i> Iniciar Sesión
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
5
admin/logout.php
Normal file
5
admin/logout.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../includes/auth.php';
|
||||
authLogout();
|
||||
header('Location: login.php');
|
||||
exit;
|
||||
1684
assets/css/admin.css
Normal file
1684
assets/css/admin.css
Normal file
File diff suppressed because it is too large
Load Diff
55
assets/js/admin.js
Normal file
55
assets/js/admin.js
Normal file
@@ -0,0 +1,55 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Sidebar toggle
|
||||
const sidebar = document.getElementById('sidebar');
|
||||
const sidebarToggle = document.getElementById('sidebarToggle');
|
||||
const sidebarOverlay = document.getElementById('sidebarOverlay');
|
||||
|
||||
if (sidebarToggle) {
|
||||
sidebarToggle.addEventListener('click', function() {
|
||||
sidebar.classList.toggle('sidebar--open');
|
||||
sidebarOverlay.classList.toggle('active');
|
||||
document.body.classList.toggle('sidebar-open');
|
||||
});
|
||||
}
|
||||
|
||||
if (sidebarOverlay) {
|
||||
sidebarOverlay.addEventListener('click', function() {
|
||||
sidebar.classList.remove('sidebar--open');
|
||||
sidebarOverlay.classList.remove('active');
|
||||
document.body.classList.remove('sidebar-open');
|
||||
});
|
||||
}
|
||||
|
||||
// Confirm delete actions
|
||||
document.querySelectorAll('[data-confirm]').forEach(function(el) {
|
||||
el.addEventListener('click', function(e) {
|
||||
if (!confirm(this.dataset.confirm)) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Auto-dismiss alerts after 5 seconds
|
||||
document.querySelectorAll('.alert--dismissible').forEach(function(alert) {
|
||||
setTimeout(function() {
|
||||
alert.style.opacity = '0';
|
||||
alert.style.transform = 'translateY(-10px)';
|
||||
setTimeout(function() { alert.remove(); }, 300);
|
||||
}, 5000);
|
||||
});
|
||||
|
||||
// Table search filter
|
||||
var searchInput = document.getElementById('tableSearch');
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('input', function() {
|
||||
var query = this.value.toLowerCase();
|
||||
var table = document.querySelector('.admin-table');
|
||||
if (!table) return;
|
||||
var rows = table.querySelectorAll('tbody tr');
|
||||
rows.forEach(function(row) {
|
||||
var text = row.textContent.toLowerCase();
|
||||
row.style.display = text.includes(query) ? '' : 'none';
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user