diff --git a/menu.html b/menu.html index a818f4e..bfe11dc 100644 --- a/menu.html +++ b/menu.html @@ -83,6 +83,14 @@

Buscar
Servicio

+ +
+
+ +
+

Ranking
y Estadísticas

+
+ @@ -93,6 +101,7 @@ let userZones = []; let userGuilds = []; + let systemStatuses = []; // --- SISTEMA DE TEMA DINÁMICO --- async function applyTheme() { @@ -118,12 +127,11 @@ const token = localStorage.getItem("token"); const role = localStorage.getItem("role"); - if (!token || role !== 'operario') { + if (!token || (role !== 'operario' && role !== 'operario_cerrado')) { window.location.href = "index.html"; return; } - // Aplicamos los colores corporativos de la empresa await applyTheme(); lucide.createIcons(); @@ -133,19 +141,27 @@ const options = { weekday: 'long', day: 'numeric', month: 'long' }; document.getElementById('headerDate').innerText = new Date().toLocaleDateString('es-ES', options); - await fetchUserData(); // Para saber los gremios y zonas del operario + await loadStatuses(); + await fetchUserData(); fetchBadges(); }); - // 1. Obtener zonas y gremios del operario + async function loadStatuses() { + try { + const res = await fetch(`${API_URL}/statuses`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); + const data = await res.json(); + if (data.ok) systemStatuses = data.statuses; + } catch (e) { console.error("Error cargando estados:", e); } + } + async function fetchUserData() { try { const res = await fetch(`${API_URL}/auth/me`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); const data = await res.json(); if (data.ok && data.user) { - // zones suele venir como array de objetos: [{"cps": "11204"}] userZones = Array.isArray(data.user.zones) ? data.user.zones.map(z => z.cps) : []; - // Necesitamos cargar los gremios de otra ruta porque auth/me no los trae por defecto + + // Necesitamos cargar los gremios const resG = await fetch(`${API_URL}/admin/users`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); const dataG = await resG.json(); if(dataG.ok) { @@ -158,18 +174,37 @@ async function fetchBadges() { try { - // 1. Pedimos los servicios ASIGNADOS AL OPERARIO (para el badge naranja) - const resActive = await fetch(`${API_URL}/services/active`, { - headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } - }); - const dataActive = await resActive.json(); + const headers = { "Authorization": `Bearer ${localStorage.getItem("token")}` }; - if (dataActive.ok) { - const myServices = dataActive.services.filter(s => s.provider !== 'SYSTEM_BLOCK'); + // 1. Cargar servicios activos del operario y peticiones + const resActive = await fetch(`${API_URL}/services/active`, { headers }); + const dataActive = await resActive.json(); + + const resReqs = await fetch(`${API_URL}/agenda/requests`, { headers }); + const dataReqs = await resReqs.json(); + + if (dataActive.ok && dataReqs.ok) { let sinCitaCount = 0; - myServices.forEach(s => { + + // Sumamos las peticiones pendientes + sinCitaCount += dataReqs.requests.length; + + // Filtramos y contamos la lista normal + dataActive.services.forEach(s => { + if (s.provider === 'SYSTEM_BLOCK') return; + const raw = s.raw_data || {}; - if (!raw.scheduled_date) sinCitaCount++; + if (raw.appointment_status === 'pending') return; // Ya las contamos arriba + + // Si no tiene fecha, lo evaluamos + if (!raw.scheduled_date || raw.scheduled_date.trim() === "") { + // Validar que el estado no sea finalizado/anulado (ej: "Terminado sin fecha") + if (raw.status_operativo) { + const st = systemStatuses.find(x => String(x.id) === String(raw.status_operativo)); + if (st && st.is_final) return; + } + sinCitaCount++; + } }); if (sinCitaCount > 0) { @@ -179,42 +214,36 @@ } } - // 2. Pedimos la "Bolsa de Trabajo" (servicios sin asignar que cuadran con CP y Gremio) - // Usamos la ruta genérica de scraped pero filtramos en frontend para que sea más rápido. - const resScraped = await fetch(`${API_URL}/providers/scraped`, { - headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } - }); - const dataScraped = await resScraped.json(); + // 2. Pedimos la "Bolsa de Trabajo" SOLO SI TIENE PERMISO (operario_cerrado NO cuenta bolsa) + if (localStorage.getItem("role") === 'operario') { + const resScraped = await fetch(`${API_URL}/providers/scraped`, { headers }); + const dataScraped = await resScraped.json(); - if (dataScraped.ok) { - let bolsaCount = 0; - dataScraped.services.forEach(s => { - // Descartamos si ya tiene asignado o si es un bloqueo - if(s.assigned_to || s.provider === 'SYSTEM_BLOCK') return; - - const raw = s.raw_data || {}; - const dbStatus = raw.status_operativo; - - // Si está anulado/finalizado, descartar - if(s.status === 'archived' || (dbStatus && ['anulado', 'terminado', 'finalizado'].includes(dbStatus.toLowerCase()))) return; + if (dataScraped.ok) { + let bolsaCount = 0; + dataScraped.services.forEach(s => { + if(s.assigned_to || s.provider === 'SYSTEM_BLOCK') return; + + const raw = s.raw_data || {}; + const dbStatus = raw.status_operativo; + if(s.status === 'archived' || (dbStatus && ['anulado', 'terminado', 'finalizado'].includes(dbStatus.toLowerCase()))) return; - // Check de Gremio y Zona - const sGuild = String(s.guild_id || raw.guild_id); - const sCp = String(raw['Código Postal'] || raw['CP'] || "").trim(); + const sGuild = String(s.guild_id || raw.guild_id); + const sCp = String(raw['Código Postal'] || raw['CP'] || "").trim(); - const matchGuild = userGuilds.includes(Number(sGuild)) || userGuilds.includes(String(sGuild)); - const matchZone = userZones.some(z => sCp.startsWith(z)); // Coincidencia parcial (ej: zona "11" coge "11204") + const matchGuild = userGuilds.includes(Number(sGuild)) || userGuilds.includes(String(sGuild)); + const matchZone = userZones.some(z => sCp.startsWith(z)); - // Si cuadra (o si el operario no tiene filtros estrictos configurados, se lo enseñamos) - if((userGuilds.length === 0 || matchGuild) && (userZones.length === 0 || matchZone)) { - bolsaCount++; + if((userGuilds.length === 0 || matchGuild) && (userZones.length === 0 || matchZone)) { + bolsaCount++; + } + }); + + if (bolsaCount > 0) { + const b2 = document.getElementById('badgeBolsa'); + b2.innerText = `${bolsaCount} libre${bolsaCount > 1 ? 's' : ''}`; + b2.classList.remove('hidden'); } - }); - - if (bolsaCount > 0) { - const b2 = document.getElementById('badgeBolsa'); - b2.innerText = `${bolsaCount} libre${bolsaCount > 1 ? 's' : ''}`; - b2.classList.remove('hidden'); } }