Skip to content

Commit 0a5e04c

Browse files
authored
Merge pull request #100 from opentripplanner/print-view-text-tweaks
Fix up print view text for various rental modes
2 parents 5b4294d + 3fa82f8 commit 0a5e04c

File tree

6 files changed

+145
-35
lines changed

6 files changed

+145
-35
lines changed

Diff for: lib/components/app/print-layout.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ class PrintLayout extends Component {
5959
}
6060

6161
render () {
62-
const { itinerary, companies, timeFormat } = this.props
62+
const { configCompanies, customIcons, itinerary, timeFormat } = this.props
6363
return (
6464
<div className='otp print-layout'>
6565
{/* The header bar, including the Toggle Map and Print buttons */}
@@ -87,7 +87,14 @@ class PrintLayout extends Component {
8787
}
8888

8989
{/* The main itinerary body */}
90-
{itinerary && <PrintableItinerary itinerary={itinerary} companies={companies} timeFormat={timeFormat} />}
90+
{itinerary
91+
? <PrintableItinerary
92+
configCompanies={configCompanies}
93+
customIcons={customIcons}
94+
itinerary={itinerary}
95+
timeFormat={timeFormat} />
96+
: null
97+
}
9198
</div>
9299
)
93100
}
@@ -98,7 +105,7 @@ class PrintLayout extends Component {
98105
const mapStateToProps = (state, ownProps) => {
99106
return {
100107
itinerary: getActiveItinerary(state.otp),
101-
companies: state.otp.currentQuery.companies,
108+
configCompanies: state.otp.config.companies,
102109
timeFormat: getTimeFormat(state.otp.config)
103110
}
104111
}

Diff for: lib/components/app/responsive-webapp.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,13 @@ class RouterWrapper extends Component {
193193
/>
194194
<Route
195195
path='/print'
196-
component={PrintLayout}
196+
component={(routerProps) => {
197+
// combine the router props with the other props that get
198+
// passed to the exported component. This way it's possible for
199+
// the PrintLayout component to receive the custom icons prop.
200+
const props = {...this.props, ...routerProps}
201+
return <PrintLayout {...props} />
202+
}}
197203
/>
198204
{/* For any other route, simply return the web app. */}
199205
<Route

Diff for: lib/components/narrative/line-itin/access-leg-body.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ class AccessLegSummary extends Component {
163163
<div>
164164
{getLegModeLabel(leg)}
165165
{' '}
166-
{leg.distance && <span> {distanceString(leg.distance)}</span>}
166+
{leg.distance > 0 && <span> {distanceString(leg.distance)}</span>}
167167
{` to ${getPlaceName(leg.to, config.companies)}`}
168168
</div>
169169
</div>

Diff for: lib/components/narrative/line-itin/place-row.js

+7-5
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { connect } from 'react-redux'
44
import LocationIcon from '../../icons/location-icon'
55
import ViewStopButton from '../../viewers/view-stop-button'
66
import {
7-
getCompanyForNetwork,
7+
getCompaniesLabelFromNetworks,
88
getModeForPlace,
99
getPlaceName
1010
} from '../../../util/itinerary'
@@ -187,9 +187,11 @@ class RentedVehicleLeg extends PureComponent {
187187
// resumes there won't be any network info. In that case we simply return
188188
// that the rental is continuing.
189189
if (leg.from.networks) {
190-
const companies = leg.from.networks.map(n => getCompanyForNetwork(n, configCompanies))
191-
const companyLabel = companies.map(co => co.label).join('/')
192-
rentalDescription += ` ${companyLabel}`
190+
const companiesLabel = getCompaniesLabelFromNetworks(
191+
leg.from.networks,
192+
configCompanies
193+
)
194+
rentalDescription += ` ${companiesLabel}`
193195
// Only show vehicle name for car rentals. For bikes and eScooters, these
194196
// IDs/names tend to be less relevant (or entirely useless) in this context.
195197
if (leg.rentedCar && leg.from.name) {
@@ -200,7 +202,7 @@ class RentedVehicleLeg extends PureComponent {
200202
rentalDescription = 'Continue using rental'
201203
}
202204

203-
rentalDescription += ` ${modeString}${vehicleName}`
205+
rentalDescription += ` ${modeString} ${vehicleName}`
204206
}
205207
// e.g., Pick up REACHNOW rented car XYZNDB OR
206208
// Pick up SPIN eScooter

Diff for: lib/components/narrative/printable/printable-itinerary.js

+101-23
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
import React, { Component } from 'react'
22
import PropTypes from 'prop-types'
33

4-
import ModeIcon from '../../icons/mode-icon'
54
import TripDetails from '../trip-details'
5+
import { distanceString } from '../../../util/distance'
66
import { formatTime, formatDuration } from '../../../util/time'
7-
import { getLegModeLabel, getStepDirection, getStepStreetName, getTimeZoneOffset } from '../../../util/itinerary'
7+
import {
8+
getCompaniesLabelFromNetworks,
9+
getLegIcon,
10+
getLegModeLabel,
11+
getPlaceName,
12+
getStepDirection,
13+
getStepStreetName,
14+
getTimeZoneOffset
15+
} from '../../../util/itinerary'
816

917
export default class PrintableItinerary extends Component {
1018
static propTypes = {
1119
itinerary: PropTypes.object
1220
}
1321

1422
render () {
15-
const { itinerary, timeFormat } = this.props
23+
const {
24+
configCompanies,
25+
customIcons,
26+
itinerary,
27+
timeFormat
28+
} = this.props
1629

1730
const timeOptions = {
1831
format: timeFormat,
@@ -31,10 +44,26 @@ export default class PrintableItinerary extends Component {
3144
</div>
3245
)}
3346
{itinerary.legs.map((leg, k) => leg.transitLeg
34-
? <TransitLeg key={k} leg={leg} interlineFollows={k < itinerary.legs.length - 1 && itinerary.legs[k + 1].interlineWithPreviousLeg} timeOptions={timeOptions} />
47+
? <TransitLeg
48+
key={k}
49+
customIcons={customIcons}
50+
interlineFollows={k < itinerary.legs.length - 1 &&
51+
itinerary.legs[k + 1].interlineWithPreviousLeg
52+
}
53+
leg={leg}
54+
timeOptions={timeOptions} />
3555
: leg.hailedCar
36-
? <TNCLeg leg={leg} timeOptions={timeOptions} />
37-
: <AccessLeg key={k} leg={leg} timeOptions={timeOptions} />
56+
? <TNCLeg
57+
customIcons={customIcons}
58+
leg={leg}
59+
timeOptions={timeOptions} />
60+
: <AccessLeg
61+
key={k}
62+
configCompanies={configCompanies}
63+
customIcons={customIcons}
64+
leg={leg}
65+
timeOptions={timeOptions}
66+
/>
3867
)}
3968
<TripDetails itinerary={itinerary} />
4069
</div>
@@ -48,18 +77,23 @@ class TransitLeg extends Component {
4877
}
4978

5079
render () {
51-
const { leg, interlineFollows, timeOptions } = this.props
80+
const { customIcons, leg, interlineFollows, timeOptions } = this.props
5281

5382
// Handle case of transit leg interlined w/ previous
5483
if (leg.interlineWithPreviousLeg) {
5584
return (
5685
<div className='leg collapse-top'>
5786
<div className='leg-body'>
5887
<div className='leg-header'>
59-
Continues as <b>{leg.routeShortName} {leg.routeLongName}</b> to <b>{leg.to.name}</b>
88+
Continues as{' '}
89+
<b>{leg.routeShortName} {leg.routeLongName}</b>{' '}
90+
to <b>{leg.to.name}</b>
6091
</div>
6192
<div className='leg-details'>
62-
<div className='leg-detail'>Get off at <b>{leg.to.name}</b> at {formatTime(leg.endTime, timeOptions)}</div>
93+
<div className='leg-detail'>
94+
Get off at <b>{leg.to.name}</b>{' '}
95+
at {formatTime(leg.endTime, timeOptions)}
96+
</div>
6397
</div>
6498
</div>
6599
</div>
@@ -68,17 +102,25 @@ class TransitLeg extends Component {
68102

69103
return (
70104
<div className='leg'>
71-
<div className='mode-icon'><ModeIcon mode={leg.mode} /></div>
105+
<div className='mode-icon'>{getLegIcon(leg, customIcons)}</div>
72106
<div className='leg-body'>
73107
<div className='leg-header'>
74108
<b>{leg.routeShortName} {leg.routeLongName}</b> to <b>{leg.to.name}</b>
75109
</div>
76110
<div className='leg-details'>
77-
<div className='leg-detail'>Board at <b>{leg.from.name}</b> at {formatTime(leg.startTime, timeOptions)}</div>
78-
{interlineFollows
79-
? <div className='leg-detail'>Stay on board at <b>{leg.to.name}</b></div>
80-
: <div className='leg-detail'>Get off at <b>{leg.to.name}</b> at {formatTime(leg.endTime, timeOptions)}</div>
81-
}
111+
<div className='leg-detail'>
112+
Board at <b>{leg.from.name}</b>{' '}
113+
at {formatTime(leg.startTime, timeOptions)}
114+
</div>
115+
<div className='leg-detail'>
116+
{interlineFollows
117+
? <span>Stay on board at <b>{leg.to.name}</b></span>
118+
: <span>
119+
Get off at <b>{leg.to.name}</b>{' '}
120+
at {formatTime(leg.endTime, timeOptions)}
121+
</span>
122+
}
123+
</div>
82124
</div>
83125
</div>
84126
</div>
@@ -92,19 +134,49 @@ class AccessLeg extends Component {
92134
}
93135

94136
render () {
95-
const { leg } = this.props
137+
const { configCompanies, customIcons, leg } = this.props
138+
139+
// calculate leg mode label in a special way for this component
140+
let legModeLabel = getLegModeLabel(leg)
141+
142+
if (leg.rentedBike) {
143+
// FIXME: Special case for TriMet that needs to be refactored to
144+
// incorporate actual company.
145+
legModeLabel = 'Ride BIKETOWN bike'
146+
} else if (leg.rentedCar) {
147+
// Add extra information to printview that would otherwise clutter up
148+
// other places that use the getLegModeLabel function
149+
const companiesLabel = getCompaniesLabelFromNetworks(
150+
leg.from.networks,
151+
configCompanies
152+
)
153+
legModeLabel = `Drive ${companiesLabel} ${leg.from.name}`
154+
} else if (leg.rentedVehicle) {
155+
const companiesLabel = getCompaniesLabelFromNetworks(
156+
leg.from.networks,
157+
configCompanies
158+
)
159+
legModeLabel = `Ride ${companiesLabel} eScooter`
160+
}
161+
96162
return (
97163
<div className='leg'>
98-
<div className='mode-icon'><ModeIcon mode={leg.mode} /></div>
164+
<div className='mode-icon'>{getLegIcon(leg, customIcons)}</div>
99165
<div className='leg-body'>
100166
<div className='leg-header'>
101-
<b>{getLegModeLabel(leg)}</b> to <b>{leg.to.name}</b>
167+
<b>{legModeLabel}</b>{' '}
168+
{!leg.hailedCar &&
169+
leg.distance > 0 &&
170+
<span> {distanceString(leg.distance)} </span>}
171+
to <b>{getPlaceName(leg.to, configCompanies)}</b>
102172
</div>
103173
{!leg.hailedCar && (
104174
<div className='leg-details'>
105175
{leg.steps.map((step, k) => {
106176
return (
107-
<div key={k} className='leg-detail'>{getStepDirection(step)} on <b>{getStepStreetName(step)}</b></div>
177+
<div key={k} className='leg-detail'>
178+
{getStepDirection(step)} on <b>{getStepStreetName(step)}</b>
179+
</div>
108180
)
109181
})}
110182
</div>
@@ -121,20 +193,26 @@ class TNCLeg extends Component {
121193
}
122194

123195
render () {
124-
const { leg } = this.props
196+
const { customIcons, leg } = this.props
125197
const { tncData } = leg
126198
if (!tncData) return null
127199

128200
return (
129201
<div className='leg'>
130-
<div className='mode-icon'><ModeIcon mode={leg.mode} /></div>
202+
<div className='mode-icon'>{getLegIcon(leg, customIcons)}</div>
131203
<div className='leg-body'>
132204
<div className='leg-header'>
133205
<b>Take {tncData.displayName}</b> to <b>{leg.to.name}</b>
134206
</div>
135207
<div className='leg-details'>
136-
<div className='leg-detail'>Estimated wait time for pickup: <b>{formatDuration(tncData.estimatedArrival)}</b></div>
137-
<div className='leg-detail'>Estimated travel time: <b>{formatDuration(leg.duration)}</b> (does not account for traffic)</div>
208+
<div className='leg-detail'>
209+
Estimated wait time for pickup:{' '}
210+
<b>{formatDuration(tncData.estimatedArrival)}</b>
211+
</div>
212+
<div className='leg-detail'>
213+
Estimated travel time:{' '}
214+
<b>{formatDuration(leg.duration)}</b> (does not account for traffic)
215+
</div>
138216
</div>
139217
</div>
140218
</div>

Diff for: lib/util/itinerary.js

+19-2
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ export function toSentenceCase (str) {
379379
*/
380380
export function getLegIcon (leg, customIcons) {
381381
// check if a custom function exists for determining the icon for a leg
382-
if (typeof customIcons.customIconForLeg === 'function') {
382+
if (customIcons && typeof customIcons.customIconForLeg === 'function') {
383383
// function exits, get the icon string lookup. It's possible for there to be
384384
// a custom function that only returns a string for when a leg meets the
385385
// criteria of the custom function
@@ -402,14 +402,31 @@ export function getLegIcon (leg, customIcons) {
402402
return getIcon(iconStr, customIcons)
403403
}
404404

405-
export function getCompanyForNetwork (networkString, companies = []) {
405+
/**
406+
* Get the configured company object for the given network string if the company
407+
* has been defined in the provided companies array config.
408+
*/
409+
function getCompanyForNetwork (networkString, companies = []) {
406410
const company = companies.find(co => co.id === networkString)
407411
if (!company) {
408412
console.warn(`No company found in config.yml that matches rented vehicle network: ${networkString}`, companies)
409413
}
410414
return company
411415
}
412416

417+
/**
418+
* Get a string label to display from a list of vehicle rental networks.
419+
*
420+
* @param {Array<string>} networks A list of network ids.
421+
* @param {Array<object>} [companies=[]] An optional list of the companies config.
422+
* @return {string} A label for use in presentation on a website.
423+
*/
424+
export function getCompaniesLabelFromNetworks (networks, companies = []) {
425+
return networks.map(network => getCompanyForNetwork(network, companies))
426+
.map(co => co.label)
427+
.join('/')
428+
}
429+
413430
/**
414431
* Returns mode name by checking the vertex type (VertexType class in OTP) for
415432
* the provided place. NOTE: this is currently only intended for vehicles at

0 commit comments

Comments
 (0)