diff --git a/calendario.html b/calendario.html
index 38c581d..1664c73 100644
--- a/calendario.html
+++ b/calendario.html
@@ -477,10 +477,16 @@
let localServices = [];
let systemStatuses = [];
let systemGuilds = [];
- let currentWeekStart = new Date();
- let selectedDateStr = "";
+ let currentWeekStart = new Date();
+ let selectedDateStr = "";
let activeNotifications = []; // Variable global para guardar IDs con mensajes
+ // 🛰️ SEGUIMIENTO GPS EN VIVO MIENTRAS EL AVISO ESTÁ "DE CAMINO"
+ let gpsPingIntervalId = null;
+ const GPS_PING_KEY = 'active_camino_service';
+ const GPS_PING_INTERVAL_MS = 25000; // cada 25s, mientras la página siga abierta
+ const GPS_PING_MAX_MS = 3 * 60 * 60 * 1000; // corte de seguridad: 3h sin cambiar de estado
+
async function applyTheme() {
try {
let theme = JSON.parse(localStorage.getItem('app_theme'));
@@ -540,6 +546,15 @@
// Comprobar notificaciones al cargar y cada 30 segundos
checkNotifications();
setInterval(checkNotifications, 30000);
+
+ // Si veníamos de marcar "De Camino" y se recargó la página (o se reabrió la app),
+ // retomamos el envío periódico de posición para ese mismo aviso.
+ try {
+ const tracked = JSON.parse(localStorage.getItem(GPS_PING_KEY) || 'null');
+ if (tracked && tracked.id && (Date.now() - tracked.startedAt) < GPS_PING_MAX_MS) {
+ startGpsTracking(tracked.id);
+ }
+ } catch (e) { /* localStorage corrupto o no disponible: seguimos sin reanudar */ }
});
let lastUnreadCount = 0; // Para saber si el número ha subido y sonar
@@ -1503,25 +1518,73 @@
body: JSON.stringify({ status_operativo: st.id })
});
- if(res.ok) {
- showToast("¡Actualizado!");
-
- if (action === 'camino' && navigator.geolocation) {
- navigator.geolocation.getCurrentPosition(async (pos) => {
- await fetch(`${API_URL}/services/${currentServiceId}/location`, {
- method: 'POST',
- headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
- body: JSON.stringify({ lat: pos.coords.latitude, lng: pos.coords.longitude })
- });
- }, () => {}, { enableHighAccuracy: false, timeout: 10000 });
+ if(res.ok) {
+ showToast("¡Actualizado!");
+
+ if (action === 'camino') {
+ // Arranca (o retoma) el envío periódico de posición mientras dure el desplazamiento
+ startGpsTracking(currentServiceId);
+ } else {
+ // Cualquier otro cambio de estado (p.ej. "Trabajando") significa que ya ha llegado:
+ // paramos el seguimiento GPS de este aviso si estaba activo.
+ stopGpsTrackingIfMatches(currentServiceId);
}
- closeModal();
- refreshData();
+ closeModal();
+ refreshData();
}
} catch (e) { alert("Error al actualizar"); }
}
+ // Envía una posición puntual del operario para el aviso indicado.
+ async function sendLocationPing(serviceId) {
+ if (!navigator.geolocation) return;
+ navigator.geolocation.getCurrentPosition(async (pos) => {
+ try {
+ await fetch(`${API_URL}/services/${serviceId}/location`, {
+ method: 'POST',
+ headers: { "Content-Type": "application/json", "Authorization": `Bearer ${localStorage.getItem("token")}` },
+ body: JSON.stringify({ lat: pos.coords.latitude, lng: pos.coords.longitude })
+ });
+ } catch (e) { /* fallo puntual de red: lo reintentamos en el siguiente ciclo */ }
+ }, () => { /* permiso denegado o GPS lento: lo reintentamos en el siguiente ciclo */ }, { enableHighAccuracy: false, timeout: 10000, maximumAge: 15000 });
+ }
+
+ // Arranca el ciclo de posición en vivo para un aviso "De Camino" (o lo retoma si ya estaba en curso).
+ function startGpsTracking(serviceId) {
+ if (gpsPingIntervalId) clearInterval(gpsPingIntervalId);
+
+ let tracked = null;
+ try { tracked = JSON.parse(localStorage.getItem(GPS_PING_KEY) || 'null'); } catch (e) {}
+ const startedAt = (tracked && tracked.id === serviceId) ? tracked.startedAt : Date.now();
+ localStorage.setItem(GPS_PING_KEY, JSON.stringify({ id: serviceId, startedAt }));
+
+ sendLocationPing(serviceId); // envío inmediato, sin esperar al primer ciclo
+
+ gpsPingIntervalId = setInterval(() => {
+ let cur = null;
+ try { cur = JSON.parse(localStorage.getItem(GPS_PING_KEY) || 'null'); } catch (e) {}
+ if (!cur || cur.id !== serviceId || (Date.now() - cur.startedAt) > GPS_PING_MAX_MS) {
+ stopGpsTracking();
+ return;
+ }
+ sendLocationPing(serviceId);
+ }, GPS_PING_INTERVAL_MS);
+ }
+
+ function stopGpsTracking() {
+ if (gpsPingIntervalId) { clearInterval(gpsPingIntervalId); gpsPingIntervalId = null; }
+ localStorage.removeItem(GPS_PING_KEY);
+ }
+
+ // Para el seguimiento solo si el aviso que se está rastreando es este mismo (evita cortar
+ // el rastreo de OTRO aviso "de camino" si el operario cambia el estado de uno distinto).
+ function stopGpsTrackingIfMatches(serviceId) {
+ let cur = null;
+ try { cur = JSON.parse(localStorage.getItem(GPS_PING_KEY) || 'null'); } catch (e) {}
+ if (cur && cur.id === serviceId) stopGpsTracking();
+ }
+
async function askToFinish() {
if(!currentServiceId) return;
@@ -1540,10 +1603,11 @@
})
});
- if(res.ok) {
- showToast(sendSurvey ? "Expediente finalizado y encuesta enviada." : "Expediente finalizado.");
- closeModal();
- refreshData();
+ if(res.ok) {
+ showToast(sendSurvey ? "Expediente finalizado y encuesta enviada." : "Expediente finalizado.");
+ stopGpsTrackingIfMatches(currentServiceId);
+ closeModal();
+ refreshData();
}
} catch (e) { alert("Error al finalizar."); }
}