diff --git a/src/components/StationTimeTableRow.tsx b/src/components/StationTimeTableRow.tsx
index ca5c28f7..8aad0935 100644
--- a/src/components/StationTimeTableRow.tsx
+++ b/src/components/StationTimeTableRow.tsx
@@ -8,7 +8,7 @@ import {
TableCell,
TableRow,
} from '@mui/material';
-import { ChevronRight } from 'mdi-material-ui';
+import { Airplane, ChevronRight } from 'mdi-material-ui';
import RouterLink from 'next/link';
import {
@@ -47,7 +47,7 @@ function StationTimeTableRow({
: train.trainType.name + train.trainNumber;
const deptOrDestStation =
timeTableType === TimeTableRowType.Departure
- ? getTrainDestinationStation(train)
+ ? getTrainDestinationStation(train, stationCode)
: getTrainDepartureStation(train);
const deptOrDestStationName = deptOrDestStation
? getTrainStationName(deptOrDestStation)
@@ -111,6 +111,9 @@ function StationTimeTableRow({
onClick={handleStationClick}
>
{deptOrDestStationName}
+ {deptOrDestStation?.shortCode === 'LEN' && (
+
+ )}
diff --git a/src/utils/__tests__/train.test.ts b/src/utils/__tests__/train.test.ts
index 70b7e7b8..60854e6c 100644
--- a/src/utils/__tests__/train.test.ts
+++ b/src/utils/__tests__/train.test.ts
@@ -106,6 +106,80 @@ const train: TrainDetailsFragment = {
],
};
+/**
+ * Ring rail (Kehärata) train HKI to HKI via LEN (airport)
+ */
+const ringRailTrainBase: TrainDetailsFragment = {
+ ...trainBase,
+ commuterLineid: 'I',
+ timeTableRows: [
+ {
+ ...departureTimeTableRowBase,
+ scheduledTime: '2023-01-25T08:55:00Z',
+ station: {
+ name: 'Helsinki',
+ shortCode: 'HKI',
+ },
+ },
+ {
+ ...arrivalTimeTableRowBase,
+ scheduledTime: '2023-01-25T09:00:00Z',
+ station: {
+ name: 'Pasila',
+ shortCode: 'PSL',
+ },
+ },
+ {
+ ...departureTimeTableRowBase,
+ scheduledTime: '2023-01-25T09:05:00Z',
+ station: {
+ name: 'Pasila',
+ shortCode: 'PSL',
+ },
+ },
+ {
+ ...arrivalTimeTableRowBase,
+ scheduledTime: '2023-01-25T11:00:00Z',
+ station: {
+ name: 'Lentoasema',
+ shortCode: 'LEN',
+ },
+ },
+ {
+ ...departureTimeTableRowBase,
+ scheduledTime: '2023-01-25T11:05:00Z',
+ station: {
+ name: 'Lentoasema',
+ shortCode: 'LEN',
+ },
+ },
+ {
+ ...arrivalTimeTableRowBase,
+ scheduledTime: '2023-01-25T11:30:00Z',
+ station: {
+ name: 'Pasila',
+ shortCode: 'PSL',
+ },
+ },
+ {
+ ...departureTimeTableRowBase,
+ scheduledTime: '2023-01-25T11:35:00Z',
+ station: {
+ name: 'Pasila',
+ shortCode: 'PSL',
+ },
+ },
+ {
+ ...arrivalTimeTableRowBase,
+ scheduledTime: '2023-01-25T11:40:00Z',
+ station: {
+ name: 'Helsinki',
+ shortCode: 'HKI',
+ },
+ },
+ ],
+};
+
describe('getTimeTableRowRealTime', () => {
it('should be the scheduled time of the row when neither actual time or live estimate time is defined', () => {
expect(
@@ -177,6 +251,50 @@ describe('getTrainDestinationStation', () => {
expect(station).toBeDefined();
expect(station!.name).toBe('Tampere');
});
+ describe.each(['I', 'P'])('ring rail %s train', (commuterLineid: string) => {
+ const ringRailTrain = {
+ ...ringRailTrainBase,
+ commuterLineid: commuterLineid,
+ };
+
+ beforeEach(() => {
+ jest.useFakeTimers();
+ });
+
+ afterEach(() => {
+ jest.useRealTimers();
+ });
+
+ it('should be the LEN (airport) station when the given station is earlier than LEN', () => {
+ jest.setSystemTime(parseISO('2023-01-25T08:55:00Z'));
+
+ const destStationAtHki = getTrainDestinationStation(ringRailTrain, 'HKI');
+ expect(destStationAtHki).toBeDefined();
+ expect(destStationAtHki!.name).toBe('Lentoasema');
+
+ const destStationAtPsl = getTrainDestinationStation(ringRailTrain, 'PSL');
+ expect(destStationAtPsl).toBeDefined();
+ expect(destStationAtPsl!.name).toBe('Lentoasema');
+ });
+
+ it('should be the station of the destination time table row when the given station is later than LEN', () => {
+ // Train is between section PSL - LEN based on current time and train schedule
+ // So train has already passed PSL (first time)
+ jest.setSystemTime(parseISO('2023-01-25T10:30:00Z'));
+
+ const destStationAtLen = getTrainDestinationStation(ringRailTrain, 'LEN');
+ expect(destStationAtLen).toBeDefined();
+ expect(destStationAtLen!.name).toBe('Helsinki');
+
+ const destStationAtPsl = getTrainDestinationStation(ringRailTrain, 'PSL');
+ expect(destStationAtPsl).toBeDefined();
+ expect(destStationAtPsl!.name).toBe('Helsinki');
+
+ const destStationAtHki = getTrainDestinationStation(ringRailTrain, 'HKI');
+ expect(destStationAtHki).toBeDefined();
+ expect(destStationAtHki!.name).toBe('Helsinki');
+ });
+ });
});
describe('getTrainDepartureStationName', () => {
diff --git a/src/utils/train.ts b/src/utils/train.ts
index a94a74d7..9f96e8ed 100644
--- a/src/utils/train.ts
+++ b/src/utils/train.ts
@@ -1,7 +1,12 @@
import { parseISO } from 'date-fns';
import { orderBy } from 'lodash';
-import { TrainByStationFragment } from '../graphql/generated/digitraffic';
+import {
+ TimeTableRowType,
+ TrainByStationFragment,
+} from '../graphql/generated/digitraffic';
+
+import getTimeTableRowForStation from './getTimeTableRowForStation';
export function getTimeTableRowRealTime(row: {
scheduledTime: string;
@@ -30,7 +35,37 @@ export function getTrainDepartureStation(train: TrainByStationFragment) {
return getDepartureTimeTableRow(train)?.station;
}
-export function getTrainDestinationStation(train: TrainByStationFragment) {
+export function getTrainDestinationStation(
+ train: TrainByStationFragment,
+ stationCode?: string
+) {
+ // Special handling for ring route (kehärata) trains:
+ // Return LEN (airport) as the destination station if
+ // the given station code is earlier on the train
+ // time table rows than the airport.
+ if (
+ stationCode &&
+ train.commuterLineid &&
+ ['I', 'P'].includes(train.commuterLineid)
+ ) {
+ const stationRow = getTimeTableRowForStation(
+ stationCode,
+ train,
+ TimeTableRowType.Departure
+ );
+ const airportArrivalRow = getTimeTableRowForStation(
+ 'LEN',
+ train,
+ TimeTableRowType.Arrival
+ );
+ if (
+ airportArrivalRow &&
+ stationRow &&
+ stationRow.scheduledTime < airportArrivalRow.scheduledTime
+ ) {
+ return airportArrivalRow.station;
+ }
+ }
return getDestinationTimeTableRow(train)?.station;
}
@@ -39,15 +74,18 @@ export function getTrainDepartureStationName(train: TrainByStationFragment) {
return departureStation ? getTrainStationName(departureStation) : undefined;
}
-export function getTrainDestinationStationName(train: TrainByStationFragment) {
- const destinationStation = getTrainDestinationStation(train);
+export function getTrainDestinationStationName(
+ train: TrainByStationFragment,
+ stationCode?: string
+) {
+ const destinationStation = getTrainDestinationStation(train, stationCode);
return destinationStation
? getTrainStationName(destinationStation)
: undefined;
}
export function getTrainStationName(station: { name: string }) {
- return station.name.replace('asema', '').trimEnd();
+ return station.name.replace(' asema', '').trimEnd();
}
export function getWagonNumberFromVehicleId(