diff --git a/.dockerignore b/.dockerignore index 77da024..dfc6c22 100644 --- a/.dockerignore +++ b/.dockerignore @@ -32,6 +32,9 @@ AGENTS.md scripts/private/ scripts/*.local.* +# Private timetable note +transit_api/LOCAL_BUS_TIMETABLE_README.md + # Local files *.local .local diff --git a/.gitignore b/.gitignore index 6f40b5d..6e131c8 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,9 @@ scripts/private/ scripts/*.local.* scripts/.env +# Private timetable note +transit_api/LOCAL_BUS_TIMETABLE_README.md + # Runtime files *.log *.sqlite3 diff --git a/transit_api/.dockerignore b/transit_api/.dockerignore index bd82a2d..a869fca 100644 --- a/transit_api/.dockerignore +++ b/transit_api/.dockerignore @@ -41,3 +41,6 @@ build/ dist/ coverage/ .nyc_output/ + +# Private timetable note +LOCAL_BUS_TIMETABLE_README.md diff --git a/transit_api/.gitignore b/transit_api/.gitignore index a27c873..6cc5ddc 100644 --- a/transit_api/.gitignore +++ b/transit_api/.gitignore @@ -47,4 +47,7 @@ credentials.json # Temporary tmp/ -temp/ \ No newline at end of file +temp/ + +# Private timetable note +LOCAL_BUS_TIMETABLE_README.md \ No newline at end of file diff --git a/transit_api/index.js b/transit_api/index.js index 660541f..531a56b 100644 --- a/transit_api/index.js +++ b/transit_api/index.js @@ -1498,20 +1498,67 @@ app.get('/admin/schedules', authMiddleware, adminMiddleware, async (req, res) => LEFT JOIN workers.employees e ON s.driver_id = e.id ORDER BY s.start_time DESC`); + const lineIds = Array.from( + new Set( + result.rows + .map(row => Number(row.bus_line_id)) + .filter(Number.isFinite) + ) + ); + + const routeStopsByLine = new Map(); + if (lineIds.length > 0) { + const routeStopsResult = await db.query(` + SELECT + rs.bus_line_id, + rs.stop_id, + rs.stop_order, + rs.estimated_arrival_minutes, + s.name AS stop_name + FROM transit.route_stops rs + JOIN transit.stops s ON s.id = rs.stop_id + WHERE rs.bus_line_id = ANY($1::int[]) + ORDER BY rs.bus_line_id ASC, rs.stop_order ASC + `, [lineIds]); + + for (const row of routeStopsResult.rows) { + const busLineId = Number(row.bus_line_id); + if (!routeStopsByLine.has(busLineId)) { + routeStopsByLine.set(busLineId, []); + } + routeStopsByLine.get(busLineId).push(row); + } + } + const schedules = result.rows.map(row => { - const departureTimes = calculateDepartureTimes(row.start_time, row.bus_line_id, _mock); - const weekdays = parseWeekdaysValue(row.weekdays); - + const busLineId = Number(row.bus_line_id); + const lineRouteStops = routeStopsByLine.get(busLineId) || []; + const startDate = new Date(row.start_time); + + const departureTimes = lineRouteStops.map(routeStop => { + const departureDate = new Date(startDate); + const etaMinutes = Number(routeStop.estimated_arrival_minutes) || 0; + departureDate.setMinutes(departureDate.getMinutes() + etaMinutes); + + return { + order: Number(routeStop.stop_order), + stopId: Number(routeStop.stop_id), + stopName: routeStop.stop_name || 'Unknown Stop', + estimatedArrivalMinutes: etaMinutes, + departureTime: departureDate.toISOString(), + }; + }); + return { id: Number(row.id), - busLineId: Number(row.bus_line_id), + busLineId, busId: Number(row.bus_id), driverId: row.driver_id !== null && row.driver_id !== undefined ? Number(row.driver_id) : null, driverName: row.driver_name || null, startTime: row.start_time, endTime: row.end_time, - weekdays: weekdays, + weekdays, departureTimes, status: row.status, lineNumber: row.line_number,