From 093ee906eae5361bbf47ae2fdc4003f95696656a Mon Sep 17 00:00:00 2001 From: Ariel Costas Guerrero Date: Thu, 6 Nov 2025 15:44:58 +0100 Subject: Rename schedules table --- src/frontend/app/components/SchedulesTable.tsx | 167 +++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 src/frontend/app/components/SchedulesTable.tsx (limited to 'src/frontend/app/components/SchedulesTable.tsx') diff --git a/src/frontend/app/components/SchedulesTable.tsx b/src/frontend/app/components/SchedulesTable.tsx new file mode 100644 index 0000000..afa6f8e --- /dev/null +++ b/src/frontend/app/components/SchedulesTable.tsx @@ -0,0 +1,167 @@ +import { useTranslation } from "react-i18next"; +import LineIcon from "./LineIcon"; +import "./SchedulesTable.css"; +import { useApp } from "~/AppContext"; + +export interface ScheduledTable { + line: { + name: string; + colour: string; + }; + trip: { + id: string; + service_id: string; + headsign: string; + direction_id: number; + }; + route_id: string; + departure_time: string; + arrival_time: string; + stop_sequence: number; + shape_dist_traveled: number; + next_streets: string[]; +} + +interface TimetableTableProps { + data: ScheduledTable[]; + showAll?: boolean; + currentTime?: string; // HH:MM:SS format +} + +// Utility function to parse service ID and get the turn number +const parseServiceId = (serviceId: string): string => { + const parts = serviceId.split('_'); + if (parts.length === 0) return ''; + + const lastPart = parts[parts.length - 1]; + if (lastPart.length < 6) return ''; + + const last6 = lastPart.slice(-6); + const lineCode = last6.slice(0, 3); + const turnCode = last6.slice(-3); + + // Remove leading zeros from turn + const turnNumber = parseInt(turnCode, 10).toString(); + + // Parse line number with special cases + const lineNumber = parseInt(lineCode, 10); + let displayLine: string; + + switch (lineNumber) { + case 1: displayLine = "C1"; break; + case 3: displayLine = "C3"; break; + case 30: displayLine = "N1"; break; + case 33: displayLine = "N4"; break; + case 8: displayLine = "A"; break; + case 101: displayLine = "H"; break; + case 150: displayLine = "REF"; break; + case 500: displayLine = "TUR"; break; + default: displayLine = `L${lineNumber}`; + } + + return `${displayLine}-${turnNumber}`; +}; + +// Utility function to compare times +const timeToMinutes = (time: string): number => { + const [hours, minutes] = time.split(':').map(Number); + return hours * 60 + minutes; +}; + +// Utility function to find nearby entries +const findNearbyEntries = (entries: ScheduledTable[], currentTime: string, before: number = 4, after: number = 4): ScheduledTable[] => { + if (!currentTime) return entries.slice(0, before + after); + + const currentMinutes = timeToMinutes(currentTime); + const sortedEntries = [...entries].sort((a, b) => + timeToMinutes(a.departure_time) - timeToMinutes(b.departure_time) + ); + + let currentIndex = sortedEntries.findIndex(entry => + timeToMinutes(entry.departure_time) >= currentMinutes + ); + + if (currentIndex === -1) { + // All entries are before current time, show last ones + return sortedEntries.slice(-before - after); + } + + const startIndex = Math.max(0, currentIndex - before); + const endIndex = Math.min(sortedEntries.length, currentIndex + after); + + return sortedEntries.slice(startIndex, endIndex); +}; + +export const SchedulesTable: React.FC = ({ + data, + showAll = false, + currentTime +}) => { + const { t } = useTranslation(); + const { region } = useApp(); + + const displayData = showAll ? data : findNearbyEntries(data, currentTime || ''); + const nowMinutes = currentTime ? timeToMinutes(currentTime) : timeToMinutes(new Date().toTimeString().slice(0, 8)); + + return ( +
+
+ {showAll + ? t("timetable.fullCaption", "Horarios teóricos de la parada") + : t("timetable.nearbyCaption", "Próximos horarios teóricos") + } +
+ +
+ {displayData.map((entry, index) => { + const entryMinutes = timeToMinutes(entry.departure_time); + const isPast = entryMinutes < nowMinutes; + return ( +
+
+
+ +
+ +
+ {entry.trip.headsign && entry.trip.headsign.trim() ? ( + {entry.trip.headsign} + ) : ( + {t("timetable.noDestination", "Línea")} {entry.line.name} + )} +
+ +
+ + {entry.departure_time.slice(0, 5)} + +
+
+
+
+ + {parseServiceId(entry.trip.service_id)} + + {entry.next_streets.length > 0 && ( + — {entry.next_streets.join(' — ')} + )} +
+
+
+ ); + })} +
+ {displayData.length === 0 && ( +

{t("timetable.noData", "No hay datos de horarios disponibles")}

+ )} +
+ ); +}; -- cgit v1.3