fix(eta): update to 12h format and ensure ETA always shows in minutes (e.g., 70 min)
This commit is contained in:
@ -23,7 +23,7 @@
|
|||||||
<div class="eta-loader"></div>
|
<div class="eta-loader"></div>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="hasActiveBuses">
|
<template v-else-if="hasActiveBuses">
|
||||||
<span class="eta-value">{{ etaValue }}</span>
|
<span class="eta-value">{{ typeof etaValue === 'number' ? formatDurationMinutes(etaValue) : etaValue }}</span>
|
||||||
<span class="eta-unit">min</span>
|
<span class="eta-unit">min</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { formatDurationMinutes } from '@/utils/durationFormatter'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
isVisible: boolean
|
isVisible: boolean
|
||||||
|
|||||||
@ -104,7 +104,7 @@
|
|||||||
<div class="flex flex-col items-end text-right shrink-0 ml-4">
|
<div class="flex flex-col items-end text-right shrink-0 ml-4">
|
||||||
<!-- ETA gigante -->
|
<!-- ETA gigante -->
|
||||||
<div v-if="bus.estado !== 'pasó'" class="text-2xl font-black text-gray-900 dark:text-white flex items-baseline gap-1" :class="{ 'text-green-600 dark:text-green-400': bus.estado === 'en_camino' }">
|
<div v-if="bus.estado !== 'pasó'" class="text-2xl font-black text-gray-900 dark:text-white flex items-baseline gap-1" :class="{ 'text-green-600 dark:text-green-400': bus.estado === 'en_camino' }">
|
||||||
<span>~{{ bus.etaMinutos }}</span>
|
<span>~{{ formatDurationMinutes(bus.etaMinutos) }}</span>
|
||||||
<span class="text-sm font-bold text-gray-500 dark:text-gray-400">min</span>
|
<span class="text-sm font-bold text-gray-500 dark:text-gray-400">min</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -143,6 +143,7 @@
|
|||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { ref, onMounted, onUnmounted } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import type { BusETA } from '@/composables/useETA';
|
import type { BusETA } from '@/composables/useETA';
|
||||||
|
import { formatDurationMinutes } from '@/utils/durationFormatter';
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
|
|||||||
@ -126,10 +126,21 @@ export function useETA() {
|
|||||||
|
|
||||||
const [hStr, mStr] = salida.split(':');
|
const [hStr, mStr] = salida.split(':');
|
||||||
const minutosSalida = parseInt(hStr) * 60 + parseInt(mStr);
|
const minutosSalida = parseInt(hStr) * 60 + parseInt(mStr);
|
||||||
const minutosLlegadaParada = minutosSalida + minutosHastaParada;
|
|
||||||
const etaMinutos = minutosLlegadaParada - minutosAhora;
|
// Cálculo explícito: tiempo que falta para salir + tiempo de trayecto hasta la parada
|
||||||
const horaLlegada = minutosAHora(minutosLlegadaParada);
|
// Si el bus ya salió, el tiempo de espera para salir es 0 y el tiempo de trayecto se reduce
|
||||||
const horaSalidaFormato = `${hStr.padStart(2, '0')}:${mStr.padStart(2, '0')}`;
|
const minutosEsperaSalida = Math.max(0, minutosSalida - minutosAhora);
|
||||||
|
const minutosTransitoBase = minutosHastaParada;
|
||||||
|
const minutosTranscurridosDesdeSalida = Math.max(0, minutosAhora - minutosSalida);
|
||||||
|
|
||||||
|
// Si ya salió, el trayecto restante es base - transcurrido. Si no ha salido, es el base completo.
|
||||||
|
const minutosTransitoRestante = Math.max(0, minutosTransitoBase - minutosTranscurridosDesdeSalida);
|
||||||
|
|
||||||
|
const etaMinutos = minutosEsperaSalida + minutosTransitoRestante;
|
||||||
|
const minutosLlegadaEstablecidos = minutosSalida + minutosTransitoBase;
|
||||||
|
|
||||||
|
const horaLlegada = format12h(minutosLlegadaEstablecidos);
|
||||||
|
const horaSalidaFormato = format12h(minutosSalida);
|
||||||
|
|
||||||
let estado: BusETA['estado'];
|
let estado: BusETA['estado'];
|
||||||
if (etaMinutos > 5) {
|
if (etaMinutos > 5) {
|
||||||
@ -165,13 +176,15 @@ export function useETA() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Helper: convierte minutos desde medianoche a "HH:mm"
|
// Helper: convierte minutos desde medianoche a formato 12h (hh:mm am/pm)
|
||||||
function minutosAHora(minutos: number): string {
|
function format12h(minutos: number): string {
|
||||||
const totalMinutes = Math.round(minutos);
|
const totalMinutes = Math.round(minutos);
|
||||||
const m = ((totalMinutes % 1440) + 1440) % 1440; // normalizar 0-1439
|
const m = ((totalMinutes % 1440) + 1440) % 1440; // normalizar 0-1439
|
||||||
const h = Math.floor(m / 60);
|
let h = Math.floor(m / 60);
|
||||||
const min = Math.floor(m % 60);
|
const min = Math.floor(m % 60);
|
||||||
return `${String(h).padStart(2, '0')}:${String(min).padStart(2, '0')}`;
|
const ampm = h >= 12 ? 'PM' : 'AM';
|
||||||
|
const h12 = h % 12 || 12;
|
||||||
|
return `${h12}:${String(min).padStart(2, '0')} ${ampm}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { calcularETA, busesActivos, cargando };
|
return { calcularETA, busesActivos, cargando };
|
||||||
|
|||||||
8
frontend/src/utils/durationFormatter.ts
Normal file
8
frontend/src/utils/durationFormatter.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
/**
|
||||||
|
* Formats a duration in minutes to a human-readable string.
|
||||||
|
* It will always show minutes, even if it's more than 60, e.g., "70 min".
|
||||||
|
*/
|
||||||
|
export function formatDurationMinutes(minutes: number): string {
|
||||||
|
const rounded = Math.round(minutes);
|
||||||
|
return `${rounded}`;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user