Skip to content

Commit

Permalink
Merge branch 'main' into passenger-information-messages
Browse files Browse the repository at this point in the history
  • Loading branch information
viliket committed Sep 15, 2023
2 parents 5ddad3a + 6dc2cac commit a5b573d
Show file tree
Hide file tree
Showing 7 changed files with 192 additions and 31 deletions.
1 change: 1 addition & 0 deletions public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"no_results": "No results.",
"train": "Train",
"train_details": "Train details",
"from": "From",
"destination": "Destination",
"departure": "Departure",
"departures": "Departures",
Expand Down
1 change: 1 addition & 0 deletions public/locales/fi/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"no_results": "Ei tuloksia.",
"train": "Juna",
"train_details": "Junan tiedot",
"from": "Lähtöasema",
"destination": "Määränpää",
"departure": "Lähtee",
"departures": "Lähtevät",
Expand Down
8 changes: 6 additions & 2 deletions src/components/StationTimeTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type StationTimeTableProps = {
stationCode: string;
timeTableType: TimeTableRowType;
trains: TrainByStationFragment[];
tableRowOnClick: (trainNumber: number, scheduledTime: Date) => void;
tableRowOnClick: (trainNumber: number, departureDate: string) => void;
};

function StationTimeTable({
Expand Down Expand Up @@ -55,7 +55,11 @@ function StationTimeTable({
<TableHead>
<TableRow>
<TableCell>{t('train')}</TableCell>
<TableCell>{t('destination')}</TableCell>
<TableCell>
{timeTableType === TimeTableRowType.Departure
? t('destination')
: t('from')}
</TableCell>
<TableCell align="center">
{timeTableType === TimeTableRowType.Departure
? t('departure')
Expand Down
40 changes: 21 additions & 19 deletions src/components/StationTimeTableRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ 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 {
TimeTableRowType,
TrainByStationFragment,
} from '../graphql/generated/digitraffic';
import { formatEET } from '../utils/date';
import getTimeTableRowForStation from '../utils/getTimeTableRowForStation';
import {
getTrainDestinationStationName,
getTrainScheduledDepartureTime,
getTrainDepartureStation,
getTrainDestinationStation,
getTrainStationName,
} from '../utils/train';

import TimeTableRowTime from './TimeTableRowTime';
Expand All @@ -29,7 +29,7 @@ type StationTimeTableRowProps = {
train: TrainByStationFragment;
stationCode: string;
timeTableType: TimeTableRowType;
tableRowOnClick: (trainNumber: number, scheduledTime: Date) => void;
tableRowOnClick: (trainNumber: number, departureDate: string) => void;
};

function StationTimeTableRow({
Expand All @@ -41,11 +41,18 @@ function StationTimeTableRow({
const handleStationClick = (e: React.MouseEvent) => e.stopPropagation();

const trainNumber = train.trainNumber;
const departureDate = train.departureDate;
const trainName = train.commuterLineid
? train.commuterLineid
: train.trainType.name + train.trainNumber;
const destinationStationName = getTrainDestinationStationName(train);
const departureTime = getTrainScheduledDepartureTime(train);
const deptOrDestStation =
timeTableType === TimeTableRowType.Departure
? getTrainDestinationStation(train, stationCode)
: getTrainDepartureStation(train);
const deptOrDestStationName = deptOrDestStation
? getTrainStationName(deptOrDestStation)
: null;

const stationRow = getTimeTableRowForStation(
stationCode,
train,
Expand All @@ -59,11 +66,7 @@ function StationTimeTableRow({
sx={{
cursor: 'pointer',
}}
onClick={() => {
if (departureTime) {
tableRowOnClick(trainNumber, departureTime);
}
}}
onClick={() => tableRowOnClick(trainNumber, departureDate)}
>
<TableCell scope="row">
<span
Expand Down Expand Up @@ -94,24 +97,23 @@ function StationTimeTableRow({
{trainName}
<VehicleTrackingIcon
trainNumber={trainNumber}
departureDate={
departureTime
? formatEET(departureTime, 'yyyy-MM-dd')
: undefined
}
departureDate={departureDate}
/>
</Box>
</span>
</TableCell>
<TableCell>
<Link
component={RouterLink}
href={`/${destinationStationName}`}
href={`/${deptOrDestStationName}`}
color="inherit"
underline="none"
onClick={handleStationClick}
>
{destinationStationName}
{deptOrDestStationName}
{deptOrDestStation?.shortCode === 'LEN' && (
<Airplane sx={{ position: 'absolute', fontSize: '1.3rem' }} />
)}
</Link>
</TableCell>
<TableCell align="center">
Expand Down
7 changes: 2 additions & 5 deletions src/pages/[station].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,9 @@ const Station: NextPageWithLayout = () => {
}, []);

const handleTimeTableRowClick = useCallback(
(trainNumber: number, scheduledTime: Date) => {
(trainNumber: number, departureDate: string) => {
router.push(
`/train/${trainNumber}/${formatEET(
scheduledTime,
'yyyy-MM-dd'
)}?station=${stationCode}`
`/train/${trainNumber}/${departureDate}?station=${stationCode}`
);
},
[router, stationCode]
Expand Down
118 changes: 118 additions & 0 deletions src/utils/__tests__/train.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down Expand Up @@ -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', () => {
Expand Down
48 changes: 43 additions & 5 deletions src/utils/train.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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(
Expand Down

0 comments on commit a5b573d

Please sign in to comment.