- admin/Layout.php: nueva clase compartida con topbar, nav agrupado y hamburger móvil - assets/app.css: CSS centralizado (~130 líneas), elimina ~2000 líneas duplicadas - DashboardController: 11 vistas refactorizadas con Layout; tarjetas de stats clicables; drawer de aprobación rápida desde el dashboard; Live Feed reemplaza polling 3s por SSE; bot-config con preview WhatsApp en tiempo real; chat con back-button móvil y textarea auto-resize - public/index.php: rutas SSE (/admin/webhook/stream/sse) y pending-list (/admin/pending-list) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
82 lines
3.0 KiB
PHP
82 lines
3.0 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
class Layout
|
|
{
|
|
private static function h(string $v): string
|
|
{
|
|
return htmlspecialchars($v, ENT_QUOTES, 'UTF-8');
|
|
}
|
|
|
|
public static function open(
|
|
string $title,
|
|
string $active,
|
|
string $userName,
|
|
int $pending = 0
|
|
): string {
|
|
$t = self::h($title);
|
|
$u = self::h($userName);
|
|
|
|
$groups = [
|
|
[
|
|
['dashboard', '/admin/dashboard', '📊', 'Dashboard'],
|
|
['live', '/admin/live', '🔴', 'Live'],
|
|
['chat', '/admin/chat', '💬', 'Chat'],
|
|
],
|
|
[
|
|
['pending', '/admin/pending', '⏳', 'Pendientes', $pending],
|
|
['companies', '/admin/companies', '🏢', 'Empresas'],
|
|
],
|
|
[
|
|
['bot-config', '/admin/bot-config', '🤖', 'Bot'],
|
|
['conv-flow', '/admin/conversation-flow', '🔗', 'Flujos'],
|
|
['settings', '/admin/settings', '⚙️', 'Ajustes'],
|
|
],
|
|
];
|
|
|
|
$navHtml = '';
|
|
foreach ($groups as $gi => $group) {
|
|
if ($gi > 0) {
|
|
$navHtml .= '<span class="nav-sep"></span>';
|
|
}
|
|
foreach ($group as $item) {
|
|
[$key, $href, $icon, $label] = $item;
|
|
$badge = isset($item[4]) && $item[4] > 0
|
|
? '<span class="nav-badge">' . (int)$item[4] . '</span>'
|
|
: '';
|
|
$cls = $active === $key ? ' active' : '';
|
|
$navHtml .= "<a href=\"{$href}\" class=\"nav-link{$cls}\">{$icon} {$label}{$badge}</a>";
|
|
}
|
|
}
|
|
|
|
$navHtml .= '<span class="nav-sep"></span>';
|
|
$navHtml .= '<a href="/admin/sync-companies" class="nav-link nav-action" title="Sincronizar desde ERP" onclick="return confirm(\'¿Sincronizar empresas desde el ERP?\')">🔄</a>';
|
|
$navHtml .= '<a href="/admin/process-queue" class="nav-link nav-action" title="Procesar cola de mensajes" onclick="return confirm(\'¿Procesar cola de mensajes?\')">📨</a>';
|
|
|
|
return <<<HTML
|
|
<!DOCTYPE html>
|
|
<html lang="es">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{$t} — Palmas360</title>
|
|
<link rel="stylesheet" href="/assets/app.css">
|
|
</head>
|
|
<body>
|
|
<div class="topbar">
|
|
<div style="display:flex;align-items:center;gap:10px">
|
|
<button class="nav-hamburger" id="navToggle" onclick="document.getElementById('navBar').classList.toggle('open')" aria-label="Menu">☰</button>
|
|
<h1><img src="https://app.palmas360.com/Test/imgLogin/logo.png" alt="Palmas360" style="height:32px;vertical-align:middle;margin-right:8px;filter:brightness(0) invert(1)"> {$t}</h1>
|
|
</div>
|
|
<div class="topbar-r">
|
|
<span class="ubadge">👤 {$u}</span>
|
|
<a href="/logout" class="btn-out">Salir</a>
|
|
</div>
|
|
</div>
|
|
<nav class="nav-bar" id="navBar">
|
|
{$navHtml}
|
|
</nav>
|
|
HTML;
|
|
}
|
|
}
|