fix(admin): bug del activo + simplificar a Nombre Completo + gear en landing

BUG FIX
* admin.html: el filtro <select id="f-activo"> y el modal <input id="f-activo">
  tenían el MISMO id. document.getElementById devolvía el select (primer en
  DOM order) y la lectura .checked siempre era undefined → JSON enviaba el
  valor stale del select. Renombré el filtro a `f-activo-filter`.

REFACTOR: drop apellido, usar Nombre Completo
* Migración 007: copia apellido→name para placeholders, migra
  escrituras_tramites.abogado y tramites_legales.abogado a usar nombre
  completo, DROP COLUMN apellido + índice.
* Lookups: abogadoApellidos() → abogadoNames() filtra socios+abogados
  activos con name no vacío.
* Auth.php: drop método apellido(), agregado userName().
* tramites/api.php: visibilidad usa users.name = t.abogado.
* admin/api.php: drop apellido en create/update payloads.
* admin.html: drop columna y campo Apellido del table y form.
* Bootstrap envía window.DONNA.abogados con nombres completos.

LANDING (index.php)
* Gear icon en dash-header visible solo si Auth::isSocio() (chequeo
  server-side, sin flash de JS).

CLEANUP
* Eliminado logging de debug en admin/api.php que se agregó para
  diagnosticar el bug del activo.

PERMISOS (sin cambios — confirmación)
* Trámites Legales: solo socio/abogado pueden crear (canCreate() ya lo
  enforza desde 2db8f23).
* Escrituras: cualquier rol autenticado puede crear (escrituras/api.php
  nunca tuvo restricción).
This commit is contained in:
Soporte ZH Consultores
2026-06-04 23:42:06 +00:00
parent 2db8f23ba5
commit 072cc0b6e3
8 changed files with 83 additions and 58 deletions
+13 -15
View File
@@ -41,27 +41,26 @@ try {
if ($email === '') err('email requerido');
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) err('email inválido');
$name = trim((string)($b['name'] ?? ''));
$role = in_array(($b['role'] ?? ''), ROLES, true) ? $b['role'] : 'usuario';
$apellido = trim((string)($b['apellido'] ?? ''));
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
$orden = (int)($b['orden'] ?? 0);
$name = trim((string)($b['name'] ?? ''));
$role = in_array(($b['role'] ?? ''), ROLES, true) ? $b['role'] : 'usuario';
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
$orden = (int)($b['orden'] ?? 0);
$exists = $pdo->prepare('SELECT id FROM users WHERE email = :e');
$exists->execute([':e' => $email]);
if ($exists->fetch()) err('Ya existe un usuario con ese email', 409);
$ins = $pdo->prepare(
'INSERT INTO users (email, name, role, apellido, activo, orden, first_seen_at, last_login_at)
VALUES (:email, :name, :role, :apellido, :activo, :orden, NULL, NULL)'
'INSERT INTO users (email, name, role, activo, orden, first_seen_at, last_login_at)
VALUES (:email, :name, :role, :activo, :orden, NULL, NULL)'
);
$ins->execute([
':email' => $email, ':name' => $name, ':role' => $role,
':apellido' => $apellido, ':activo' => $activo, ':orden' => $orden,
':activo' => $activo, ':orden' => $orden,
]);
$id = (int)$pdo->lastInsertId();
$sel = $pdo->prepare('SELECT id, email, name, role, apellido, activo, orden, first_seen_at, last_login_at FROM users WHERE id = :id');
$sel = $pdo->prepare('SELECT id, email, name, role, activo, orden, first_seen_at, last_login_at FROM users WHERE id = :id');
$sel->execute([':id' => $id]);
$row = $sel->fetch();
$row['id'] = (int)$row['id'];
@@ -97,22 +96,21 @@ try {
if ($chk->fetch()) err('Otro usuario ya tiene ese email', 409);
}
$name = trim((string)($b['name'] ?? ''));
$apellido = trim((string)($b['apellido'] ?? ''));
$orden = (int)($b['orden'] ?? 0);
$name = trim((string)($b['name'] ?? ''));
$orden = (int)($b['orden'] ?? 0);
$upd = $pdo->prepare(
'UPDATE users SET email = :email, name = :name, role = :role,
apellido = :apellido, activo = :activo, orden = :orden
activo = :activo, orden = :orden
WHERE id = :id'
);
$upd->execute([
':email' => $newEmail, ':name' => $name, ':role' => $newRole,
':apellido' => $apellido, ':activo' => $newActivo, ':orden' => $orden,
':activo' => $newActivo, ':orden' => $orden,
':id' => $id,
]);
$sel = $pdo->prepare('SELECT id, email, name, role, apellido, activo, orden, first_seen_at, last_login_at FROM users WHERE id = :id');
$sel = $pdo->prepare('SELECT id, email, name, role, activo, orden, first_seen_at, last_login_at FROM users WHERE id = :id');
$sel->execute([':id' => $id]);
$row = $sel->fetch();
$row['id'] = (int)$row['id'];
+16 -6
View File
@@ -106,6 +106,9 @@ a{color:inherit;text-decoration:none;}
.user-email{font-size:10.5px;color:rgba(255,255,255,0.55);max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
.btn-logout{font-size:11px;padding:6px 12px;border:1px solid rgba(255,255,255,0.18);border-radius:18px;background:transparent;color:rgba(255,255,255,0.7);cursor:pointer;font-family:'DM Sans',sans-serif;transition:all .15s;}
.btn-logout:hover{background:rgba(255,255,255,0.12);color:#fff;border-color:rgba(255,255,255,0.3);}
.btn-gear{display:inline-flex;align-items:center;justify-content:center;width:36px;height:36px;border:1px solid rgba(255,255,255,0.18);border-radius:8px;color:rgba(255,255,255,0.85);transition:all .15s;text-decoration:none;font-family:'DM Sans',sans-serif;margin-right:8px;}
.btn-gear:hover{background:var(--gold);border-color:var(--gold);color:var(--navy);}
.btn-gear svg{width:16px;height:16px;}
.dash-main{max-width:1180px;margin:0 auto;padding:48px 32px 80px;}
.dash-hero{margin-bottom:40px;}
@@ -199,13 +202,20 @@ a{color:inherit;text-decoration:none;}
<span class="brand-name" style="font-size:14px;color:rgba(255,255,255,0.7);">Portal interno</span>
</div>
</div>
<div class="user-chip">
<div class="user-avatar"><?= htmlspecialchars(initials($user['name'] ?: $user['email'])) ?></div>
<div class="user-info">
<span class="user-name"><?= htmlspecialchars($user['name'] ?: $user['email']) ?></span>
<?php if ($user['name']): ?><span class="user-email"><?= htmlspecialchars($user['email']) ?></span><?php endif; ?>
<div style="display:flex;align-items:center;">
<?php if (Auth::isSocio()): ?>
<a class="btn-gear" href="/admin/" title="Panel de Control">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
</a>
<?php endif; ?>
<div class="user-chip">
<div class="user-avatar"><?= htmlspecialchars(initials($user['name'] ?: $user['email'])) ?></div>
<div class="user-info">
<span class="user-name"><?= htmlspecialchars($user['name'] ?: $user['email']) ?></span>
<?php if ($user['name']): ?><span class="user-email"><?= htmlspecialchars($user['email']) ?></span><?php endif; ?>
</div>
<a href="/auth/logout.php" class="btn-logout">Cerrar sesión</a>
</div>
<a href="/auth/logout.php" class="btn-logout">Cerrar sesión</a>
</div>
</header>
+4 -4
View File
@@ -91,7 +91,7 @@ function hydrate(PDO $pdo, array $row): array {
}, $hrs->fetchAll());
$inv = $pdo->prepare(
'SELECT u.id, u.email, u.name, u.apellido
'SELECT u.id, u.email, u.name
FROM tramites_involucrados ti
JOIN users u ON u.id = ti.user_id
WHERE ti.tramite_id = :t
@@ -109,7 +109,7 @@ function hydrate(PDO $pdo, array $row): array {
/**
* ¿El usuario actual puede ver/editar este trámite?
* Socio → siempre
* Resto → si es creador, o abogado solicitante (apellido), o involucrado
* Resto → si es creador, o abogado solicitante (name), o involucrado
*/
function canView(PDO $pdo, int $tid): bool {
if (Auth::isSocio()) return true;
@@ -117,7 +117,7 @@ function canView(PDO $pdo, int $tid): bool {
$uid = Auth::userId();
$stmt = $pdo->prepare(
"SELECT 1 FROM tramites_legales t
LEFT JOIN users ua ON ua.apellido = t.abogado AND ua.activo = 1
LEFT JOIN users ua ON ua.name = t.abogado AND ua.activo = 1
LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid
WHERE t.id = :tid
AND (t.creado_por = :email OR ua.id = :uid2 OR ti.user_id IS NOT NULL)
@@ -153,7 +153,7 @@ try {
} else {
$stmt = $pdo->prepare(
"SELECT DISTINCT t.* FROM tramites_legales t
LEFT JOIN users ua ON ua.apellido = t.abogado AND ua.activo = 1
LEFT JOIN users ua ON ua.name = t.abogado AND ua.activo = 1
LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid
WHERE t.creado_por = :email
OR ua.id = :uid2