Actualizar index.html

This commit is contained in:
2026-02-26 07:55:17 +00:00
parent 56ba1b6fa8
commit 64fe4717ac

View File

@@ -75,7 +75,7 @@
: 'https://integrarepara-api.integrarepara.es'; : 'https://integrarepara-api.integrarepara.es';
let urlToken = ""; let urlToken = "";
let etasToInit = []; // Para procesar los tiempos de llegada al cargar let etasToInit = [];
document.addEventListener("DOMContentLoaded", async () => { document.addEventListener("DOMContentLoaded", async () => {
lucide.createIcons(); lucide.createIcons();
@@ -149,7 +149,6 @@
const historyContainerWrapper = document.getElementById('historyContainerWrapper'); const historyContainerWrapper = document.getElementById('historyContainerWrapper');
const historyContainer = document.getElementById('historyServicesContainer'); const historyContainer = document.getElementById('historyServicesContainer');
// Limpiar contenedores por si acaso (útil si hay recargas)
activeContainer.innerHTML = ''; activeContainer.innerHTML = '';
historyContainer.innerHTML = ''; historyContainer.innerHTML = '';
@@ -157,12 +156,12 @@
let hasHistory = false; let hasHistory = false;
allServices.forEach(srv => { allServices.forEach(srv => {
// Usamos la nueva variable booleana que nos manda el servidor
const isFinalized = srv.is_final; const isFinalized = srv.is_final;
const raw = srv.raw_data || {}; const raw = srv.raw_data || {};
const descLimpia = summarizeDescription(srv.description); const descLimpia = summarizeDescription(srv.description);
let statusHtml = ''; let statusHtml = '';
// ESTRUCTURA PRINCIPAL DE ESTADOS
if (isFinalized) { if (isFinalized) {
statusHtml = ` statusHtml = `
<div class="bg-slate-50 border border-slate-200 p-4 rounded-2xl flex items-center justify-between opacity-70 grayscale"> <div class="bg-slate-50 border border-slate-200 p-4 rounded-2xl flex items-center justify-between opacity-70 grayscale">
@@ -214,13 +213,21 @@
else if (srv.status_name === 'Visita Agendada' || (srv.scheduled_date && srv.scheduled_time)) { else if (srv.status_name === 'Visita Agendada' || (srv.scheduled_date && srv.scheduled_time)) {
const endT = addOneHour(srv.scheduled_time); const endT = addOneHour(srv.scheduled_time);
statusHtml = ` statusHtml = `
<div class="bg-gradient-to-br from-emerald-400 to-emerald-600 p-6 rounded-3xl flex items-center gap-5 text-white shadow-lg shadow-emerald-500/30 relative overflow-hidden"> <div class="bg-gradient-to-br from-emerald-400 to-emerald-600 p-6 rounded-3xl text-white shadow-lg shadow-emerald-500/30 relative overflow-hidden">
<div class="w-14 h-14 bg-white/20 rounded-2xl flex items-center justify-center backdrop-blur-md border border-white/30 shrink-0 relative z-10"><i data-lucide="calendar-check" class="w-7 h-7 text-white"></i></div> <div class="flex items-center gap-5 mb-4">
<div class="relative z-10"> <div class="w-14 h-14 bg-white/20 rounded-2xl flex items-center justify-center backdrop-blur-md border border-white/30 shrink-0 relative z-10">
<p class="text-[9px] font-black uppercase tracking-widest text-emerald-100 mb-0.5">Visita Confirmada</p> <i data-lucide="calendar-check" class="w-7 h-7 text-white"></i>
<p class="font-black uppercase text-lg leading-none mb-1.5">${formatDate(srv.scheduled_date)}</p> </div>
<p class="text-sm font-bold text-emerald-50 flex items-center gap-1.5"><i data-lucide="clock" class="w-4 h-4"></i> Llegada aprox: ${srv.scheduled_time} - ${endT}</p> <div class="relative z-10 flex-1">
<p class="text-[9px] font-black uppercase tracking-widest text-emerald-100 mb-0.5">Visita Confirmada</p>
<p class="font-black uppercase text-lg leading-none mb-1.5">${formatDate(srv.scheduled_date)}</p>
<p class="text-sm font-bold text-emerald-50 flex items-center gap-1.5"><i data-lucide="clock" class="w-4 h-4"></i> ${srv.scheduled_time} - ${endT}</p>
</div>
</div> </div>
<a href="cita.html?token=${urlToken}&service=${srv.id}" class="w-full bg-white/20 hover:bg-white/30 text-white border border-white/30 backdrop-blur-md font-black py-3 rounded-xl flex items-center justify-center gap-2 transition-colors text-[10px] uppercase tracking-widest relative z-10">
<i data-lucide="calendar-clock" class="w-4 h-4"></i> Modificar Cita
</a>
</div>`; </div>`;
} }
else { else {
@@ -231,21 +238,76 @@
</div>`; </div>`;
} }
// =====================================
// NUEVO: BLOQUE DE BOTONES DE CONTACTO
// =====================================
let contactHtml = '';
const hasWorker = srv.assigned_worker && srv.assigned_worker !== 'Pendiente';
if (hasWorker && !isFinalized) {
// Extraemos el teléfono del trabajador (si la BD lo manda) o usamos uno temporal para que funcione el enlace
const workerPhone = srv.worker_phone ? srv.worker_phone.replace('+', '') : "34000000000";
contactHtml = `
<div class="flex gap-2 mt-5">
<a href="tel:+${workerPhone}" class="flex-1 bg-blue-50 hover:bg-blue-100 border border-blue-200 text-blue-600 font-black py-3 rounded-xl flex items-center justify-center gap-1.5 active:scale-95 transition-transform shadow-sm text-[10px] uppercase tracking-widest">
<i data-lucide="phone" class="w-4 h-4"></i> Llamar Técnico
</a>
<a href="https://wa.me/${workerPhone}" target="_blank" class="flex-1 bg-emerald-50 hover:bg-emerald-100 border border-emerald-200 text-emerald-600 font-black py-3 rounded-xl flex items-center justify-center gap-1.5 active:scale-95 transition-transform shadow-sm text-[10px] uppercase tracking-widest">
<i data-lucide="message-circle" class="w-4 h-4"></i> WhatsApp
</a>
</div>
`;
}
// =====================================
// NUEVO: DATOS DEL ASEGURADO (CAJA LIMPIA)
// =====================================
const clientDataHtml = `
<div class="bg-slate-50/50 rounded-2xl p-4 mt-5 border border-slate-100 text-left">
<p class="text-[9px] font-black text-slate-400 uppercase tracking-widest mb-3 border-b border-slate-100 pb-2">Información del Siniestro</p>
<div class="space-y-3">
<div class="flex items-start gap-2.5">
<i data-lucide="user" class="w-4 h-4 text-slate-400 mt-0.5"></i>
<p class="text-xs font-bold text-slate-700 leading-tight">${raw["Nombre Cliente"] || raw["CLIENTE"] || client.name || "Asegurado"}</p>
</div>
<div class="flex items-start gap-2.5">
<i data-lucide="map-pin" class="w-4 h-4 text-slate-400 mt-0.5"></i>
<p class="text-xs font-bold text-slate-700 leading-tight">
${raw["Dirección"] || raw["DOMICILIO"] || "Dirección no especificada"}<br>
<span class="text-[10px] text-slate-500 font-medium">${raw["Código Postal"] || ""} ${raw["Población"] || raw["POBLACION-PROVINCIA"] || ""}</span>
</p>
</div>
<div class="flex items-start gap-2.5">
<i data-lucide="building" class="w-4 h-4 text-slate-400 mt-0.5"></i>
<p class="text-xs font-bold text-slate-700 leading-tight">${raw["Compañía"] || raw["COMPAÑIA"] || "Particular"}</p>
</div>
</div>
</div>
`;
// ENSAMBLAJE DE LA TARJETA FINAL
let cardHtml = ` let cardHtml = `
<div class="bg-white/80 backdrop-blur-xl border border-white shadow-xl shadow-slate-200/40 rounded-[2.5rem] p-6 mb-6 relative overflow-hidden"> <div class="bg-white/80 backdrop-blur-xl border border-white shadow-xl shadow-slate-200/40 rounded-[2.5rem] p-6 mb-6 relative overflow-hidden text-left">
<div class="flex justify-between items-start mb-5"> <div class="flex justify-between items-start mb-5">
<span class="text-[10px] font-black text-slate-400 uppercase tracking-widest">${srv.title}</span> <span class="text-[10px] font-black text-slate-400 uppercase tracking-widest">${srv.title}</span>
${srv.assigned_worker && srv.assigned_worker !== 'Pendiente' ? ${hasWorker ?
`<div class="bg-slate-50 border border-slate-100 px-3 py-1.5 rounded-lg text-center shrink-0"> `<div class="bg-slate-50 border border-slate-100 px-3 py-1.5 rounded-lg text-center shrink-0">
<p class="text-[8px] uppercase font-black text-slate-400 mb-0.5">Técnico</p> <p class="text-[8px] uppercase font-black text-slate-400 mb-0.5">Técnico</p>
<p class="text-[10px] font-bold text-blue-600">${srv.assigned_worker.split(' ')[0]}</p> <p class="text-[10px] font-bold text-blue-600">${srv.assigned_worker.split(' ')[0]}</p>
</div>` : '' </div>` : ''
} }
</div> </div>
<div class="mb-6">${statusHtml}</div>
<div class="pt-5 border-t border-slate-100"> <div class="mb-5">${statusHtml}</div>
${contactHtml}
${clientDataHtml}
<div class="pt-5 mt-5 border-t border-slate-100">
<p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1.5">Motivo de la Visita</p> <p class="text-[10px] font-black text-slate-400 uppercase tracking-widest mb-1.5">Motivo de la Visita</p>
<h3 class="font-black text-slate-800 text-sm leading-snug">${descLimpia}</h3> <h3 class="font-black text-slate-800 text-sm leading-relaxed">${descLimpia}</h3>
</div> </div>
</div> </div>
`; `;
@@ -259,18 +321,11 @@
} }
}); });
// Lógica para mostrar/ocultar secciones if (!hasActive) document.getElementById('noActiveServices').classList.remove('hidden');
if (!hasActive) { else document.getElementById('noActiveServices').classList.add('hidden');
document.getElementById('noActiveServices').classList.remove('hidden');
} else {
document.getElementById('noActiveServices').classList.add('hidden');
}
if (hasHistory) { if (hasHistory) document.getElementById('historyContainerWrapper').classList.remove('hidden');
historyContainerWrapper.classList.remove('hidden'); else document.getElementById('historyContainerWrapper').classList.add('hidden');
} else {
historyContainerWrapper.classList.add('hidden');
}
lucide.createIcons(); lucide.createIcons();
@@ -279,7 +334,6 @@
document.getElementById('loader').classList.add('hidden'); document.getElementById('loader').classList.add('hidden');
document.getElementById('mainContent').classList.remove('hidden'); document.getElementById('mainContent').classList.remove('hidden');
// Disparamos el cálculo de ETA para los que estén De Camino
etasToInit.forEach(item => calculateClientETA(item.id, item.address)); etasToInit.forEach(item => calculateClientETA(item.id, item.address));
}, 300); }, 300);
} }
@@ -291,7 +345,6 @@
const container = document.getElementById(`eta-container-${serviceId}`); const container = document.getElementById(`eta-container-${serviceId}`);
try { try {
// 1. Obtenemos la ubicación de donde salió el técnico
const res = await fetch(`${API_URL}/public/portal/${urlToken}/location/${serviceId}`); const res = await fetch(`${API_URL}/public/portal/${urlToken}/location/${serviceId}`);
const data = await res.json(); const data = await res.json();
@@ -303,7 +356,6 @@
const wLat = parseFloat(data.location.lat); const wLat = parseFloat(data.location.lat);
const wLon = parseFloat(data.location.lng); const wLon = parseFloat(data.location.lng);
// 2. Buscamos las coordenadas del cliente
let geoRes = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(destAddress + ', España')}`); let geoRes = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(destAddress + ', España')}`);
let geoData = await geoRes.json(); let geoData = await geoRes.json();
@@ -318,7 +370,6 @@
const cLat = parseFloat(geoData[0].lat); const cLat = parseFloat(geoData[0].lat);
const cLon = parseFloat(geoData[0].lon); const cLon = parseFloat(geoData[0].lon);
// 3. Calculamos la distancia en línea recta (Fórmula de Haversine)
const R = 6371; const R = 6371;
const dLat = (cLat - wLat) * Math.PI / 180; const dLat = (cLat - wLat) * Math.PI / 180;
const dLon = (cLon - wLon) * Math.PI / 180; const dLon = (cLon - wLon) * Math.PI / 180;
@@ -326,23 +377,19 @@
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
const km = R * c; const km = R * c;
// 4. Estimamos los minutos totales (velocidad media ciudad 35km/h + 5min atascos/aparcar)
const totalMins = Math.round((km/35)*60) + 5; const totalMins = Math.round((km/35)*60) + 5;
// 5. EL TRUCO MAGICO: Restar los minutos que ya han pasado desde que salió
const startedAt = new Date(data.location.updated_at).getTime(); const startedAt = new Date(data.location.updated_at).getTime();
const now = new Date().getTime(); const now = new Date().getTime();
const diffMins = Math.floor((now - startedAt) / 60000); const diffMins = Math.floor((now - startedAt) / 60000);
let remainingMins = totalMins - diffMins; let remainingMins = totalMins - diffMins;
if (remainingMins < 1) remainingMins = 1; // Para que no ponga 0 o negativo if (remainingMins < 1) remainingMins = 1;
// Calculamos el % para la barra visual
let progressPercent = (diffMins / totalMins) * 100; let progressPercent = (diffMins / totalMins) * 100;
if (progressPercent > 95) progressPercent = 95; if (progressPercent > 95) progressPercent = 95;
if (progressPercent < 5) progressPercent = 5; if (progressPercent < 5) progressPercent = 5;
// Dibujamos la barra visual
container.innerHTML = ` container.innerHTML = `
<p class="text-[10px] font-black text-indigo-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5"> <p class="text-[10px] font-black text-indigo-500 uppercase tracking-widest mb-1.5 flex items-center gap-1.5">
<i data-lucide="clock" class="w-3.5 h-3.5"></i> Llegada en aprox. <span class="text-indigo-700 text-sm ml-0.5">${remainingMins} min</span> <i data-lucide="clock" class="w-3.5 h-3.5"></i> Llegada en aprox. <span class="text-indigo-700 text-sm ml-0.5">${remainingMins} min</span>