From 49e3b540644537745f9f6a06b8bf236f644dff78 Mon Sep 17 00:00:00 2001 From: Jono Cooper Date: Fri, 10 Apr 2020 10:30:11 +1200 Subject: [PATCH] Refactor Timetable Component --- js/views/lines/Line.jsx | 247 +++++------------- js/views/lines/LineErrorBoundary.jsx | 49 ++++ js/views/lines/Timetable.jsx | 189 -------------- js/views/lines/stops/LineStops.jsx | 38 +-- js/views/lines/timetable/LineTimetable.jsx | 160 ++++++++++++ .../lines/timetable/LineTimetableSelector.jsx | 178 +++++++++++++ js/views/station/Station.jsx | 2 +- stories/timetable.stories.jsx | 22 +- 8 files changed, 486 insertions(+), 399 deletions(-) create mode 100644 js/views/lines/LineErrorBoundary.jsx delete mode 100644 js/views/lines/Timetable.jsx create mode 100644 js/views/lines/timetable/LineTimetable.jsx create mode 100644 js/views/lines/timetable/LineTimetableSelector.jsx diff --git a/js/views/lines/Line.jsx b/js/views/lines/Line.jsx index 0e601a92..9d7ee402 100644 --- a/js/views/lines/Line.jsx +++ b/js/views/lines/Line.jsx @@ -1,12 +1,11 @@ import React from 'react' import PropTypes from 'prop-types' -import { View, Text, StyleSheet } from 'react-native' +import { View, StyleSheet } from 'react-native' import leaflet from 'leaflet' import { withRouter } from 'react-router' import queryString from 'query-string' import { vars } from '../../styles.js' -import SettingsStore from '../../stores/SettingsStore.js' import UiStore from '../../stores/UiStore.js' import Header from '../reusable/Header.jsx' import LinkedScroll from '../reusable/LinkedScroll.jsx' @@ -14,8 +13,9 @@ import LinkedScroll from '../reusable/LinkedScroll.jsx' import Layer from '../maps/Layer.jsx' import LineData from '../../data/LineData.js' import { LineStops } from './stops/LineStops.jsx' +import { LineTimetable } from './timetable/LineTimetable.jsx' +import { LineErrorBoundary } from './LineErrorBoundary.jsx' import IconHelper from '../../helpers/icons/index.js' -import Timetable from './Timetable.jsx' import TripInfo from './TripInfo.jsx' import LineIcon from '../../../dist/icons/linepicker.svg' @@ -96,7 +96,6 @@ class Line extends React.Component { this.state = { lineMetadata: [], - timetable: [], realtimeStopUpdates: {}, currentTrip: parsed.trip_id || null, vehiclepos: [], @@ -114,7 +113,6 @@ class Line extends React.Component { componentDidMount() { this.dataResolved = this.getData() - this.getTimetable() this.getPositionData() this.liveRefresh = setInterval(() => { @@ -132,135 +130,30 @@ class Line extends React.Component { } async getData() { - try { - const metadata = await this.lineData.getMeta() - - if (metadata.length === 0) { - throw new Error('The line was not found.') - } - - const route = - metadata.find(i => i.direction_id === this.lineData.direction_id) || - metadata[0] - this.lineData.direction_id = route.direction_id - - this.setState({ - lineMetadata: metadata, - }) + const metadata = await this.lineData.getMeta() - // if the stop wasn't specified in the URL - if (this.lineData.stop_id === null) { - this.lineData.stop_id = route.first_stop_id - this.getTimetable() - } - } catch (err) { + if (metadata.length === 0) { clearInterval(this.liveRefresh) - console.error(err) this.setState({ error: true, - errorMessage: err.message, + errorMessage: 'The line was not found.', }) + return } - } - getTimetable = async () => { - // this will be invoked again properly - if (this.lineData.stop_id === null) return - - const getTimetableState = rawData => { - const tolerance = 1000 * 60 * 30 - const visibleTolerance = 1000 * 60 * 2 - const realtimeTolerance = 1000 * 60 * 90 - const now = new Date(new Date().getTime() - tolerance) - const visibleNow = new Date(new Date().getTime() - visibleTolerance) - const realtimeNow = new Date(new Date().getTime() + realtimeTolerance) - const newState = { - timetable: rawData - .filter(service => { - return now < new Date(service.departure_time) - }) - .sort( - (a, b) => new Date(a.departure_time) > new Date(b.departure_time) - ) - .map(service => { - service.visible = visibleNow < new Date(service.departure_time) - service.realtimeQuery = - new Date(service.departure_time) < realtimeNow - return service - }), - } - if (this.state.currentTrip !== null) { - newState.currentTrip = this.state.currentTrip - } else if (newState.timetable.length > 0) { - const selectedTrip = newState.timetable.find(a => a.visible === true) - if (selectedTrip) { - newState.currentTrip = selectedTrip.trip_id - } - } - return newState - } - try { - const timetableData = await this.lineData.getTimetable(0) - this.setState(getTimetableState(timetableData), async () => { - const { timetable } = this.state - - this.lineData.realtime_trips = timetable - .filter(t => t.realtimeQuery === true) - .map(t => t.trip_id) - - this.getRealtimeStopUpdate() - - const tomorrowTimetableData = await this.lineData.getTimetable(1) - const newState = getTimetableState( - timetable.slice().concat(tomorrowTimetableData) - ) - this.lineData.realtime_trips = newState.timetable - .filter(t => t.realtimeQuery === true) - .map(t => t.trip_id) - - this.setState(newState, () => { - if (newState.timetable.length === 0) { - // timetable is empty, so best guess - const { lineMetadata } = this.state - - // if there's no metadata, try get it - if (lineMetadata.length === 0) { - this.lineData.stop_id = null - this.getData() - } else { - const secondAttempt = - lineMetadata.find( - i => i.direction_id === this.lineData.direction_id - ) || lineMetadata[0] - this.lineData.direction_id = secondAttempt.direction_id - - if ( - this.lineData.stop_id === secondAttempt.first_stop_id && - this.lineData.direction_id === secondAttempt.direction_id - ) { - // already attempted this, so give up - this.setState({ - error: true, - errorMessage: - 'We didn’t find any services for this line within the next few days.', - }) - } else { - this.lineData.direction_id = secondAttempt.direction_id - this.lineData.stop_id = secondAttempt.first_stop_id - this.getTimetable() - } - } - } - }) - }) - } catch (err) { - // cannot get timetable, usually because the stop_id is undefined - console.error(err) - this.setState({ - error: true, - errorMessage: err.message, - }) + const route = + metadata.find(i => i.direction_id === this.lineData.direction_id) || + metadata[0] + this.lineData.direction_id = route.direction_id + + // if the stop wasn't specified in the URL + if (this.lineData.stop_id === null) { + this.lineData.stop_id = route.first_stop_id } + + this.setState({ + lineMetadata: metadata, + }) } getPositionData = async () => { @@ -289,6 +182,7 @@ class Line extends React.Component { // this makes sure the route data has been loaded. await this.dataResolved const { lineMetadata } = this.state + if (lineMetadata.length === 0) return 'cancelled' // this if it the line can't loa const icon = icons.get( this.iconHelper.getRouteType(lineMetadata[0].route_type) ) @@ -309,6 +203,14 @@ class Line extends React.Component { this.setState({ realtimeStopUpdates }) } + setRealtimeTrips = (trips, triggerUpdate) => { + this.lineData.realtime_trips = trips + .filter(t => t.realtimeQuery === true) + .map(t => t.trip_id) + + if (triggerUpdate) this.getRealtimeStopUpdate() + } + triggerTrip = tripId => { return () => { this.setState({ @@ -328,11 +230,11 @@ class Line extends React.Component { error, errorMessage, lineMetadata, - timetable, currentTrip, realtimeStopUpdates, vehiclepos, } = this.state + const currentLine = lineMetadata.length > 0 ? lineMetadata.length === 1 @@ -342,55 +244,45 @@ class Line extends React.Component { ) : {} - if (error) { - return ( - -
- - - Sorry! We couldn't load the {match.params.route_short_name}{' '} - line. - - {errorMessage} - - - ) - } - - const tripInfo = vehiclepos.find(pos => pos.trip_id === currentTrip) - const timetableElement = - timetable.length > 0 ? ( - - ) : null - return ( -
} - actionFn={this.triggerPicker} - /> - - {timetableElement} - {window.location.hostname === 'localhost' ? ( - - ) : null} - +
} + actionFn={this.triggerPicker} /> - + + + {window.location.hostname === 'localhost' ? ( + pos.trip_id === currentTrip)} + /> + ) : null} + + + ) } @@ -429,14 +321,5 @@ styles = StyleSheet.create({ fontSize: 13, color: '#888', }, - - error: { - padding: vars.padding, - }, - errorMessage: { - fontSize: vars.defaultFontSize, - fontFamily: vars.fontFamily, - marginBottom: vars.padding, - }, }) export default withRouter(Line) diff --git a/js/views/lines/LineErrorBoundary.jsx b/js/views/lines/LineErrorBoundary.jsx new file mode 100644 index 00000000..5a1b6b7f --- /dev/null +++ b/js/views/lines/LineErrorBoundary.jsx @@ -0,0 +1,49 @@ +import React, { Component } from 'react' +import { View, Text, StyleSheet } from 'react-native' + +import { t } from '../../stores/translationStore.js' +import { vars, paragraphStyles } from '../../styles.js' +import Header from '../reusable/Header.jsx' + +let styles + +export class LineErrorBoundary extends Component { + constructor(props) { + super(props) + this.state = { hasError: false } + } + + static getDerivedStateFromError(err) { + return { hasError: true, message: err.message } + } + + render() { + const { line, forceError, errorMessage } = this.props + const { hasError, message } = this.state + if (hasError || forceError) { + // You can render any custom fallback UI + return ( + <> +
+ + + Sorry! We couldn't load the {line} line. + + + {errorMessage || message} + + + + ) + } + + const { children } = this.props + return children + } +} + +const { padding } = vars +styles = StyleSheet.create({ + error: { padding }, + bold: { fontWeight: '600' }, +}) diff --git a/js/views/lines/Timetable.jsx b/js/views/lines/Timetable.jsx deleted file mode 100644 index 3921f3b5..00000000 --- a/js/views/lines/Timetable.jsx +++ /dev/null @@ -1,189 +0,0 @@ -import React, { Fragment } from 'react' -import PropTypes from 'prop-types' - -import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' -import { vars } from '../../styles.js' - -import { getTime } from '../../helpers/date.js' - -const formatDate = (dateString, delay, isTwentyFourHour, region) => { - const date = new Date(dateString) - date.setTime(date.getTime() + delay * 1000) - const humanTime = getTime(date, isTwentyFourHour, true, region) - - // make this nicer - return `${humanTime.text || ''}${humanTime.subtext || ''}${ - humanTime.minutes ? `${humanTime.minutes} min` : '' - }` -} - -let styles = null - -const Timetable = ({ - timetable, - currentTrip, - triggerTrip, - realtimeStopUpdates, - region, - isTwentyFourHour = false, -}) => { - const tripIds = {} - return ( - - Departures - - {timetable - .map(service => { - const realtimeTrip = realtimeStopUpdates[service.trip_id] - if ( - realtimeTrip && - realtimeTrip.stopTimeUpdate && - realtimeTrip.stopTimeUpdate.length > 0 - ) { - let stop = realtimeTrip.stopTimeUpdate.find( - i => i.stopSequence === service.stop_sequence - ) - if (!stop) [stop] = realtimeTrip.stopTimeUpdate - service.realtimeStop = stop - - if (stop.stopSequence) { - service.visible = - stop.stopSequence < service.stop_sequence || - service.trip_id === currentTrip - } - } - return service - }) - .filter(service => { - // ensures that services that start and finish at the same place with the same trip_id don't show up more than once - tripIds[service.trip_id] = (tripIds[service.trip_id] || 0) + 1 - return service.visible === true && tripIds[service.trip_id] === 1 - }) - .map(service => { - let departureTextStyle = null - let emotion = null - let delay = 0 - let scheduleRelationship = 'scheduled' - - if (service.realtimeStop) { - const stop = service.realtimeStop - scheduleRelationship = stop.scheduleRelationship.toLowerCase() - - if (stop.scheduleRelationship === 'SCHEDULED') { - const estimate = stop.departure || stop.arrival - delay = estimate.delay - - const delayText = `(${Math.ceil(Math.abs(delay) / 60)}m)` - if (delay < -90) { - emotion = styles.neutral - scheduleRelationship = <>early {delayText} - } else if (delay < 180) { - emotion = styles.positive - scheduleRelationship = 'on time' - } else if (delay >= 180) { - emotion = styles.negative - scheduleRelationship = <>late {delayText} - } - } else if (stop.scheduleRelationship === 'CANCELLED') { - departureTextStyle = styles.cancelled - emotion = styles.negative - } - } - return ( - - - {formatDate( - service.departure_time, - delay, - isTwentyFourHour, - region - )} - - - {scheduleRelationship} - - - ) - })} - - - ) -} - -Timetable.propTypes = { - currentTrip: PropTypes.string, - timetable: PropTypes.arrayOf( - PropTypes.shape({ - trip_id: PropTypes.string.isRequired, - departure_time: PropTypes.string.isRequired, - }) - ).isRequired, - triggerTrip: PropTypes.func.isRequired, -} - -Timetable.defaultProps = { - currentTrip: '', -} - -styles = StyleSheet.create({ - departures: { - flexDirection: 'row', - overflowX: 'scroll', - paddingBottom: vars.padding / 2, - }, - departure: { - backgroundColor: 'rgba(0,0,0,0.06)', - width: `calc(33.3333% - ${Math.floor((vars.padding * 4) / 3)}px)`, - marginLeft: vars.padding, - borderRadius: 3, - paddingTop: vars.padding / 2, - paddingBottom: vars.padding / 2, - }, - departureSelected: { - backgroundColor: '#fff', - boxShadow: '0 1px 3px rgba(0,0,0,0.2)', - }, - departureDate: { - fontWeight: '600', - textAlign: 'center', - fontFamily: vars.fontFamily, - fontSize: 16, - }, - cancelled: { - textDecorationStyle: 'solid', - textDecorationLine: 'line-through', - }, - departureStatus: { - textAlign: 'center', - fontFamily: vars.fontFamily, - fontSize: 13, - color: '#888', - textTransform: 'capitalize', - }, - positive: { - color: '#27ae60', - }, - neutral: { - color: '#2980b9', - }, - negative: { - color: '#c0392b', - }, - direction: { - paddingTop: vars.padding, - paddingLeft: vars.padding, - paddingBottom: vars.padding * 0.5, - fontWeight: '600', - fontSize: vars.defaultFontSize, - fontFamily: vars.fontFamily, - }, -}) -export default Timetable diff --git a/js/views/lines/stops/LineStops.jsx b/js/views/lines/stops/LineStops.jsx index 65f5742c..561acbb8 100644 --- a/js/views/lines/stops/LineStops.jsx +++ b/js/views/lines/stops/LineStops.jsx @@ -34,15 +34,19 @@ export class LineStops extends Component { componentDidUpdate(prevProps) { const { tripId } = this.props if (tripId !== prevProps.tripId) { + this.setState({ loading: true }) this.getStops() } } componentWillUnmount() { const { pointsLayer, shapesLayer } = this - shapesLayer.hide(true, true) + // shapeslayer is nullable + if (shapesLayer) { + shapesLayer.hide(true, true) + shapesLayer.unmounted = true + } pointsLayer.hide() - shapesLayer.unmounted = true pointsLayer.unmounted = true } @@ -113,23 +117,25 @@ export class LineStops extends Component { render() { const { line, region, stopId, tripId, realtimeTripUpdate } = this.props const { loading, current, next, color } = this.state - if (loading) { - return - } + return ( Stops - + {loading ? ( + + ) : ( + + )} ) } diff --git a/js/views/lines/timetable/LineTimetable.jsx b/js/views/lines/timetable/LineTimetable.jsx new file mode 100644 index 00000000..9513e070 --- /dev/null +++ b/js/views/lines/timetable/LineTimetable.jsx @@ -0,0 +1,160 @@ +import React, { Component } from 'react' +import { View, Text, StyleSheet } from 'react-native' + +import LineData from '../../../data/LineData.js' +import SettingsStore from '../../../stores/SettingsStore.js' +import LineTimetableSelector from './LineTimetableSelector.jsx' +import Spinner from '../../reusable/Spinner.jsx' +import { vars } from '../../../styles.js' + +let styles = null + +export class LineTimetable extends Component { + constructor(props) { + super(props) + + const { region, tripId, stopId } = props + this.lineData = new LineData({ + region, + trip_id: tripId, + stop_id: stopId, + }) + + this.state = { + timetable: [], + } + } + + componentDidMount() { + this.getTimetable() + } + + componentDidUpdate(prevProps) { + const { stopId, line, agencyId, directionId } = this.props + if ( + stopId !== prevProps.stopId || + line !== prevProps.line || + agencyId !== prevProps.agencyId || + directionId !== prevProps.directionId + ) { + console.info('Getting new data') + this.getTimetable() + } + } + + getTimetable = async () => { + const { + line, + stopId, + agencyId, + directionId, + triggerTrip, + setRealtimeTrips, + } = this.props + // this will be invoked again properly + if (stopId === null) return + this.lineData.route_short_name = line + this.lineData.stop_id = stopId + this.lineData.agency_id = agencyId + this.lineData.direction_id = directionId + + const getTimetableState = rawData => { + const tolerance = 1000 * 60 * 30 + const visibleTolerance = 1000 * 60 * 2 + const realtimeTolerance = 1000 * 60 * 90 + const now = new Date(new Date().getTime() - tolerance) + const visibleNow = new Date(new Date().getTime() - visibleTolerance) + const realtimeNow = new Date(new Date().getTime() + realtimeTolerance) + const newState = { + timetable: rawData + .filter(service => { + return now < new Date(service.departure_time) + }) + .sort( + (a, b) => new Date(a.departure_time) > new Date(b.departure_time) + ) + .map(service => ({ + ...service, + visible: visibleNow < new Date(service.departure_time), + realtimeQuery: new Date(service.departure_time) < realtimeNow, + })), + } + const { tripId } = this.props + if (tripId == null && newState.timetable.length > 0) { + const selectedTrip = newState.timetable.find(a => a.visible === true) + if (selectedTrip) { + // sends the computed trip id back up to the parent component + triggerTrip(selectedTrip.trip_id)() + } + } + return newState + } + + try { + const timetableData = await this.lineData.getTimetable(0) + this.setState(getTimetableState(timetableData), async () => { + const { timetable } = this.state + setRealtimeTrips(timetable, true) + + const tomorrowTimetableData = await this.lineData.getTimetable(1) + const newState = getTimetableState( + timetable.slice().concat(tomorrowTimetableData) + ) + + setRealtimeTrips(newState.timetable, false) + + this.setState(newState, async () => { + if (newState.timetable.length > 0) return + // direction id 2 is the magical both directions + this.lineData.direction_id = 2 + const widerTimetableData = await this.lineData.getTimetable(0) + if (widerTimetableData.length > 0) { + this.setState(getTimetableState(widerTimetableData)) + } else { + this.setState(() => { + throw new Error( + 'We didn’t find any services for this line within the next few days.' + ) + }) + } + }) + }) + } catch (err) { + // cannot get timetable, usually because the stop_id is undefined + throw new Error(err.message) + } + } + + render() { + const { tripId, region, triggerTrip, realtimeStopUpdates } = this.props + const { timetable } = this.state + + return ( + + Departures + {timetable.length === 0 ? ( + // could potentially do a nicer loading state in the future + ) : ( + + )} + + ) + } +} +styles = StyleSheet.create({ + direction: { + paddingTop: vars.padding, + paddingLeft: vars.padding, + paddingBottom: vars.padding * 0.5, + fontWeight: '600', + fontSize: vars.defaultFontSize, + fontFamily: vars.fontFamily, + }, +}) diff --git a/js/views/lines/timetable/LineTimetableSelector.jsx b/js/views/lines/timetable/LineTimetableSelector.jsx new file mode 100644 index 00000000..81257f98 --- /dev/null +++ b/js/views/lines/timetable/LineTimetableSelector.jsx @@ -0,0 +1,178 @@ +import React from 'react' +import PropTypes from 'prop-types' + +import { View, Text, StyleSheet, TouchableOpacity } from 'react-native' +import { vars } from '../../../styles.js' + +import { getTime } from '../../../helpers/date.js' + +const formatDate = (dateString, delay, isTwentyFourHour, region) => { + const date = new Date(dateString) + date.setTime(date.getTime() + delay * 1000) + const humanTime = getTime(date, isTwentyFourHour, true, region) + + // make this nicer + return `${humanTime.text || ''}${humanTime.subtext || ''}${ + humanTime.minutes ? `${humanTime.minutes} min` : '' + }` +} + +let styles = null + +const LineTimetableSelector = ({ + timetable, + currentTrip, + triggerTrip, + realtimeStopUpdates, + region, + isTwentyFourHour = false, +}) => { + const tripIds = {} + return ( + + {timetable + .map(service => { + const realtimeTrip = realtimeStopUpdates[service.trip_id] + if ( + realtimeTrip && + realtimeTrip.stopTimeUpdate && + realtimeTrip.stopTimeUpdate.length > 0 + ) { + let stop = realtimeTrip.stopTimeUpdate.find( + i => i.stopSequence === service.stop_sequence + ) + if (!stop) [stop] = realtimeTrip.stopTimeUpdate + service.realtimeStop = stop + + if (stop.stopSequence) { + service.visible = + stop.stopSequence < service.stop_sequence || + service.trip_id === currentTrip + } + } + return service + }) + .filter(service => { + // ensures that services that start and finish at the same place with the same trip_id don't show up more than once + tripIds[service.trip_id] = (tripIds[service.trip_id] || 0) + 1 + return service.visible === true && tripIds[service.trip_id] === 1 + }) + .map(service => { + let departureTextStyle = null + let emotion = null + let delay = 0 + let scheduleRelationship = 'scheduled' + + if (service.realtimeStop) { + const stop = service.realtimeStop + scheduleRelationship = stop.scheduleRelationship.toLowerCase() + + if (stop.scheduleRelationship === 'SCHEDULED') { + const estimate = stop.departure || stop.arrival + delay = estimate.delay + + const delayText = `(${Math.ceil(Math.abs(delay) / 60)}m)` + if (delay < -90) { + emotion = styles.neutral + scheduleRelationship = <>early {delayText} + } else if (delay < 180) { + emotion = styles.positive + scheduleRelationship = 'on time' + } else if (delay >= 180) { + emotion = styles.negative + scheduleRelationship = <>late {delayText} + } + } else if (stop.scheduleRelationship === 'CANCELLED') { + departureTextStyle = styles.cancelled + emotion = styles.negative + } + } + return ( + + + {formatDate( + service.departure_time, + delay, + isTwentyFourHour, + region + )} + + + {scheduleRelationship} + + + ) + })} + + ) +} + +LineTimetableSelector.propTypes = { + currentTrip: PropTypes.string, + timetable: PropTypes.arrayOf( + PropTypes.shape({ + trip_id: PropTypes.string.isRequired, + departure_time: PropTypes.string.isRequired, + }) + ).isRequired, + triggerTrip: PropTypes.func.isRequired, +} + +LineTimetableSelector.defaultProps = { + currentTrip: '', +} + +styles = StyleSheet.create({ + departures: { + flexDirection: 'row', + overflowX: 'scroll', + paddingBottom: vars.padding / 2, + }, + departure: { + backgroundColor: 'rgba(0,0,0,0.06)', + width: `calc(33.3333% - ${Math.floor((vars.padding * 4) / 3)}px)`, + marginLeft: vars.padding, + borderRadius: 3, + paddingTop: vars.padding / 2, + paddingBottom: vars.padding / 2, + }, + departureSelected: { + backgroundColor: '#fff', + boxShadow: '0 1px 3px rgba(0,0,0,0.2)', + }, + departureDate: { + fontWeight: '600', + textAlign: 'center', + fontFamily: vars.fontFamily, + fontSize: 16, + }, + cancelled: { + textDecorationStyle: 'solid', + textDecorationLine: 'line-through', + }, + departureStatus: { + textAlign: 'center', + fontFamily: vars.fontFamily, + fontSize: 13, + color: '#888', + textTransform: 'capitalize', + }, + positive: { + color: '#27ae60', + }, + neutral: { + color: '#2980b9', + }, + negative: { + color: '#c0392b', + }, +}) +export default LineTimetableSelector diff --git a/js/views/station/Station.jsx b/js/views/station/Station.jsx index 814e53a2..43a6ba68 100644 --- a/js/views/station/Station.jsx +++ b/js/views/station/Station.jsx @@ -198,7 +198,7 @@ class Station extends Component { const stopId = match.params.station let tripIdParameter = '' if (tripId != null) { - tripIdParameter = `&tripId=${tripId}` + tripIdParameter = `&trip_id=${tripId}` } history.push( diff --git a/stories/timetable.stories.jsx b/stories/timetable.stories.jsx index 8eb2cabd..8e5ad802 100644 --- a/stories/timetable.stories.jsx +++ b/stories/timetable.stories.jsx @@ -1,6 +1,6 @@ import React from 'react' import { storiesOf } from '@storybook/react' -import Timetable from '../js/views/lines/Timetable' +import LineTimetableSelector from '../js/views/lines/timetable/LineTimetableSelector' const now = new Date().toISOString() const tenMins = new Date(new Date(now).getTime() + 10 * 60000).toISOString() @@ -9,7 +9,7 @@ const past = new Date(new Date(now).getTime() - 10 * 60000).toISOString() storiesOf('Timetable', module) .add('1 trip', () => ( - )) .add('2 trips', () => ( - )) .add('3 trips', () => ( - )) .add('selected trip', () => ( - )) .add('realtime - cancelled', () => ( - )) .add('realtime - late', () => ( - )) .add('realtime - on time', () => ( - )) .add('realtime - early', () => ( - )) .add('realtime - very late', () => ( - )) .add('realtime - very early', () => ( -