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:
+13
-15
@@ -41,27 +41,26 @@ try {
|
|||||||
if ($email === '') err('email requerido');
|
if ($email === '') err('email requerido');
|
||||||
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) err('email inválido');
|
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) err('email inválido');
|
||||||
|
|
||||||
$name = trim((string)($b['name'] ?? ''));
|
$name = trim((string)($b['name'] ?? ''));
|
||||||
$role = in_array(($b['role'] ?? ''), ROLES, true) ? $b['role'] : 'usuario';
|
$role = in_array(($b['role'] ?? ''), ROLES, true) ? $b['role'] : 'usuario';
|
||||||
$apellido = trim((string)($b['apellido'] ?? ''));
|
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
|
||||||
$activo = (int)($b['activo'] ?? 1) === 1 ? 1 : 0;
|
$orden = (int)($b['orden'] ?? 0);
|
||||||
$orden = (int)($b['orden'] ?? 0);
|
|
||||||
|
|
||||||
$exists = $pdo->prepare('SELECT id FROM users WHERE email = :e');
|
$exists = $pdo->prepare('SELECT id FROM users WHERE email = :e');
|
||||||
$exists->execute([':e' => $email]);
|
$exists->execute([':e' => $email]);
|
||||||
if ($exists->fetch()) err('Ya existe un usuario con ese email', 409);
|
if ($exists->fetch()) err('Ya existe un usuario con ese email', 409);
|
||||||
|
|
||||||
$ins = $pdo->prepare(
|
$ins = $pdo->prepare(
|
||||||
'INSERT INTO users (email, name, role, apellido, activo, orden, first_seen_at, last_login_at)
|
'INSERT INTO users (email, name, role, activo, orden, first_seen_at, last_login_at)
|
||||||
VALUES (:email, :name, :role, :apellido, :activo, :orden, NULL, NULL)'
|
VALUES (:email, :name, :role, :activo, :orden, NULL, NULL)'
|
||||||
);
|
);
|
||||||
$ins->execute([
|
$ins->execute([
|
||||||
':email' => $email, ':name' => $name, ':role' => $role,
|
':email' => $email, ':name' => $name, ':role' => $role,
|
||||||
':apellido' => $apellido, ':activo' => $activo, ':orden' => $orden,
|
':activo' => $activo, ':orden' => $orden,
|
||||||
]);
|
]);
|
||||||
$id = (int)$pdo->lastInsertId();
|
$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]);
|
$sel->execute([':id' => $id]);
|
||||||
$row = $sel->fetch();
|
$row = $sel->fetch();
|
||||||
$row['id'] = (int)$row['id'];
|
$row['id'] = (int)$row['id'];
|
||||||
@@ -97,22 +96,21 @@ try {
|
|||||||
if ($chk->fetch()) err('Otro usuario ya tiene ese email', 409);
|
if ($chk->fetch()) err('Otro usuario ya tiene ese email', 409);
|
||||||
}
|
}
|
||||||
|
|
||||||
$name = trim((string)($b['name'] ?? ''));
|
$name = trim((string)($b['name'] ?? ''));
|
||||||
$apellido = trim((string)($b['apellido'] ?? ''));
|
$orden = (int)($b['orden'] ?? 0);
|
||||||
$orden = (int)($b['orden'] ?? 0);
|
|
||||||
|
|
||||||
$upd = $pdo->prepare(
|
$upd = $pdo->prepare(
|
||||||
'UPDATE users SET email = :email, name = :name, role = :role,
|
'UPDATE users SET email = :email, name = :name, role = :role,
|
||||||
apellido = :apellido, activo = :activo, orden = :orden
|
activo = :activo, orden = :orden
|
||||||
WHERE id = :id'
|
WHERE id = :id'
|
||||||
);
|
);
|
||||||
$upd->execute([
|
$upd->execute([
|
||||||
':email' => $newEmail, ':name' => $name, ':role' => $newRole,
|
':email' => $newEmail, ':name' => $name, ':role' => $newRole,
|
||||||
':apellido' => $apellido, ':activo' => $newActivo, ':orden' => $orden,
|
':activo' => $newActivo, ':orden' => $orden,
|
||||||
':id' => $id,
|
':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]);
|
$sel->execute([':id' => $id]);
|
||||||
$row = $sel->fetch();
|
$row = $sel->fetch();
|
||||||
$row['id'] = (int)$row['id'];
|
$row['id'] = (int)$row['id'];
|
||||||
|
|||||||
+16
-6
@@ -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;}
|
.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{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-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-main{max-width:1180px;margin:0 auto;padding:48px 32px 80px;}
|
||||||
.dash-hero{margin-bottom:40px;}
|
.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>
|
<span class="brand-name" style="font-size:14px;color:rgba(255,255,255,0.7);">Portal interno</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="user-chip">
|
<div style="display:flex;align-items:center;">
|
||||||
<div class="user-avatar"><?= htmlspecialchars(initials($user['name'] ?: $user['email'])) ?></div>
|
<?php if (Auth::isSocio()): ?>
|
||||||
<div class="user-info">
|
<a class="btn-gear" href="/admin/" title="Panel de Control">
|
||||||
<span class="user-name"><?= htmlspecialchars($user['name'] ?: $user['email']) ?></span>
|
<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>
|
||||||
<?php if ($user['name']): ?><span class="user-email"><?= htmlspecialchars($user['email']) ?></span><?php endif; ?>
|
</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>
|
</div>
|
||||||
<a href="/auth/logout.php" class="btn-logout">Cerrar sesión</a>
|
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ function hydrate(PDO $pdo, array $row): array {
|
|||||||
}, $hrs->fetchAll());
|
}, $hrs->fetchAll());
|
||||||
|
|
||||||
$inv = $pdo->prepare(
|
$inv = $pdo->prepare(
|
||||||
'SELECT u.id, u.email, u.name, u.apellido
|
'SELECT u.id, u.email, u.name
|
||||||
FROM tramites_involucrados ti
|
FROM tramites_involucrados ti
|
||||||
JOIN users u ON u.id = ti.user_id
|
JOIN users u ON u.id = ti.user_id
|
||||||
WHERE ti.tramite_id = :t
|
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?
|
* ¿El usuario actual puede ver/editar este trámite?
|
||||||
* Socio → siempre
|
* 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 {
|
function canView(PDO $pdo, int $tid): bool {
|
||||||
if (Auth::isSocio()) return true;
|
if (Auth::isSocio()) return true;
|
||||||
@@ -117,7 +117,7 @@ function canView(PDO $pdo, int $tid): bool {
|
|||||||
$uid = Auth::userId();
|
$uid = Auth::userId();
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT 1 FROM tramites_legales t
|
"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
|
LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid
|
||||||
WHERE t.id = :tid
|
WHERE t.id = :tid
|
||||||
AND (t.creado_por = :email OR ua.id = :uid2 OR ti.user_id IS NOT NULL)
|
AND (t.creado_por = :email OR ua.id = :uid2 OR ti.user_id IS NOT NULL)
|
||||||
@@ -153,7 +153,7 @@ try {
|
|||||||
} else {
|
} else {
|
||||||
$stmt = $pdo->prepare(
|
$stmt = $pdo->prepare(
|
||||||
"SELECT DISTINCT t.* FROM tramites_legales t
|
"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
|
LEFT JOIN tramites_involucrados ti ON ti.tramite_id = t.id AND ti.user_id = :uid
|
||||||
WHERE t.creado_por = :email
|
WHERE t.creado_por = :email
|
||||||
OR ua.id = :uid2
|
OR ua.id = :uid2
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
-- ============================================================
|
||||||
|
-- Donna — Schema 007: Eliminar apellido, usar Nombre Completo
|
||||||
|
-- ============================================================
|
||||||
|
-- Decisión: simplificar el modelo trabajando solo con `name` en lugar de
|
||||||
|
-- mantener apellido + name. El dropdown "Abogado Solicitante" muestra el
|
||||||
|
-- nombre completo en lugar del apellido suelto.
|
||||||
|
|
||||||
|
-- 1) Migrar nombres de placeholders desde apellido
|
||||||
|
UPDATE users
|
||||||
|
SET name = apellido
|
||||||
|
WHERE (name = '' OR name = '(Asignar email real)')
|
||||||
|
AND apellido != '';
|
||||||
|
|
||||||
|
-- 2) Migrar tramites a usar el name en lugar del apellido
|
||||||
|
UPDATE escrituras_tramites t
|
||||||
|
JOIN users u ON u.apellido = t.abogado AND u.apellido != '' AND u.name != ''
|
||||||
|
SET t.abogado = u.name;
|
||||||
|
|
||||||
|
UPDATE tramites_legales t
|
||||||
|
JOIN users u ON u.apellido = t.abogado AND u.apellido != '' AND u.name != ''
|
||||||
|
SET t.abogado = u.name;
|
||||||
|
|
||||||
|
-- 3) Drop columna apellido + su índice
|
||||||
|
ALTER TABLE users
|
||||||
|
DROP INDEX idx_apellido,
|
||||||
|
DROP COLUMN apellido;
|
||||||
+3
-3
@@ -47,7 +47,7 @@ final class Auth {
|
|||||||
if (!$email) return self::$userRowCache = self::defaultRow();
|
if (!$email) return self::$userRowCache = self::defaultRow();
|
||||||
try {
|
try {
|
||||||
$stmt = Db::pdo()->prepare(
|
$stmt = Db::pdo()->prepare(
|
||||||
'SELECT id, email, name, role, apellido, activo
|
'SELECT id, email, name, role, activo
|
||||||
FROM users WHERE email = :e LIMIT 1'
|
FROM users WHERE email = :e LIMIT 1'
|
||||||
);
|
);
|
||||||
$stmt->execute([':e' => $email]);
|
$stmt->execute([':e' => $email]);
|
||||||
@@ -61,12 +61,12 @@ final class Auth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static function defaultRow(): array {
|
private static function defaultRow(): array {
|
||||||
return ['id' => 0, 'email' => '', 'name' => '', 'role' => 'usuario', 'apellido' => '', 'activo' => 1];
|
return ['id' => 0, 'email' => '', 'name' => '', 'role' => 'usuario', 'activo' => 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function userId(): int { return (int)(self::userRow()['id'] ?? 0); }
|
public static function userId(): int { return (int)(self::userRow()['id'] ?? 0); }
|
||||||
public static function role(): string { return (string)(self::userRow()['role'] ?? 'usuario'); }
|
public static function role(): string { return (string)(self::userRow()['role'] ?? 'usuario'); }
|
||||||
public static function apellido(): string { return (string)(self::userRow()['apellido'] ?? ''); }
|
public static function userName(): string { return (string)(self::userRow()['name'] ?? ''); }
|
||||||
|
|
||||||
public static function isSocio(): bool { return self::role() === 'socio'; }
|
public static function isSocio(): bool { return self::role() === 'socio'; }
|
||||||
public static function isAbogado(): bool { return in_array(self::role(), ['socio','abogado'], true); }
|
public static function isAbogado(): bool { return in_array(self::role(), ['socio','abogado'], true); }
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ final class Bootstrap {
|
|||||||
'isAbogado' => Auth::isAbogado(),
|
'isAbogado' => Auth::isAbogado(),
|
||||||
'canCreate' => Auth::canCreate(),
|
'canCreate' => Auth::canCreate(),
|
||||||
'canDelete' => Auth::canDelete(),
|
'canDelete' => Auth::canDelete(),
|
||||||
'abogados' => Lookups::abogadoApellidos(),
|
'abogados' => Lookups::abogadoNames(),
|
||||||
'users' => Lookups::involucrablesUsers(),
|
'users' => Lookups::involucrablesUsers(),
|
||||||
];
|
];
|
||||||
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP);
|
$json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP);
|
||||||
|
|||||||
+10
-10
@@ -5,25 +5,25 @@ require_once __DIR__ . '/Db.php';
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookups — vistas de solo lectura sobre la tabla users para poblar
|
* Lookups — vistas de solo lectura sobre la tabla users para poblar
|
||||||
* dropdowns y resolver mapeo email ↔ apellido.
|
* dropdowns y resolver visibilidad.
|
||||||
*/
|
*/
|
||||||
final class Lookups {
|
final class Lookups {
|
||||||
/** Apellidos para el dropdown "Abogado Solicitante" (socios + abogados activos). */
|
/** Nombres completos para el dropdown "Abogado Solicitante" (socios + abogados activos). */
|
||||||
public static function abogadoApellidos(): array {
|
public static function abogadoNames(): array {
|
||||||
$rows = Db::pdo()->query(
|
$rows = Db::pdo()->query(
|
||||||
"SELECT DISTINCT apellido FROM users
|
"SELECT DISTINCT name FROM users
|
||||||
WHERE activo = 1
|
WHERE activo = 1
|
||||||
AND role IN ('socio','abogado')
|
AND role IN ('socio','abogado')
|
||||||
AND apellido != ''
|
AND name != ''
|
||||||
ORDER BY orden ASC, apellido ASC"
|
ORDER BY orden ASC, name ASC"
|
||||||
)->fetchAll();
|
)->fetchAll();
|
||||||
return array_map(fn($r) => $r['apellido'], $rows);
|
return array_map(fn($r) => $r['name'], $rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Todos los usuarios activos para el picker de Involucrados. */
|
/** Todos los usuarios activos para el picker de Involucrados. */
|
||||||
public static function involucrablesUsers(): array {
|
public static function involucrablesUsers(): array {
|
||||||
$rows = Db::pdo()->query(
|
$rows = Db::pdo()->query(
|
||||||
"SELECT id, email, name, role, apellido
|
"SELECT id, email, name, role
|
||||||
FROM users
|
FROM users
|
||||||
WHERE activo = 1
|
WHERE activo = 1
|
||||||
AND email NOT LIKE 'placeholder-%'
|
AND email NOT LIKE 'placeholder-%'
|
||||||
@@ -36,10 +36,10 @@ final class Lookups {
|
|||||||
/** Todos los users (incluye inactivos y placeholders) para el Panel de Control. */
|
/** Todos los users (incluye inactivos y placeholders) para el Panel de Control. */
|
||||||
public static function allUsers(): array {
|
public static function allUsers(): array {
|
||||||
$rows = Db::pdo()->query(
|
$rows = Db::pdo()->query(
|
||||||
"SELECT id, email, name, role, apellido, activo, orden,
|
"SELECT id, email, name, role, activo, orden,
|
||||||
first_seen_at, last_login_at
|
first_seen_at, last_login_at
|
||||||
FROM users
|
FROM users
|
||||||
ORDER BY role DESC, apellido ASC, name ASC, email ASC"
|
ORDER BY role DESC, name ASC, email ASC"
|
||||||
)->fetchAll();
|
)->fetchAll();
|
||||||
foreach ($rows as &$r) {
|
foreach ($rows as &$r) {
|
||||||
$r['id'] = (int)$r['id'];
|
$r['id'] = (int)$r['id'];
|
||||||
|
|||||||
+10
-19
@@ -157,18 +157,18 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
|||||||
|
|
||||||
<div class="intro">
|
<div class="intro">
|
||||||
<h1>Usuarios y permisos</h1>
|
<h1>Usuarios y permisos</h1>
|
||||||
<p>Administra la lista unificada de usuarios del sistema. El campo <b>Apellido</b> es lo que aparece en el dropdown "Abogado Solicitante" (solo si el rol es <b>Socio</b> o <b>Abogado</b>). Los emails que empiezan con <code>placeholder-</code> son los apellidos sembrados al inicio para que los dropdowns no salieran vacíos; reemplázalos con los emails reales conforme los abogados se logueen.</p>
|
<p>Administra la lista unificada de usuarios del sistema. El campo <b>Nombre completo</b> es lo que aparece en el dropdown "Abogado Solicitante" (solo si el rol es <b>Socio</b> o <b>Abogado</b>). Los emails que empiezan con <code>placeholder-</code> son los nombres sembrados al inicio para que los dropdowns no salieran vacíos; reemplázalos con los emails reales conforme los abogados se logueen.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<input type="search" id="search" placeholder="Buscar por email, nombre o apellido…">
|
<input type="search" id="search" placeholder="Buscar por email o nombre…">
|
||||||
<select id="f-role">
|
<select id="f-role">
|
||||||
<option value="">— Todos los roles —</option>
|
<option value="">— Todos los roles —</option>
|
||||||
<option value="socio">Socio</option>
|
<option value="socio">Socio</option>
|
||||||
<option value="abogado">Abogado</option>
|
<option value="abogado">Abogado</option>
|
||||||
<option value="usuario">Usuario</option>
|
<option value="usuario">Usuario</option>
|
||||||
</select>
|
</select>
|
||||||
<select id="f-activo">
|
<select id="f-activo-filter">
|
||||||
<option value="">— Activos e inactivos —</option>
|
<option value="">— Activos e inactivos —</option>
|
||||||
<option value="1">Solo activos</option>
|
<option value="1">Solo activos</option>
|
||||||
<option value="0">Solo inactivos</option>
|
<option value="0">Solo inactivos</option>
|
||||||
@@ -182,8 +182,7 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Email</th>
|
<th>Email</th>
|
||||||
<th>Nombre</th>
|
<th>Nombre completo</th>
|
||||||
<th>Apellido</th>
|
|
||||||
<th>Rol</th>
|
<th>Rol</th>
|
||||||
<th>Activo</th>
|
<th>Activo</th>
|
||||||
<th>Orden</th>
|
<th>Orden</th>
|
||||||
@@ -209,15 +208,11 @@ tr.is-me td { background:#FFFBEB; font-weight:500; }
|
|||||||
<input type="email" id="f-email" placeholder="usuario@aal-law.com">
|
<input type="email" id="f-email" placeholder="usuario@aal-law.com">
|
||||||
<div class="fg-hint" id="hint-email">El email debe coincidir exactamente con la cuenta de Mailcow que el usuario usa para entrar.</div>
|
<div class="fg-hint" id="hint-email">El email debe coincidir exactamente con la cuenta de Mailcow que el usuario usa para entrar.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg">
|
|
||||||
<label>Nombre completo</label>
|
|
||||||
<input type="text" id="f-name" placeholder="Ej: Carlos Abrego">
|
|
||||||
</div>
|
|
||||||
<div class="fg-row">
|
<div class="fg-row">
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label>Apellido (dropdown)</label>
|
<label>Nombre completo</label>
|
||||||
<input type="text" id="f-apellido" placeholder="Ej: Abrego">
|
<input type="text" id="f-name" placeholder="Ej: Carlos Abrego">
|
||||||
<div class="fg-hint">Solo aparece en dropdowns si el rol es Socio o Abogado.</div>
|
<div class="fg-hint">Aparece en el dropdown "Abogado Solicitante" si el rol es Socio o Abogado.</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="fg">
|
<div class="fg">
|
||||||
<label>Rol</label>
|
<label>Rol</label>
|
||||||
@@ -310,12 +305,12 @@ async function loadUsers(){
|
|||||||
function visibleUsers(){
|
function visibleUsers(){
|
||||||
const q = $('search').value.toLowerCase().trim();
|
const q = $('search').value.toLowerCase().trim();
|
||||||
const fR = $('f-role').value;
|
const fR = $('f-role').value;
|
||||||
const fA = $('f-activo').value;
|
const fA = $('f-activo-filter').value;
|
||||||
return users.filter(u => {
|
return users.filter(u => {
|
||||||
if (fR && u.role !== fR) return false;
|
if (fR && u.role !== fR) return false;
|
||||||
if (fA !== '' && String(u.activo) !== fA) return false;
|
if (fA !== '' && String(u.activo) !== fA) return false;
|
||||||
if (q) {
|
if (q) {
|
||||||
const blob = ((u.email||'')+' '+(u.name||'')+' '+(u.apellido||'')).toLowerCase();
|
const blob = ((u.email||'')+' '+(u.name||'')).toLowerCase();
|
||||||
if (!blob.includes(q)) return false;
|
if (!blob.includes(q)) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@@ -338,7 +333,6 @@ function render(){
|
|||||||
return `<tr class="${rowCls}">
|
return `<tr class="${rowCls}">
|
||||||
<td><b>${esc(u.email)}</b>${isPlaceholder?' <span class="placeholder">(placeholder)</span>':''}${isMe?' <span style="color:var(--gold-d);font-size:10px;">(tú)</span>':''}</td>
|
<td><b>${esc(u.email)}</b>${isPlaceholder?' <span class="placeholder">(placeholder)</span>':''}${isMe?' <span style="color:var(--gold-d);font-size:10px;">(tú)</span>':''}</td>
|
||||||
<td>${esc(u.name) || '<span class="placeholder">—</span>'}</td>
|
<td>${esc(u.name) || '<span class="placeholder">—</span>'}</td>
|
||||||
<td>${esc(u.apellido) || '<span class="placeholder">—</span>'}</td>
|
|
||||||
<td><span class="role-pill role-${u.role}">${ROLE_LABEL[u.role] || u.role}</span></td>
|
<td><span class="role-pill role-${u.role}">${ROLE_LABEL[u.role] || u.role}</span></td>
|
||||||
<td><span class="activo-pill activo-${u.activo}">${u.activo ? 'Activo' : 'Inactivo'}</span></td>
|
<td><span class="activo-pill activo-${u.activo}">${u.activo ? 'Activo' : 'Inactivo'}</span></td>
|
||||||
<td>${u.orden}</td>
|
<td>${u.orden}</td>
|
||||||
@@ -353,7 +347,6 @@ function openCreate(){
|
|||||||
$('modal-title').textContent = 'Nuevo usuario';
|
$('modal-title').textContent = 'Nuevo usuario';
|
||||||
$('f-email').value = ''; $('f-email').readOnly = false;
|
$('f-email').value = ''; $('f-email').readOnly = false;
|
||||||
$('f-name').value = '';
|
$('f-name').value = '';
|
||||||
$('f-apellido').value = '';
|
|
||||||
$('f-role-edit').value = 'usuario';
|
$('f-role-edit').value = 'usuario';
|
||||||
$('f-orden').value = '0';
|
$('f-orden').value = '0';
|
||||||
$('f-activo').checked = true;
|
$('f-activo').checked = true;
|
||||||
@@ -370,7 +363,6 @@ function openEdit(id){
|
|||||||
$('f-email').value = u.email;
|
$('f-email').value = u.email;
|
||||||
$('f-email').readOnly = false;
|
$('f-email').readOnly = false;
|
||||||
$('f-name').value = u.name || '';
|
$('f-name').value = u.name || '';
|
||||||
$('f-apellido').value = u.apellido || '';
|
|
||||||
$('f-role-edit').value = u.role;
|
$('f-role-edit').value = u.role;
|
||||||
$('f-orden').value = u.orden;
|
$('f-orden').value = u.orden;
|
||||||
$('f-activo').checked = u.activo === 1;
|
$('f-activo').checked = u.activo === 1;
|
||||||
@@ -390,7 +382,6 @@ async function saveUser(){
|
|||||||
const payload = {
|
const payload = {
|
||||||
email: $('f-email').value.trim().toLowerCase(),
|
email: $('f-email').value.trim().toLowerCase(),
|
||||||
name: $('f-name').value.trim(),
|
name: $('f-name').value.trim(),
|
||||||
apellido: $('f-apellido').value.trim(),
|
|
||||||
role: $('f-role-edit').value,
|
role: $('f-role-edit').value,
|
||||||
orden: parseInt($('f-orden').value, 10) || 0,
|
orden: parseInt($('f-orden').value, 10) || 0,
|
||||||
activo: $('f-activo').checked ? 1 : 0,
|
activo: $('f-activo').checked ? 1 : 0,
|
||||||
@@ -423,7 +414,7 @@ async function saveUser(){
|
|||||||
document.addEventListener('keydown', e => {
|
document.addEventListener('keydown', e => {
|
||||||
if (e.key === 'Escape') closeModal();
|
if (e.key === 'Escape') closeModal();
|
||||||
});
|
});
|
||||||
['search','f-role','f-activo'].forEach(id => {
|
['search','f-role','f-activo-filter'].forEach(id => {
|
||||||
$(id).addEventListener('input', render);
|
$(id).addEventListener('input', render);
|
||||||
$(id).addEventListener('change', render);
|
$(id).addEventListener('change', render);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user