Skip to content

Commit 6f7aebe

Browse files
Merge pull request #225 from opentripplanner/dev
Release request
2 parents a3b6d0f + 4257cd3 commit 6f7aebe

9 files changed

+216
-92
lines changed

Diff for: example-config.yml

+6
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ routingTypes:
124124
- key: ITINERARY
125125
text: Exact Time
126126

127+
# Itinerary options
128+
itinerary:
129+
# Show fares for each transit leg (false if omitted).
130+
# (Requires using LineItinerary.)
131+
showRouteFares: false
132+
127133
### Use this config for the standard mode selector
128134
# modeGroups:
129135
# - name: Transit

Diff for: lib/components/narrative/line-itin/connected-itinerary-body.js

+8-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import styled from 'styled-components'
1212
import { showLegDiagram } from '../../../actions/map'
1313
import { setViewedTrip } from '../../../actions/ui'
1414
import TransitLegSubheader from './connected-transit-leg-subheader'
15+
import RealtimeTimeColumn from './realtime-time-column'
1516
import TripDetails from '../connected-trip-details'
1617
import TripTools from '../trip-tools'
1718

@@ -62,13 +63,19 @@ class ConnectedItineraryBody extends Component {
6263
showElevationProfile
6364
showLegIcon
6465
showMapButtonColumn={false}
66+
showRouteFares={config.itinerary && config.itinerary.showRouteFares}
6567
showViewTripButton
6668
timeOptions={timeOptions}
6769
toRouteAbbreviation={noop}
6870
TransitLegSubheader={TransitLegSubheader}
6971
TransitLegSummary={TransitLegSummary}
72+
TimeColumnContent={RealtimeTimeColumn}
73+
/>
74+
<TripDetails
75+
itinerary={itinerary}
76+
longDateFormat={config.dateTime.longDateFormat}
77+
timeOptions={timeOptions}
7078
/>
71-
<TripDetails itinerary={itinerary} />
7279
<TripTools itinerary={itinerary} />
7380
</ItineraryBodyContainer>
7481
)
+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
import { isTransit } from '@opentripplanner/core-utils/lib/itinerary'
2+
import {
3+
legType,
4+
timeOptionsType
5+
} from '@opentripplanner/core-utils/lib/types'
6+
import { formatTime } from '@opentripplanner/core-utils/lib/time'
7+
import PropTypes from 'prop-types'
8+
import React from 'react'
9+
import styled from 'styled-components'
10+
11+
const TimeText = styled.div``
12+
13+
const TimeStruck = styled.div`
14+
text-decoration: line-through;
15+
`
16+
17+
const TimeBlock = styled.div`
18+
line-height: 1em;
19+
margin-bottom: 4px;
20+
`
21+
22+
const TimeColumnBase = styled.div``
23+
24+
const StatusText = styled.div`
25+
color: #bbb;
26+
font-size: 80%;
27+
line-height: 1em;
28+
`
29+
30+
const DelayText = styled.span`
31+
display: block;
32+
white-space: nowrap;
33+
`
34+
35+
// Reusing stop viewer colors.
36+
const TimeColumnOnTime = styled(TimeColumnBase)`
37+
${TimeText}, ${StatusText} {
38+
color: #5cb85c;
39+
}
40+
`
41+
const TimeColumnEarly = styled(TimeColumnBase)`
42+
${TimeText}, ${StatusText} {
43+
color: #337ab7;
44+
}
45+
`
46+
const TimeColumnLate = styled(TimeColumnBase)`
47+
${TimeText}, ${StatusText} {
48+
color: #d9534f;
49+
}
50+
`
51+
52+
/**
53+
* This component displays the scheduled departure/arrival time for a leg,
54+
* and, for transit legs, displays any delays or earliness where applicable.
55+
*/
56+
export default function RealtimeTimeColumn ({
57+
isDestination,
58+
leg,
59+
timeOptions
60+
}) {
61+
const time = isDestination ? leg.endTime : leg.startTime
62+
const formattedTime = time && formatTime(time, timeOptions)
63+
const isTransitLeg = isTransit(leg.mode)
64+
65+
// For non-real-time legs, show only the scheduled time,
66+
// except for transit legs where we add the "scheduled" text underneath.
67+
if (!leg.realTime) {
68+
return (
69+
<>
70+
<TimeText>{formattedTime}</TimeText>
71+
{isTransitLeg && <StatusText>scheduled</StatusText>}
72+
</>
73+
)
74+
}
75+
76+
// Delay in seconds.
77+
const delay = isDestination ? leg.arrivalDelay : leg.departureDelay
78+
// Time is in milliseconds.
79+
const originalTime = time - delay * 1000
80+
const originalFormattedTime =
81+
originalTime && formatTime(originalTime, timeOptions)
82+
83+
// TODO: refine on-time thresholds.
84+
// const isOnTime = delay >= -60 && delay <= 120;
85+
const isOnTime = delay === 0
86+
87+
let statusText
88+
let TimeColumn = TimeColumnBase
89+
if (isOnTime) {
90+
statusText = 'on time'
91+
TimeColumn = TimeColumnOnTime
92+
} else if (delay < 0) {
93+
statusText = 'early'
94+
TimeColumn = TimeColumnEarly
95+
} else if (delay > 0) {
96+
statusText = 'late'
97+
TimeColumn = TimeColumnLate
98+
}
99+
100+
// Absolute delay in rounded minutes, for display purposes.
101+
const delayInMinutes = Math.abs(
102+
Math.round((isDestination ? leg.arrivalDelay : leg.departureDelay) / 60)
103+
)
104+
105+
let renderedTime
106+
if (!isOnTime) {
107+
// If the transit vehicle is not on time, strike the original scheduled time
108+
// and display the updated time underneath.
109+
renderedTime = (
110+
<TimeBlock>
111+
{!isOnTime && <TimeStruck>{originalFormattedTime}</TimeStruck>}
112+
<TimeText>{formattedTime}</TimeText>
113+
</TimeBlock>
114+
)
115+
} else {
116+
renderedTime = <TimeText>{formattedTime}</TimeText>
117+
}
118+
119+
return (
120+
<TimeColumn>
121+
{renderedTime}
122+
<StatusText>
123+
{/* Keep the '5 min' string on the same line. */}
124+
{!isOnTime && <DelayText>{delayInMinutes} min</DelayText>}
125+
{statusText}
126+
</StatusText>
127+
</TimeColumn>
128+
)
129+
}
130+
131+
RealtimeTimeColumn.propTypes = {
132+
isDestination: PropTypes.bool.isRequired,
133+
leg: legType.isRequired,
134+
timeOptions: timeOptionsType
135+
}
136+
137+
RealtimeTimeColumn.defaultProps = {
138+
timeOptions: null
139+
}

Diff for: lib/components/user/saved-trip-editor.js

+32-16
Original file line numberDiff line numberDiff line change
@@ -7,31 +7,47 @@ import StackedPaneDisplay from './stacked-pane-display'
77
* This component handles editing of an existing trip.
88
*/
99
const SavedTripEditor = ({
10+
isCreating,
1011
monitoredTrip,
1112
onCancel,
1213
onComplete,
1314
onDeleteTrip,
1415
panes
1516
}) => {
1617
if (monitoredTrip) {
17-
const paneSequence = [
18-
{
19-
pane: panes.basics,
20-
title: 'Trip overview'
21-
},
22-
{
23-
pane: panes.notifications,
24-
title: 'Trip notifications'
25-
},
26-
{
27-
// TODO: Find a better place for this.
28-
pane: () => <Button bsStyle='danger' onClick={onDeleteTrip}>Delete Trip</Button>,
29-
title: 'Danger zone'
30-
}
31-
]
18+
let paneSequence
19+
if (isCreating) {
20+
paneSequence = [
21+
{
22+
pane: panes.basics,
23+
title: 'Trip information'
24+
},
25+
{
26+
pane: panes.notifications,
27+
title: 'Trip notifications'
28+
}
29+
]
30+
} else {
31+
paneSequence = [
32+
{
33+
pane: panes.basics,
34+
title: 'Trip overview'
35+
},
36+
{
37+
pane: panes.notifications,
38+
title: 'Trip notifications'
39+
},
40+
{
41+
// TODO: Find a better place for this.
42+
pane: () => <Button bsStyle='danger' onClick={onDeleteTrip}>Delete Trip</Button>,
43+
title: 'Danger zone'
44+
}
45+
]
46+
}
47+
3248
return (
3349
<>
34-
<h1>{monitoredTrip.tripName}</h1>
50+
<h1>{isCreating ? 'Save trip' : monitoredTrip.tripName}</h1>
3551
<StackedPaneDisplay
3652
onCancel={onCancel}
3753
onComplete={onComplete}

Diff for: lib/components/user/saved-trip-screen.js

+9-24
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import * as uiActions from '../../actions/ui'
66
import * as userActions from '../../actions/user'
77
import DesktopNav from '../app/desktop-nav'
88
import SavedTripEditor from './saved-trip-editor'
9-
import SavedTripWizard from './saved-trip-wizard'
109
import TripBasicsPane from './trip-basics-pane'
1110
import TripNotificationsPane from './trip-notifications-pane'
1211
import TripSummaryPane from './trip-summary-pane'
@@ -187,36 +186,22 @@ class SavedTripScreen extends Component {
187186
}
188187

189188
render () {
190-
const { isCreating, monitoredTrips } = this.props
189+
const { isCreating } = this.props
191190
const { monitoredTrip } = this.state
192191

193-
let content
194-
if (isCreating && !hasMaxTripCount(monitoredTrips)) {
195-
content = (
196-
<SavedTripWizard
197-
monitoredTrip={monitoredTrip}
198-
onComplete={this._handleSaveNewTrip}
199-
panes={this._panes}
200-
/>
201-
)
202-
} else {
203-
content = (
204-
<SavedTripEditor
205-
monitoredTrip={monitoredTrip}
206-
onCancel={this._goToSavedTrips}
207-
onComplete={this._handleSaveTripEdits}
208-
onDeleteTrip={this._handleDeleteTrip}
209-
panes={this._panes}
210-
/>
211-
)
212-
}
213-
214192
return (
215193
<div className='otp'>
216194
{/* TODO: Do mobile view. */}
217195
<DesktopNav />
218196
<form className='container'>
219-
{content}
197+
<SavedTripEditor
198+
isCreating={isCreating}
199+
monitoredTrip={monitoredTrip}
200+
onCancel={isCreating ? this._goToTripPlanner : this._goToSavedTrips}
201+
onComplete={isCreating ? this._handleSaveNewTrip : this._handleSaveTripEdits}
202+
onDeleteTrip={this._handleDeleteTrip}
203+
panes={this._panes}
204+
/>
220205
</form>
221206
</div>
222207
)

Diff for: lib/components/user/saved-trip-wizard.js

-43
This file was deleted.

Diff for: lib/components/user/trip-notifications-pane.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,13 @@ class TripNotificationsPane extends Component {
7171
</FormGroup>
7272

7373
<Alert bsStyle='warning'>
74-
Under construction!
74+
Under construction!
7575
<FormGroup>
7676
<ControlLabel>Notify me if:</ControlLabel>
7777
<Checkbox>A different route or transfer point is recommended</Checkbox>
7878
<Checkbox>There is an alert for a route or stop that is part of my journey</Checkbox>
7979

80-
Your arrival or departure time changes by more than:
80+
Your arrival or departure time changes by more than:
8181
<FormControl componentClass='select' defaultValue={5} placeholder='select'>
8282
<option value={5}>5 min. (default)</option>
8383
<option value={10}>10 min.</option>

Diff for: package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"@opentripplanner/geocoder": "^1.0.2",
3535
"@opentripplanner/humanize-distance": "^0.0.22",
3636
"@opentripplanner/icons": "^1.0.1",
37-
"@opentripplanner/itinerary-body": "^1.0.2",
37+
"@opentripplanner/itinerary-body": "^1.2.0",
3838
"@opentripplanner/location-field": "^1.0.2",
3939
"@opentripplanner/location-icon": "^1.0.0",
4040
"@opentripplanner/park-and-ride-overlay": "^1.0.1",

0 commit comments

Comments
 (0)