From 0f9bd3f5762ece1dd2204dc2fba3709b50621b22 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sun, 13 Sep 2026 13:08:45 +0000 Subject: [PATCH] =?UTF-8?q?menu.html:=20carga=20js/layout.js=20(icono/favi?= =?UTF-8?q?con=20din=C3=A1mico)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- menu.html | 497 +++++++++++++++++++++++++++--------------------------- 1 file changed, 249 insertions(+), 248 deletions(-) diff --git a/menu.html b/menu.html index 0a7fe45..b3552ed 100644 --- a/menu.html +++ b/menu.html @@ -1,279 +1,280 @@ - - - Menú - IntegraRepara - - - +/* Ajuste limpio para el scroll sin barra abajo */ +.main-content { padding-bottom: calc(env(safe-area-inset-bottom) + 30px); } + +.app-card { box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05); } + +/* Clases CSS dinámicas para aplicar las variables */ +.bg-primary-dynamic { background-color: var(--primary) !important; } +.text-primary-dynamic { color: var(--primary) !important; } + -
+
-
-
-
-

HOY

-

Hola,

-
- - -
-
+
+
+
+

HOY

+

Hola,

+
-
- +
- -
-
- -
-

Solicitar
Servicios

- -
+
+ -
+ +
+
+ +
+

Buscar
Servicio

+
- +await loadStatuses(); +await fetchUserData(); +fetchBadges(); +fetchChatNotifications(); // <-- Nueva función +}); + +async function fetchChatNotifications() { +try { +const res = await fetch(`${API_URL}/worker/notifications`, { +headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } +}); +const data = await res.json(); +if (data.ok && data.unreadCount > 0) { +const badge = document.getElementById('badgeChat'); +badge.innerText = data.unreadCount; +badge.classList.remove('hidden'); +} +} catch (e) {} +} + +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) { +userZones = Array.isArray(data.user.zones) ? data.user.zones.map(z => z.cps) : []; +const resG = await fetch(`${API_URL}/admin/users`, { headers: { "Authorization": `Bearer ${localStorage.getItem("token")}` } }); +const dataG = await resG.json(); +if(dataG.ok) { +const myUser = dataG.users.find(u => u.id === data.user.id); +if(myUser) userGuilds = myUser.guilds || []; +} +} +} catch(e) {} +} + +async function fetchBadges() { +try { +const headers = { "Authorization": `Bearer ${localStorage.getItem("token")}` }; +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; +sinCitaCount += dataReqs.requests.length; +dataActive.services.forEach(s => { +if (s.provider === 'SYSTEM_BLOCK') return; +const raw = s.raw_data || {}; +if (raw.appointment_status === 'pending') return; +if (!raw.scheduled_date || raw.scheduled_date.trim() === "") { +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) { +const b1 = document.getElementById('badgeAsignados'); +b1.innerText = `${sinCitaCount} pendiente${sinCitaCount > 1 ? 's' : ''}`; +b1.classList.remove('hidden'); +} +} + +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; +let sinGremioCount = 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; +// 🆕 Mismo criterio que solicitar.html: si el aviso no tiene gremio asignado +// de verdad, es visible para cualquier operario (antes esto no se contaba aquí, +// por eso el número de la burbuja no cuadraba con lo que salía en la lista). +const rawGuildId = s.guild_id ?? raw.guild_id; +const hasGuild = rawGuildId !== undefined && rawGuildId !== null && String(rawGuildId).trim() !== "" && String(rawGuildId) !== "0"; +const sGuild = String(rawGuildId); +const sCp = String(raw['Código Postal'] || raw['CP'] || "").trim(); +const matchGuild = hasGuild && (userGuilds.includes(Number(sGuild)) || userGuilds.includes(String(sGuild))); +const matchZone = userZones.some(z => sCp.startsWith(z)); +const guildOk = !hasGuild || userGuilds.length === 0 || matchGuild; +if(guildOk && (userZones.length === 0 || matchZone)) { +bolsaCount++; +if (!hasGuild) sinGremioCount++; +} +}); +if (bolsaCount > 0) { +const b2 = document.getElementById('badgeBolsa'); +let texto = `${bolsaCount} servicio${bolsaCount > 1 ? 's' : ''}`; +if (sinGremioCount > 0) texto += ` y ${sinGremioCount} sin gremio`; +b2.innerText = texto; +b2.classList.remove('hidden'); +} +} +} +} catch (e) { console.log("Error cargando badges"); } +} + +function logout() { +localStorage.clear(); +window.location.href = "index.html"; +} + - \ No newline at end of file +