From 0e06fec1aecc5cc7229e6dc4dcb441956c5884b4 Mon Sep 17 00:00:00 2001
From: Hanzo_dev <2002samudiojohan@gmail.com>
Date: Thu, 5 Mar 2026 18:27:40 -0500
Subject: [PATCH] feat: motor de calculo real de llegadas de buses por parada -
reemplaza datos mock con logica usando travel_time_minutes + horarios del
dia, con soporte GPS para tiempos de espera en tiempo real
---
frontend/src/components/BusStopInfoModal.vue | 223 ++++++++++++++++---
frontend/src/services/busStopsService.ts | 160 ++++++++++++-
2 files changed, 338 insertions(+), 45 deletions(-)
diff --git a/frontend/src/components/BusStopInfoModal.vue b/frontend/src/components/BusStopInfoModal.vue
index eca02fe..f1a48ca 100644
--- a/frontend/src/components/BusStopInfoModal.vue
+++ b/frontend/src/components/BusStopInfoModal.vue
@@ -1,7 +1,7 @@
@@ -81,25 +103,32 @@ watch(() => props.isOpen, async (isOpen) => {
roofing
- Shelter
+ Cubierta
event_seat
- Seating
+ Asientos
accessible
- Accessible
+ Accesible
-
Next Arrivals
+
+
refresh
-
Loading arrivals...
+
Obteniendo horarios...
@@ -107,20 +136,35 @@ watch(() => props.isOpen, async (isOpen) => {
v-for="(arrival, index) in upcomingArrivals"
:key="index"
class="arrival-item"
- :style="{ animationDelay: `${index * 0.1}s` }"
+ :style="{ animationDelay: `${index * 0.07}s` }"
>
directions_bus
-
{{ arrival.routeName }}
+
+ {{ arrival.routeName }}
+ Sale: {{ formatTo12Hour(arrival.departureTime) }}
+
-
+
+
+
+
+ {{ formatWait(arrival.waitMinutes) }}
+
+ {{ formatTo12Hour(arrival.arrivalTime) }}
+
+
+
+
{{ formatTo12Hour(arrival.arrivalTime) }}
-
No upcoming arrivals found.
+
schedule
+
Sin servicio disponible en este momento
+
Prueba más tarde o revisa el horario completo
@@ -128,11 +172,11 @@ watch(() => props.isOpen, async (isOpen) => {
@@ -237,13 +281,42 @@ watch(() => props.isOpen, async (isOpen) => {
padding: 4px;
}
+.arrivals-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 12px;
+}
+
.section-title {
font-size: 1rem;
font-weight: 600;
- margin-bottom: 12px;
+ margin: 0;
color: var(--text-primary);
}
+.gps-badge {
+ display: flex;
+ align-items: center;
+ gap: 4px;
+ font-size: 0.7rem;
+ font-weight: 700;
+ padding: 3px 8px;
+ border-radius: 12px;
+ text-transform: uppercase;
+ letter-spacing: 0.03em;
+}
+.gps-badge.gps-on {
+ background: rgba(34, 197, 94, 0.12);
+ color: #22c55e;
+ border: 1px solid rgba(34, 197, 94, 0.3);
+}
+.gps-badge.gps-off {
+ background: var(--bg-secondary);
+ color: var(--text-secondary);
+ border: 1px solid var(--border-color);
+}
+
.arrivals-list {
display: flex;
flex-direction: column;
@@ -263,19 +336,74 @@ watch(() => props.isOpen, async (isOpen) => {
display: flex;
align-items: center;
gap: 8px;
+ flex: 1;
+ min-width: 0;
+}
+
+.route-texts {
+ display: flex;
+ flex-direction: column;
+ gap: 1px;
+ min-width: 0;
}
.bus-icon {
color: var(--header-bg);
+ flex-shrink: 0;
}
.route-name {
- font-weight: 500;
+ font-weight: 600;
+ font-size: 0.875rem;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
}
+.departure-hint {
+ font-size: 0.72rem;
+ color: var(--text-secondary);
+}
+
+/* Raw time (no GPS) */
.arrival-time {
font-weight: 700;
+ font-size: 0.95rem;
color: var(--active-color, green);
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+/* GPS mode: wait badge + clock */
+.arrival-time-block {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+ gap: 2px;
+ flex-shrink: 0;
+}
+
+.wait-badge {
+ font-size: 0.8rem;
+ font-weight: 800;
+ padding: 2px 8px;
+ border-radius: 10px;
+ white-space: nowrap;
+}
+.wait-badge.urgent {
+ background: rgba(239, 68, 68, 0.12);
+ color: #ef4444;
+ border: 1px solid rgba(239, 68, 68, 0.3);
+}
+.wait-badge.normal {
+ background: rgba(34, 197, 94, 0.12);
+ color: #22c55e;
+ border: 1px solid rgba(34, 197, 94, 0.25);
+}
+
+.arrival-clock {
+ font-size: 0.72rem;
+ color: var(--text-secondary);
}
/* Amenities Styles */
@@ -393,4 +521,33 @@ watch(() => props.isOpen, async (isOpen) => {
}
@keyframes spin { 100% { transform: rotate(360deg); } }
+
+.empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 8px;
+ padding: 24px 16px;
+ text-align: center;
+ color: var(--text-secondary);
+}
+
+.empty-state .material-icons {
+ font-size: 2.5rem;
+ opacity: 0.4;
+}
+
+.empty-state p {
+ margin: 0;
+ font-size: 0.9rem;
+ font-weight: 500;
+ color: var(--text-primary);
+}
+
+.empty-hint {
+ font-size: 0.78rem;
+ color: var(--text-secondary);
+ opacity: 0.75;
+}
+
diff --git a/frontend/src/services/busStopsService.ts b/frontend/src/services/busStopsService.ts
index 0bbf679..01ac746 100644
--- a/frontend/src/services/busStopsService.ts
+++ b/frontend/src/services/busStopsService.ts
@@ -2,6 +2,41 @@
import { supabase } from '@/supabase'
import type { BusStop, Route } from '@/types'
+// Map JS getDay() (0=Sun,6=Sat) to Spanish day names used in dias_operacion
+const DAY_MAP: Record