Actualizar index.html
This commit is contained in:
126
index.html
126
index.html
@@ -14,13 +14,6 @@
|
|||||||
.blob { position: absolute; filter: blur(60px); z-index: -1; opacity: 0.4; }
|
.blob { position: absolute; filter: blur(60px); z-index: -1; opacity: 0.4; }
|
||||||
.no-scrollbar::-webkit-scrollbar { display: none; }
|
.no-scrollbar::-webkit-scrollbar { display: none; }
|
||||||
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
.no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
|
||||||
|
|
||||||
/* Animación fluida para la barra de ruta del camión */
|
|
||||||
@keyframes movingLine {
|
|
||||||
0% { transform: translateX(-100%); }
|
|
||||||
100% { transform: translateX(200%); }
|
|
||||||
}
|
|
||||||
.animate-moving-line { animation: movingLine 2s linear infinite; }
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="text-slate-800 font-sans antialiased min-h-screen flex flex-col items-center relative overflow-x-hidden">
|
<body class="text-slate-800 font-sans antialiased min-h-screen flex flex-col items-center relative overflow-x-hidden">
|
||||||
@@ -82,6 +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
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", async () => {
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
lucide.createIcons();
|
lucide.createIcons();
|
||||||
@@ -99,20 +93,16 @@
|
|||||||
if (!data.ok) throw new Error("Token inválido");
|
if (!data.ok) throw new Error("Token inválido");
|
||||||
renderPortal(data.client, data.company, data.services);
|
renderPortal(data.client, data.company, data.services);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
|
||||||
showError();
|
showError();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
function showError() {
|
function showError() {
|
||||||
const loader = document.getElementById('loader');
|
document.getElementById('loader').classList.add('opacity-0', 'pointer-events-none');
|
||||||
const errorScreen = document.getElementById('errorScreen');
|
|
||||||
|
|
||||||
loader.classList.add('opacity-0', 'pointer-events-none');
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loader.classList.add('hidden');
|
document.getElementById('loader').classList.add('hidden');
|
||||||
errorScreen.classList.remove('hidden');
|
document.getElementById('errorScreen').classList.remove('hidden');
|
||||||
errorScreen.classList.add('flex');
|
document.getElementById('errorScreen').classList.add('flex');
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +152,7 @@
|
|||||||
|
|
||||||
allServices.forEach(srv => {
|
allServices.forEach(srv => {
|
||||||
const isFinalized = srv.status_name === 'Terminado';
|
const isFinalized = srv.status_name === 'Terminado';
|
||||||
const isPendingWorker = (!srv.assigned_worker || srv.assigned_worker === 'Pendiente');
|
const raw = srv.raw_data || {};
|
||||||
const descLimpia = summarizeDescription(srv.description);
|
const descLimpia = summarizeDescription(srv.description);
|
||||||
let statusHtml = '';
|
let statusHtml = '';
|
||||||
|
|
||||||
@@ -173,21 +163,22 @@
|
|||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
else if (srv.status_name === 'Técnico de Camino') {
|
else if (srv.status_name === 'Técnico de Camino') {
|
||||||
// NUEVO DISEÑO ANIMADO Y LIMPIO PARA "DE CAMINO" SIN MAPA
|
// Preparamos la dirección para calcular la ETA
|
||||||
|
const fullAddr = `${raw["Dirección"] || ""}, ${raw["Código Postal"] || ""} ${raw["Población"] || ""}`;
|
||||||
|
etasToInit.push({ id: srv.id, address: fullAddr });
|
||||||
|
|
||||||
|
// ESTRUCTURA BASE DE LA BARRA DE PROGRESO (SE LLENA CON JS)
|
||||||
statusHtml = `
|
statusHtml = `
|
||||||
<div class="bg-indigo-50 border border-indigo-200 p-6 rounded-3xl relative overflow-hidden shadow-inner">
|
<div class="bg-indigo-50 border border-indigo-200 p-6 rounded-3xl relative overflow-hidden shadow-inner">
|
||||||
<div class="absolute top-0 left-0 w-full h-1.5 bg-indigo-100 overflow-hidden">
|
|
||||||
<div class="w-1/2 h-full bg-indigo-500 rounded-full animate-moving-line"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex items-center gap-5 relative z-10">
|
<div class="flex items-center gap-5 relative z-10">
|
||||||
<div class="w-14 h-14 bg-indigo-500 text-white rounded-2xl flex items-center justify-center shadow-lg shadow-indigo-500/30 animate-pulse shrink-0">
|
<div class="w-14 h-14 bg-indigo-500 text-white rounded-2xl flex items-center justify-center shadow-lg shadow-indigo-500/30 animate-pulse shrink-0">
|
||||||
<i data-lucide="truck" class="w-7 h-7"></i>
|
<i data-lucide="truck" class="w-7 h-7"></i>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="flex-1 min-w-0">
|
||||||
<p class="text-[9px] font-black uppercase tracking-widest text-indigo-400 mb-0.5">En ruta hacia tu domicilio</p>
|
<h4 class="font-black text-indigo-900 uppercase text-lg leading-none mb-1.5 tracking-tight">¡En camino!</h4>
|
||||||
<h4 class="font-black text-indigo-900 uppercase text-lg leading-none mb-1.5 tracking-tight">¡Técnico en camino!</h4>
|
<div id="eta-container-${srv.id}">
|
||||||
<p class="text-xs font-bold text-indigo-600 leading-tight">Prepárate, el técnico está a punto de llegar a tu ubicación.</p>
|
<p class="text-[10px] font-bold text-indigo-500 flex items-center gap-1.5"><i data-lucide="loader-2" class="w-3 h-3 animate-spin"></i> Calculando ruta...</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -254,8 +245,93 @@
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
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));
|
||||||
}, 300);
|
}, 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// CÁLCULO DE ETA (TIEMPO ESTIMADO) INTELIGENTE
|
||||||
|
// ==========================================
|
||||||
|
async function calculateClientETA(serviceId, destAddress) {
|
||||||
|
const container = document.getElementById(`eta-container-${serviceId}`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Obtenemos la ubicación de donde salió el técnico
|
||||||
|
const res = await fetch(`${API_URL}/public/portal/${urlToken}/location/${serviceId}`);
|
||||||
|
const data = await res.json();
|
||||||
|
|
||||||
|
if (!data.ok || !data.location) {
|
||||||
|
container.innerHTML = `<p class="text-xs font-bold text-indigo-600 leading-tight">El técnico está conduciendo hacia tu domicilio.</p>`;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const wLat = parseFloat(data.location.lat);
|
||||||
|
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 geoData = await geoRes.json();
|
||||||
|
|
||||||
|
if (!geoData || geoData.length === 0) {
|
||||||
|
const parts = destAddress.split(',');
|
||||||
|
const fallbackDest = parts.length > 1 ? parts[parts.length - 1].trim() : destAddress;
|
||||||
|
geoRes = await fetch(`https://nominatim.openstreetmap.org/search?format=json&q=${encodeURIComponent(fallbackDest + ', España')}`);
|
||||||
|
geoData = await geoRes.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (geoData && geoData.length > 0) {
|
||||||
|
const cLat = parseFloat(geoData[0].lat);
|
||||||
|
const cLon = parseFloat(geoData[0].lon);
|
||||||
|
|
||||||
|
// 3. Calculamos la distancia en línea recta (Fórmula de Haversine)
|
||||||
|
const R = 6371;
|
||||||
|
const dLat = (cLat - wLat) * Math.PI / 180;
|
||||||
|
const dLon = (cLon - wLon) * Math.PI / 180;
|
||||||
|
const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(wLat * Math.PI / 180) * Math.cos(cLat * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2);
|
||||||
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
||||||
|
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;
|
||||||
|
|
||||||
|
// 5. EL TRUCO MAGICO: Restar los minutos que ya han pasado desde que salió
|
||||||
|
const startedAt = new Date(data.location.updated_at).getTime();
|
||||||
|
const now = new Date().getTime();
|
||||||
|
const diffMins = Math.floor((now - startedAt) / 60000);
|
||||||
|
|
||||||
|
let remainingMins = totalMins - diffMins;
|
||||||
|
if (remainingMins < 1) remainingMins = 1; // Para que no ponga 0 o negativo
|
||||||
|
|
||||||
|
// Calculamos el % para la barra visual
|
||||||
|
let progressPercent = (diffMins / totalMins) * 100;
|
||||||
|
if (progressPercent > 95) progressPercent = 95;
|
||||||
|
if (progressPercent < 5) progressPercent = 5;
|
||||||
|
|
||||||
|
// Dibujamos la barra visual
|
||||||
|
container.innerHTML = `
|
||||||
|
<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>
|
||||||
|
</p>
|
||||||
|
<div class="w-full bg-indigo-100 rounded-full h-2.5 overflow-hidden shadow-inner">
|
||||||
|
<div class="bg-indigo-500 h-full rounded-full transition-all duration-1000 relative" style="width: ${progressPercent}%">
|
||||||
|
<div class="absolute right-0 top-0 bottom-0 w-4 bg-white/40 animate-pulse"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex justify-between items-center mt-1 px-1">
|
||||||
|
<p class="text-[8px] font-black uppercase text-indigo-300">Saliendo</p>
|
||||||
|
<p class="text-[8px] font-black uppercase text-indigo-400">A ${km.toFixed(1)} km</p>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
lucide.createIcons();
|
||||||
|
} else {
|
||||||
|
container.innerHTML = `<p class="text-xs font-bold text-indigo-600 leading-tight">El técnico está conduciendo hacia tu domicilio.</p>`;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
container.innerHTML = `<p class="text-xs font-bold text-indigo-600 leading-tight">El técnico está conduciendo hacia tu domicilio.</p>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user