feat: admin clients module with CRUD, credentials, documents
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
152
admin/clientes.php
Normal file
152
admin/clientes.php
Normal file
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
$pageTitle = 'Clientes';
|
||||
require_once __DIR__ . '/../includes/db.php';
|
||||
require_once __DIR__ . '/includes/admin-header.php';
|
||||
|
||||
$db = getDB();
|
||||
|
||||
// Search & Pagination
|
||||
$q = trim($_GET['q'] ?? '');
|
||||
$page = max(1, (int)($_GET['page'] ?? 1));
|
||||
$perPage = 15;
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
// Build query
|
||||
$where = '';
|
||||
$params = [];
|
||||
if ($q !== '') {
|
||||
$where = 'WHERE c.nombre LIKE ? OR c.telefono LIKE ? OR c.email LIKE ?';
|
||||
$like = '%' . $q . '%';
|
||||
$params = [$like, $like, $like];
|
||||
}
|
||||
|
||||
// Count total
|
||||
$countSql = "SELECT COUNT(DISTINCT c.id) FROM clientes c $where";
|
||||
$countStmt = $db->prepare($countSql);
|
||||
$countStmt->execute($params);
|
||||
$totalClientes = $countStmt->fetchColumn();
|
||||
$totalPages = max(1, (int)ceil($totalClientes / $perPage));
|
||||
|
||||
// Fetch clients with tramites count
|
||||
$sql = "SELECT c.*, COUNT(t.id) AS total_tramites
|
||||
FROM clientes c
|
||||
LEFT JOIN tramites t ON c.id = t.cliente_id
|
||||
$where
|
||||
GROUP BY c.id
|
||||
ORDER BY c.created_at DESC
|
||||
LIMIT $perPage OFFSET $offset";
|
||||
$stmt = $db->prepare($sql);
|
||||
$stmt->execute($params);
|
||||
$clientes = $stmt->fetchAll();
|
||||
?>
|
||||
|
||||
<div class="admin-content__header">
|
||||
<h1><i class="fas fa-users"></i> Clientes</h1>
|
||||
<p>Gestión de clientes registrados</p>
|
||||
</div>
|
||||
|
||||
<!-- Toolbar: Search + New Client -->
|
||||
<div class="toolbar">
|
||||
<div class="toolbar__left">
|
||||
<form method="GET" class="search-bar" action="clientes.php">
|
||||
<i class="fas fa-search search-bar__icon"></i>
|
||||
<input type="text" name="q" class="search-bar__input" placeholder="Buscar por nombre, teléfono o email..." value="<?= htmlspecialchars($q) ?>">
|
||||
</form>
|
||||
<?php if ($q !== ''): ?>
|
||||
<a href="clientes.php" class="btn btn--sm btn--secondary">
|
||||
<i class="fas fa-times"></i> Limpiar
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="toolbar__right">
|
||||
<a href="cliente-detalle.php" class="btn btn--primary">
|
||||
<i class="fas fa-plus"></i> Nuevo Cliente
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Clients Table -->
|
||||
<div class="card">
|
||||
<div class="card__body">
|
||||
<?php if (empty($clientes)): ?>
|
||||
<div class="table-empty">
|
||||
<i class="fas fa-users"></i>
|
||||
<p><?= $q !== '' ? 'No se encontraron clientes con esa búsqueda.' : 'No hay clientes registrados aún.' ?></p>
|
||||
<?php if ($q !== ''): ?>
|
||||
<a href="clientes.php" class="btn btn--sm btn--outline">Ver todos</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="table-responsive">
|
||||
<table class="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Teléfono</th>
|
||||
<th>Email</th>
|
||||
<th>Trámites</th>
|
||||
<th>Fecha Registro</th>
|
||||
<th>Acción</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($clientes as $c): ?>
|
||||
<tr>
|
||||
<td><strong><?= htmlspecialchars($c['nombre']) ?></strong></td>
|
||||
<td><?= htmlspecialchars($c['telefono'] ?: '-') ?></td>
|
||||
<td><?= htmlspecialchars($c['email'] ?: '-') ?></td>
|
||||
<td>
|
||||
<span class="badge badge--info"><?= (int)$c['total_tramites'] ?></span>
|
||||
</td>
|
||||
<td><?= date('d/m/Y', strtotime($c['created_at'])) ?></td>
|
||||
<td>
|
||||
<a href="cliente-detalle.php?id=<?= (int)$c['id'] ?>" class="btn btn--sm btn--primary">
|
||||
<i class="fas fa-eye"></i> Ver
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Pagination -->
|
||||
<?php if ($totalPages > 1): ?>
|
||||
<div class="pagination">
|
||||
<?php
|
||||
$queryParams = $q !== '' ? '&q=' . urlencode($q) : '';
|
||||
?>
|
||||
<a href="?page=1<?= $queryParams ?>" class="pagination__link <?= $page <= 1 ? 'pagination__link--disabled' : '' ?>">
|
||||
<i class="fas fa-angle-double-left"></i>
|
||||
</a>
|
||||
<a href="?page=<?= $page - 1 ?><?= $queryParams ?>" class="pagination__link <?= $page <= 1 ? 'pagination__link--disabled' : '' ?>">
|
||||
<i class="fas fa-angle-left"></i>
|
||||
</a>
|
||||
|
||||
<?php
|
||||
$start = max(1, $page - 2);
|
||||
$end = min($totalPages, $page + 2);
|
||||
for ($i = $start; $i <= $end; $i++):
|
||||
?>
|
||||
<a href="?page=<?= $i ?><?= $queryParams ?>" class="pagination__link <?= $i === $page ? 'pagination__link--active' : '' ?>">
|
||||
<?= $i ?>
|
||||
</a>
|
||||
<?php endfor; ?>
|
||||
|
||||
<a href="?page=<?= $page + 1 ?><?= $queryParams ?>" class="pagination__link <?= $page >= $totalPages ? 'pagination__link--disabled' : '' ?>">
|
||||
<i class="fas fa-angle-right"></i>
|
||||
</a>
|
||||
<a href="?page=<?= $totalPages ?><?= $queryParams ?>" class="pagination__link <?= $page >= $totalPages ? 'pagination__link--disabled' : '' ?>">
|
||||
<i class="fas fa-angle-double-right"></i>
|
||||
</a>
|
||||
|
||||
<span class="pagination__info">
|
||||
Página <?= $page ?> de <?= $totalPages ?> (<?= $totalClientes ?> clientes)
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php require_once __DIR__ . '/includes/admin-footer.php'; ?>
|
||||
Reference in New Issue
Block a user