Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AB#32085: weekly line timetable #397

Merged
merged 6 commits into from
Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -11,13 +11,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
Loading