Skip to content

Commit

Permalink
Merge pull request #397 from HSLdevcom/AB#32085_line_timetable
Browse files Browse the repository at this point in the history
AB#32085: weekly line timetable
  • Loading branch information
jhanninen authored Mar 22, 2024
2 parents 1bdc2b9 + eb5b081 commit 91be8f2
Show file tree
Hide file tree
Showing 15 changed files with 857 additions and 23 deletions.
7 changes: 5 additions & 2 deletions scripts/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,11 @@ const cancelSignalRedis = new Redis(REDIS_CONNECTION_STRING);
async function generatePoster(buildId, component, props, index) {
const { stopId, date, template, selectedRuleTemplates } = props;

// RuleTemplates are not available for TerminalPoster
const data = component !== 'TerminalPoster' ? await getStopInfo({ stopId, date }) : null;
// RuleTemplates are not available for TerminalPoster and LineTimetable
const data =
component !== 'TerminalPoster' && component !== 'LineTimetable'
? await getStopInfo({ stopId, date })
: null;

// Checks if any rule template will match the stop, and returns *the first one*.
// If no match, returns the default template.
Expand Down
2 changes: 2 additions & 0 deletions src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import StopPoster from 'components/stopPoster/stopPosterContainer';
import Timetable from 'components/timetable/timetableContainer';
import A3StopPoster from 'components/a3stopPoster/a3StopPosterContainer';
import TerminalPoster from 'components/stopPoster/terminalPosterContainer';
import LineTimetable from 'components/lineTimetable/lineTimetableContainer';
import renderQueue from 'util/renderQueue';

const components = {
StopPoster,
Timetable,
A3StopPoster,
TerminalPoster,
LineTimetable,
};

const graphqlUrl = process.env.JORE_GRAPHQL_URL || 'https://kartat.hsl.fi/jore/graphql';
Expand Down
26 changes: 26 additions & 0 deletions src/components/lineTimetable/allStopsList.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
.stopListsContainer {
margin-top: 2rem;
max-width: 1171px;
}

.stopList {
margin-bottom: 2rem;
padding-left: 1.2rem;
}

.lineInfoText {
font-family: GothamRounded-Medium;
font-weight: bold;
font-size: 2rem;
}

.stopListText {
font-size: medium;
font-family: GothamRounded-Book;
}

@media print {
.stopListsContainer {
page-break-inside: avoid;
}
}
71 changes: 71 additions & 0 deletions src/components/lineTimetable/allStopsList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './allStopsList.css';

const TEXT_LANG = {
FI: 'fi',
SE: 'se',
};

const getLineInfoText = (lang, lineId) => {
let infoText = null;
switch (lang) {
case TEXT_LANG.FI:
infoText = `Linjan ${lineId} pysäkit:`;
break;

case TEXT_LANG.SE:
infoText = `Hållplatser for linje ${lineId}:`;
break;

default:
infoText = '';
}

return infoText;
};

const parseStopNames = stops => {
return {
namesFi: stops.map(item => {
return item.stop.nameFi;
}),
namesSe: stops.map(item => {
return item.stop.nameSe;
}),
};
};

const StopList = props => {
const { stops, lang, lineId } = props;
return (
<div className={styles.stopList}>
<p className={styles.lineInfoText}>{getLineInfoText(lang, lineId)}</p>
<p className={styles.stopListText}>{stops.join(' - ')}</p>
</div>
);
};

StopList.propTypes = {
stops: PropTypes.array.isRequired,
lang: PropTypes.string.isRequired,
lineId: PropTypes.string.isRequired,
};

const AllStopsList = props => {
const { stops, lineId } = props;
const parsedStopLists = parseStopNames(stops);
return (
<div className={styles.stopListsContainer}>
<StopList stops={parsedStopLists.namesFi} lang={TEXT_LANG.FI} lineId={lineId} />
<StopList stops={parsedStopLists.namesSe} lang={TEXT_LANG.SE} lineId={lineId} />
</div>
);
};

AllStopsList.propTypes = {
stops: PropTypes.array.isRequired,
lineId: PropTypes.string.isRequired,
};

export default AllStopsList;
31 changes: 31 additions & 0 deletions src/components/lineTimetable/lineTableColumns.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.departureRowContainer {
max-width: 1171px;
font-family: GothamRounded-Medium;
}

.departureRowContainer > *:nth-child(odd) {
background-color: #e8e8e8;
}

.departureRow {
font-size: 1.2rem;
margin-left: 2rem;
padding-top: 5px;
padding-bottom: 5px;
}

.departureColumnContainer {
flex-grow: 1;
align-items: normal;
}

.tableContainer {
display: flex;
margin-top: 1rem;
}

@media print {
.departureRow {
page-break-inside: avoid;
}
}
92 changes: 92 additions & 0 deletions src/components/lineTimetable/lineTableColumns.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import React from 'react';
import PropTypes from 'prop-types';
import { combineConsecutiveDays } from '../timetable/timetableContainer';
import { Column, Row, WrappingRow } from '../util';
import LineTableHeader from './lineTableHeader';
import styles from './lineTableColumns.css';

const LineTimetableRow = props => {
const { hours, minutes } = props;
const paddedMins = minutes.toString().padStart(2, '0');
return (
<WrappingRow>
<Row className={styles.departureRow}>
{hours}.{paddedMins}
</Row>
</WrappingRow>
);
};

LineTimetableRow.propTypes = {
hours: PropTypes.number.isRequired,
minutes: PropTypes.number.isRequired,
};

const DeparturesColumn = props => {
const { departures, stop } = props;
const departureRows = departures.map(departure => (
<LineTimetableRow hours={departure.hours} minutes={departure.minutes} />
));

return (
<div>
<LineTableHeader stop={stop} />
<div className={styles.departureRowContainer}>{departureRows}</div>
</div>
);
};

DeparturesColumn.propTypes = {
departures: PropTypes.array.isRequired,
stop: PropTypes.object.isRequired,
};

const LineTableColumns = props => {
const selectedDepartureDays = props.days;

const mapWeekdayDepartures = props.departures.map(departuresForStop => {
const {
mondays,
tuesdays,
wednesdays,
thursdays,
fridays,
saturdays,
sundays,
} = departuresForStop.departures;

return {
stop: departuresForStop.stop,
combinedDays: combineConsecutiveDays({
mondays,
tuesdays,
wednesdays,
thursdays,
fridays,
saturdays,
sundays,
}),
};
});

const departureColums = mapWeekdayDepartures.map(departures => {
return (
<Column className={styles.departureColumnContainer}>
<DeparturesColumn
departures={departures.combinedDays[selectedDepartureDays]}
stop={departures.stop}
/>
</Column>
);
});

return <div className={styles.tableContainer}>{departureColums}</div>;
};

LineTableColumns.propTypes = {
departures: PropTypes.arrayOf(PropTypes.any).isRequired,
stopSequence: PropTypes.arrayOf(PropTypes.string).isRequired,
days: PropTypes.string.isRequired,
};

export default LineTableColumns;
9 changes: 9 additions & 0 deletions src/components/lineTimetable/lineTableHeader.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.stop {
flex-grow: 1;
}

.stopName {
font-size: 1.2em;
margin: 0 0 0 2rem;
font-family: GothamRounded-Medium;
}
21 changes: 21 additions & 0 deletions src/components/lineTimetable/lineTableHeader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import styles from './lineTableHeader.css';

const LineTableHeader = props => {
const { stop } = props;
return (
<div className={styles.stop}>
<p className={styles.stopName}>{stop.nameFi}</p>
<p className={styles.stopName}>{stop.nameSe}</p>
</div>
);
};

LineTableHeader.propTypes = {
stop: PropTypes.object.isRequired,
};

export default LineTableHeader;
Loading

0 comments on commit 91be8f2

Please sign in to comment.