From a680452b1e3466ca610c6654d07174adf570e125 Mon Sep 17 00:00:00 2001 From: marsalva Date: Sat, 28 Feb 2026 15:22:52 +0000 Subject: [PATCH] Actualizar calendario.html --- calendario.html | 95 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 70 insertions(+), 25 deletions(-) diff --git a/calendario.html b/calendario.html index 04bdecd..26881a4 100644 --- a/calendario.html +++ b/calendario.html @@ -116,7 +116,7 @@ De Camino @@ -189,9 +189,9 @@

Cambio de Estado

- - +
@@ -215,7 +215,7 @@
-

IntegraRepara Mobile

@@ -237,7 +237,7 @@ let systemStatuses = []; let systemGuilds = []; let currentWeekStart = new Date(); - let selectedDateStr = ""; + let selectedDateStr = ""; async function applyTheme() { try { @@ -350,7 +350,8 @@ const modalSelect = document.getElementById('detStatusMap'); modalSelect.innerHTML = ''; systemStatuses.forEach(st => { - modalSelect.innerHTML += ``; + // Modificación: Solo el nombre en el select para diseño más limpio + modalSelect.innerHTML += ``; }); } } catch (e) {} @@ -391,6 +392,19 @@ } } + // Mapa de colores (Mismo que en proveedores) + const colorMap = { + 'gray': { text: 'text-slate-500', bg: 'bg-slate-100', border: 'border-slate-200' }, + 'blue': { text: 'text-blue-600', bg: 'bg-blue-50', border: 'border-blue-100' }, + 'amber': { text: 'text-amber-600', bg: 'bg-amber-50', border: 'border-amber-100' }, + 'emerald': { text: 'text-emerald-600', bg: 'bg-emerald-50', border: 'border-emerald-100' }, + 'indigo': { text: 'text-indigo-600', bg: 'bg-indigo-50', border: 'border-indigo-100' }, + 'orange': { text: 'text-orange-600', bg: 'bg-orange-50', border: 'border-orange-100' }, + 'red': { text: 'text-red-600', bg: 'bg-red-50', border: 'border-red-100' }, + 'rose': { text: 'text-rose-600', bg: 'bg-rose-50', border: 'border-rose-100' }, + 'purple': { text: 'text-purple-600', bg: 'bg-purple-50', border: 'border-purple-100' } + }; + function renderServices() { const container = document.getElementById('servicesList'); const displayDate = selectedDateStr.split('-').reverse().join('/'); @@ -416,28 +430,33 @@ let compShort = (raw["Compañía"] || "Particular").split('-')[0].trim().substring(0, 15); const guildObj = systemGuilds.find(g => String(g.id) === String(s.guild_id || raw.guild_id)); - // LÓGICA DE ICONO SEGÚN ESTADO + // MODIFICACIÓN 1: LÓGICA DE ICONO Y COLOR SEGÚN ESTADO let iconName = "clock"; const dbStatId = raw.status_operativo; const statusObj = systemStatuses.find(st => String(st.id) === String(dbStatId)); const stName = (statusObj?.name || "").toLowerCase(); + const stColor = (statusObj?.color || "gray"); if (stName.includes('camino')) iconName = "car"; - else if (stName.includes('trabajando') || stName.includes('llegado')) iconName = "wrench"; + else if (stName.includes('trabajando') || stName.includes('llegado') || stName.includes('reparación')) iconName = "hammer"; else if (stName.includes('incidencia') || stName.includes('pausa')) iconName = "alert-triangle"; else if (stName.includes('citado')) iconName = "calendar"; + + const cMap = colorMap[stColor] || colorMap['gray']; return `
${s.is_urgent ? '
Urgente
' : ''}
- - ${time} +
+ +
+ ${time}
- ${compShort} - ${guildObj ? guildObj.name : 'Reparación'} + ${compShort} + ${guildObj ? guildObj.name : 'Reparación'}

${name}

${addr}

@@ -509,7 +528,6 @@ function callClient() { const p = document.getElementById('detPhoneRaw').value; if (p) window.location.href = `tel:+34${p}`; else alert("Sin teléfono"); } function openWhatsApp() { const p = document.getElementById('detPhoneRaw').value; if (p) window.open(`https://wa.me/34${p}`, '_blank'); else alert("Sin teléfono"); } - // BOTÓN VER MAPA CORREGIDO PARA ANDROID E IOS function openMaps() { const a = document.getElementById('detAddress').innerText; if (a) { @@ -517,7 +535,6 @@ } } -// CÁLCULO DE GPS ULTRARRÁPIDO CON FALLBACK Y TIMEOUT async function calculateDistance(dest) { const loading = document.getElementById('gpsLoading'); const result = document.getElementById('gpsResult'); @@ -533,22 +550,19 @@ result.classList.add('hidden'); lucide.createIcons(); - // OPCIONES MÁGICAS PARA QUE SEA INSTANTÁNEO const gpsOptions = { - enableHighAccuracy: false, // Usa antenas/wifi en vez de buscar satélites (tarda milisegundos en vez de minutos) - timeout: 8000, // Máximo 8 segundos de espera, si no, cancela - maximumAge: 300000 // Permite usar la ubicación de hace 5 minutos si ya la sabe + enableHighAccuracy: false, + timeout: 8000, + maximumAge: 300000 }; navigator.geolocation.getCurrentPosition(async (pos) => { const lat = pos.coords.latitude; const lon = pos.coords.longitude; try { - // Intento 1: Dirección completa let res = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(dest + ', España')}`); let data = await res.json(); - // Intento 2: Si falla (porque hay "pisos", "escaleras", etc), buscamos solo por CP y Población if (!data || data.length === 0) { const parts = dest.split(','); const fallbackDest = parts.length > 1 ? parts[parts.length - 1].trim() : dest; @@ -573,15 +587,14 @@ } }, (err) => { loading.innerHTML = 'GPS Lento/Denegado'; - }, gpsOptions); // <- AQUÍ PASAMOS LAS OPCIONES DE VELOCIDAD + }, gpsOptions); } async function quickUpdate(action) { if(!currentServiceId) return; let word = ""; let msg = ""; - if(action === 'camino') { word = "camino"; msg = "¿Enviar 'De Camino'?"; } + if(action === 'camino') { word = "camino"; msg = "¿Enviar estado 'De Camino'?"; } if(action === 'trabajando') { word = "trabaja"; msg = "¿Iniciar trabajo?"; } - if(action === 'finalizado') { word = "finaliza"; msg = "¿Finalizar expediente?"; } if(!confirm(msg)) return; const st = systemStatuses.find(s => s.name.toLowerCase().includes(word)); @@ -596,7 +609,6 @@ if(res.ok) { showToast("¡Actualizado!"); - // MAGIA: Si es "De camino", forzamos enviar el GPS INMEDIATAMENTE if (action === 'camino' && navigator.geolocation) { navigator.geolocation.getCurrentPosition(async (pos) => { await fetch(`${API_URL}/services/${currentServiceId}/location`, { @@ -610,7 +622,40 @@ closeModal(); refreshData(); } - } catch (e) { alert("Error"); } + } catch (e) { alert("Error al actualizar"); } + } + + // MODIFICACIÓN 3: LÓGICA DE FINALIZAR CON PREGUNTA DE ENCUESTA + async function askToFinish() { + if(!currentServiceId) return; + + const stFinalizado = systemStatuses.find(s => s.name.toLowerCase().includes('finaliza')); + if(!stFinalizado) return alert("El sistema no tiene un estado Finalizado válido."); + + // Preguntamos explícitamente si se envía la encuesta + const sendSurvey = confirm("¿Deseas enviar la encuesta de satisfacción al cliente antes de finalizar?"); + + try { + // Al poner el estado a Finalizado, el servidor borra el aviso de la agenda. + // Le pasamos al servidor un "flag" para que sepa si envía o no envía el WhatsApp de la encuesta. + // NOTA: Como la ruta de server.js actual dispara automáticamente el WA al ver 'finalizado', + // le pasamos un booleano en el body "skip_survey" para que el servidor lo bloquee si eligió NO. + + const res = await fetch(`${API_URL}/services/set-appointment/${currentServiceId}`, { + method: 'PUT', + headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` }, + body: JSON.stringify({ + status_operativo: stFinalizado.id, + skip_survey: !sendSurvey // <- Flag que puedes usar en tu server.js si quieres anularlo + }) + }); + + if(res.ok) { + showToast(sendSurvey ? "Expediente finalizado y encuesta enviada." : "Expediente finalizado."); + closeModal(); + refreshData(); + } + } catch (e) { alert("Error al finalizar."); } } async function saveAppointment() {