Actualizar panel.html
This commit is contained in:
191
panel.html
191
panel.html
@@ -3,169 +3,53 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Panel de Control - IntegraRepara</title>
|
||||
<title>Panel - IntegraRepara</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://unpkg.com/lucide@latest"></script>
|
||||
<style>
|
||||
.fade-in { animation: fadeIn 0.5s ease-in-out; }
|
||||
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
|
||||
</style>
|
||||
<style>.fade-in { animation: fadeIn 0.5s ease-in-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }</style>
|
||||
</head>
|
||||
<body class="bg-gray-50 text-gray-800 font-sans antialiased">
|
||||
|
||||
<div class="flex h-screen overflow-hidden">
|
||||
|
||||
<aside class="w-64 bg-slate-900 text-white flex flex-col hidden md:flex shadow-xl z-20">
|
||||
<div class="h-16 flex items-center justify-center border-b border-slate-800">
|
||||
<h1 class="text-xl font-bold tracking-wider text-blue-400">INTEGRA<span class="text-white">REPARA</span></h1>
|
||||
</div>
|
||||
|
||||
<nav class="flex-1 px-4 py-6 space-y-2">
|
||||
<a href="#" class="flex items-center gap-3 px-4 py-3 bg-blue-600 rounded-lg text-white transition-all shadow-lg shadow-blue-500/30">
|
||||
<i data-lucide="layout-dashboard" class="w-5 h-5"></i>
|
||||
<span>Dashboard</span>
|
||||
</a>
|
||||
<a href="#" class="flex items-center gap-3 px-4 py-3 text-slate-400 hover:text-white hover:bg-slate-800 rounded-lg transition-all">
|
||||
<i data-lucide="calendar" class="w-5 h-5"></i>
|
||||
<span>Calendario</span>
|
||||
</a>
|
||||
<a href="#" class="flex items-center gap-3 px-4 py-3 text-slate-400 hover:text-white hover:bg-slate-800 rounded-lg transition-all">
|
||||
<i data-lucide="users" class="w-5 h-5"></i>
|
||||
<span>Clientes</span>
|
||||
</a>
|
||||
<a href="#" class="flex items-center gap-3 px-4 py-3 text-slate-400 hover:text-white hover:bg-slate-800 rounded-lg transition-all">
|
||||
<i data-lucide="settings" class="w-5 h-5"></i>
|
||||
<span>Configuración</span>
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<div class="p-4 border-t border-slate-800">
|
||||
<button id="btnLogout" class="flex items-center gap-2 text-slate-400 hover:text-red-400 transition-colors w-full p-2 rounded hover:bg-slate-800">
|
||||
<i data-lucide="log-out" class="w-5 h-5"></i>
|
||||
<span>Cerrar Sesión</span>
|
||||
</button>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div id="sidebar-container" class="h-full"></div>
|
||||
|
||||
<div class="flex-1 flex flex-col overflow-hidden relative">
|
||||
|
||||
<header class="h-16 bg-white border-b border-gray-200 flex items-center justify-between px-8 shadow-sm">
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="relative hidden lg:block">
|
||||
<i data-lucide="search" class="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400"></i>
|
||||
<input type="text" placeholder="Buscar..." class="pl-10 pr-4 py-2 bg-gray-100 border-none rounded-full focus:ring-2 focus:ring-blue-500 focus:bg-white text-sm w-64 transition-all">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="text-right hidden sm:block">
|
||||
<p class="text-sm font-semibold text-gray-700" id="userName">Cargando...</p>
|
||||
<p class="text-xs text-gray-500" id="userEmail">...</p>
|
||||
</div>
|
||||
<div class="w-10 h-10 bg-gradient-to-br from-blue-500 to-indigo-600 rounded-full flex items-center justify-center text-white font-bold shadow-lg" id="userAvatar">U</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div id="header-container"></div>
|
||||
|
||||
<main class="flex-1 overflow-x-hidden overflow-y-auto bg-gray-50 p-8 fade-in">
|
||||
|
||||
<div class="flex justify-between items-center mb-8">
|
||||
<h2 class="text-2xl font-bold text-gray-800">Panel de Control</h2>
|
||||
<button onclick="openNewServiceModal()" class="bg-blue-600 hover:bg-blue-700 text-white px-5 py-2 rounded-lg shadow-lg shadow-blue-500/30 flex items-center gap-2 transition-all">
|
||||
<i data-lucide="plus-circle" class="w-5 h-5"></i>
|
||||
Nuevo Servicio
|
||||
<h2 class="text-2xl font-bold text-gray-800">Dashboard</h2>
|
||||
<button onclick="alert('Próximamente')" class="bg-blue-600 hover:bg-blue-700 text-white px-5 py-2 rounded-lg shadow-lg flex items-center gap-2">
|
||||
<i data-lucide="plus-circle" class="w-5 h-5"></i> Nuevo
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||||
<div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase">Servicios Activos</p>
|
||||
<h3 class="text-2xl font-bold text-gray-800 mt-1" id="countServices">0</h3>
|
||||
</div>
|
||||
<div class="p-2 bg-blue-50 text-blue-600 rounded-lg"><i data-lucide="briefcase" class="w-6 h-6"></i></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white p-6 rounded-xl shadow-sm border border-gray-100">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase">Clientes</p>
|
||||
<h3 class="text-2xl font-bold text-gray-800 mt-1">+12</h3>
|
||||
</div>
|
||||
<div class="p-2 bg-green-50 text-green-600 rounded-lg"><i data-lucide="users" class="w-6 h-6"></i></div>
|
||||
</div>
|
||||
<p class="text-xs font-semibold text-gray-500 uppercase">Servicios Activos</p>
|
||||
<h3 class="text-2xl font-bold text-gray-800 mt-1" id="countServices">...</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 overflow-hidden">
|
||||
<div class="p-6 border-b border-gray-100 flex justify-between items-center">
|
||||
<h3 class="font-bold text-gray-800">Servicios Recientes</h3>
|
||||
</div>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-left border-collapse">
|
||||
<thead>
|
||||
<tr class="bg-gray-50 text-gray-600 text-sm uppercase tracking-wider">
|
||||
<th class="p-4 font-semibold">Cliente</th>
|
||||
<th class="p-4 font-semibold">Servicio</th>
|
||||
<th class="p-4 font-semibold">Fecha</th>
|
||||
<th class="p-4 font-semibold">Estado</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="servicesTableBody" class="text-sm divide-y divide-gray-100">
|
||||
<tr><td class="p-4 text-center text-gray-500" colspan="4">Cargando datos...</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow-sm border border-gray-100 p-6">
|
||||
<h3 class="font-bold text-gray-800 mb-4">Servicios Recientes</h3>
|
||||
<div id="servicesTableBody">Cargando...</div>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="layout.js"></script>
|
||||
|
||||
<script>
|
||||
const API_URL = "https://integrarepara-api.integrarepara.es";
|
||||
|
||||
// ==========================================
|
||||
// 1. FUNCIÓN LOGOUT (GLOBAL Y SEGURA)
|
||||
// ==========================================
|
||||
// La definimos fuera de todo para que esté disponible siempre
|
||||
function logout() {
|
||||
console.log("Cerrando sesión...");
|
||||
localStorage.removeItem("token");
|
||||
window.location.href = "index.html";
|
||||
}
|
||||
|
||||
// Asignar evento al botón directamente por ID (Más robusto)
|
||||
document.getElementById('btnLogout').addEventListener('click', logout);
|
||||
|
||||
// ==========================================
|
||||
// 2. LÓGICA DE CARGA
|
||||
// ==========================================
|
||||
// Esperamos a que cargue el layout y luego cargamos los datos
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
lucide.createIcons();
|
||||
|
||||
const token = localStorage.getItem("token");
|
||||
if (!token) {
|
||||
window.location.href = "index.html";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// Decodificar token visualmente
|
||||
const payload = JSON.parse(atob(token.split('.')[1]));
|
||||
document.getElementById("userEmail").innerText = payload.email || "Usuario";
|
||||
document.getElementById("userName").innerText = payload.fullName || "Bienvenido";
|
||||
document.getElementById("userAvatar").innerText = (payload.email[0] || "U").toUpperCase();
|
||||
|
||||
// Cargar datos
|
||||
loadServices(token);
|
||||
} catch (e) {
|
||||
console.error("Error leyendo token", e);
|
||||
// Si el token está corrupto, cerramos sesión
|
||||
logout();
|
||||
}
|
||||
const token = localStorage.getItem("token");
|
||||
if(token) loadServices(token);
|
||||
});
|
||||
|
||||
async function loadServices(token) {
|
||||
@@ -174,40 +58,23 @@
|
||||
headers: { "Authorization": `Bearer ${token}` }
|
||||
});
|
||||
const data = await res.json();
|
||||
|
||||
if (data.ok) {
|
||||
renderTable(data.services);
|
||||
document.getElementById("countServices").innerText = data.services.length;
|
||||
renderTable(data.services);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error cargando servicios:", error);
|
||||
}
|
||||
} catch (e) { console.error(e); }
|
||||
}
|
||||
|
||||
function renderTable(services) {
|
||||
const tbody = document.getElementById("servicesTableBody");
|
||||
tbody.innerHTML = "";
|
||||
|
||||
if (services.length === 0) {
|
||||
tbody.innerHTML = `<tr><td colspan="4" class="p-4 text-center text-gray-400">No hay servicios registrados.</td></tr>`;
|
||||
return;
|
||||
}
|
||||
|
||||
services.forEach(service => {
|
||||
const date = new Date(service.created_at).toLocaleDateString("es-ES");
|
||||
tbody.innerHTML += `
|
||||
<tr class="hover:bg-gray-50 transition-colors">
|
||||
<td class="p-4 font-medium text-gray-800">${service.client_name || "Sin nombre"}</td>
|
||||
<td class="p-4 text-gray-600">${service.title}</td>
|
||||
<td class="p-4 text-gray-500">${date}</td>
|
||||
<td class="p-4"><span class="bg-yellow-100 text-yellow-700 px-2 py-1 rounded-full text-xs font-semibold">En Proceso</span></td>
|
||||
</tr>
|
||||
`;
|
||||
const container = document.getElementById("servicesTableBody");
|
||||
if(services.length === 0) { container.innerHTML = "No hay servicios."; return; }
|
||||
|
||||
let html = '<table class="w-full text-left"><thead><tr class="text-gray-500 text-sm"><th>Cliente</th><th>Servicio</th><th>Estado</th></tr></thead><tbody>';
|
||||
services.forEach(s => {
|
||||
html += `<tr class="border-t"><td class="p-3">${s.client_name}</td><td>${s.title}</td><td><span class="bg-yellow-100 px-2 rounded text-xs">En Proceso</span></td></tr>`;
|
||||
});
|
||||
}
|
||||
|
||||
function openNewServiceModal() {
|
||||
alert("Próximamente: Crear nuevo servicio");
|
||||
html += '</tbody></table>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user