Skip to content

Commit 21f2e52

Browse files
authored
Merge pull request #77 from opentripplanner/dev
Bug fix release
2 parents 02a70c1 + d886c1e commit 21f2e52

21 files changed

+635
-287
lines changed

Diff for: lib/actions/api.js

+271-136
Large diffs are not rendered by default.

Diff for: lib/actions/map.js

+13-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { createAction } from 'redux-actions'
22

3+
import { routingQuery } from './api'
4+
import { clearActiveSearch } from './form'
35
import { reverse } from '../util/geocoder'
46

57
/* SET_LOCATION action creator. Updates a from or to location in the store
@@ -13,18 +15,23 @@ import { reverse } from '../util/geocoder'
1315
* }
1416
*/
1517

16-
export const clearingLocation = createAction('CLEAR_LOCATION')
17-
export const settingLocation = createAction('SET_LOCATION')
18-
export const switchingLocations = createAction('SWITCH_LOCATIONS')
18+
// Private actions
19+
const clearingLocation = createAction('CLEAR_LOCATION')
20+
const settingLocation = createAction('SET_LOCATION')
1921

22+
// Public actions
2023
export const forgetPlace = createAction('FORGET_PLACE')
2124
export const rememberPlace = createAction('REMEMBER_PLACE')
2225
export const forgetStop = createAction('FORGET_STOP')
2326
export const rememberStop = createAction('REMEMBER_STOP')
2427

2528
export function clearLocation (payload) {
2629
return function (dispatch, getState) {
30+
// Dispatch the clear location action and then clear the active search (so
31+
// that the map and narrative are not showing a search when one or both
32+
// locations are not defined).
2733
dispatch(clearingLocation(payload))
34+
dispatch(clearActiveSearch())
2835
}
2936
}
3037

@@ -72,6 +79,7 @@ export function setLocationToCurrent (payload) {
7279
export function switchLocations () {
7380
return function (dispatch, getState) {
7481
const { from, to } = getState().otp.currentQuery
82+
// First, reverse the locations.
7583
dispatch(settingLocation({
7684
type: 'from',
7785
location: to
@@ -80,6 +88,8 @@ export function switchLocations () {
8088
type: 'to',
8189
location: from
8290
}))
91+
// Then kick off a routing query (if the query is invalid, search will abort).
92+
dispatch(routingQuery())
8393
}
8494
}
8595

Diff for: lib/components/form/plan-trip-button.js

+6-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ class PlanTripButton extends Component {
1515
profileTrip: PropTypes.func
1616
}
1717

18+
static defaultProps = {
19+
disabled: false
20+
}
21+
1822
_onClick = () => {
1923
this.props.routingQuery()
2024
if (typeof this.props.onClick === 'function') this.props.onClick()
@@ -23,10 +27,8 @@ class PlanTripButton extends Component {
2327

2428
render () {
2529
const { currentQuery, text } = this.props
26-
const disabled = this.props.disabled === undefined
27-
? !currentQuery.from || !currentQuery.to
28-
: this.props.disabled
29-
30+
const locationMissing = !currentQuery.from || !currentQuery.to
31+
const disabled = locationMissing || this.props.disabled
3032
return (
3133
<Button
3234
className='plan-trip-button'

Diff for: lib/components/form/settings-selector-panel.js

+9-5
Original file line numberDiff line numberDiff line change
@@ -263,20 +263,21 @@ class SettingsSelectorPanel extends Component {
263263
const {config, mode, icons} = this.props
264264
const {exclusiveModes} = config.modes
265265
const modeHasTransit = hasTransit(mode)
266-
266+
// Use int for array element keys
267+
let key = 0
267268
if (!exclusiveModes) return null
268269

269270
// create an array of children to display within a mode-group-row
270271
// at most 2 exclusive modes will be displayed side-by-side
271272
const children = []
272-
const spacer = (
273-
<Col xs={2} style={{ height: 44 }}>&nbsp;</Col>
273+
const spacer = () => (
274+
<Col xs={2} key={key++} style={{ height: 44 }}>&nbsp;</Col>
274275
)
275276

276277
exclusiveModes.forEach((exclusiveMode, idx) => {
277278
// add left padding for every evenly indexed exclusiveMode
278279
if (idx % 2 === 0) {
279-
children.push(spacer)
280+
children.push(spacer())
280281
}
281282

282283
switch (exclusiveMode) {
@@ -285,6 +286,7 @@ class SettingsSelectorPanel extends Component {
285286
<Col xs={4}>
286287
<ModeButton
287288
enabled
289+
key={key++}
288290
active={mode === 'WALK'}
289291
icons={icons}
290292
mode={'WALK'}
@@ -301,6 +303,7 @@ class SettingsSelectorPanel extends Component {
301303
<Col xs={4}>
302304
<ModeButton
303305
enabled
306+
key={key++}
304307
active={!modeHasTransit && hasBike(mode)}
305308
icons={icons}
306309
mode={'BICYCLE'}
@@ -317,6 +320,7 @@ class SettingsSelectorPanel extends Component {
317320
<Col xs={4}>
318321
<ModeButton
319322
enabled
323+
key={key++}
320324
active={!modeHasTransit && hasMicromobility(mode)}
321325
icons={icons}
322326
mode={'MICROMOBILITY'}
@@ -334,7 +338,7 @@ class SettingsSelectorPanel extends Component {
334338

335339
// add right padding for every odd indexed exclusiveMode
336340
if (idx % 2 !== 0) {
337-
children.push(spacer)
341+
children.push(spacer())
338342
}
339343
})
340344

Diff for: lib/components/map/map.css

-2
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,13 @@
6767
/*** Car Rental Map Icons ***/
6868

6969
.otp .car-rental-icon {
70-
color: gray;
7170
font-size: 18px;
7271
text-align: center;
7372
}
7473

7574
/*** Micromobility Rental Map Icons ***/
7675

7776
.otp .micromobility-rental-icon {
78-
color: gray;
7977
font-size: 18px;
8078
text-align: center;
8179
}

Diff for: lib/components/map/route-viewer-overlay.js

+19-6
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,16 @@ import React from 'react'
22
import { connect } from 'react-redux'
33
import { FeatureGroup, MapLayer, Polyline } from 'react-leaflet'
44

5-
function geomToArray (point) {
6-
return [point.lat, point.lon]
5+
import polyline from '@mapbox/polyline'
6+
7+
// helper fn to check if geometry has been populated for all patterns in route
8+
const isGeomComplete = routeData => {
9+
return (
10+
routeData &&
11+
routeData.patterns &&
12+
Object.values(routeData.patterns)
13+
.every(ptn => typeof ptn.geometry !== 'undefined')
14+
)
715
}
816

917
class RouteViewerOverlay extends MapLayer {
@@ -16,9 +24,14 @@ class RouteViewerOverlay extends MapLayer {
1624

1725
componentWillReceiveProps (nextProps) {
1826
// if pattern geometry just finished populating, update the map points
19-
if (nextProps.routeData && nextProps.routeData.patterns && Object.keys(nextProps.routeData.patterns).length > 0) {
27+
if (
28+
!isGeomComplete(this.props.routeData) &&
29+
isGeomComplete(nextProps.routeData)
30+
) {
2031
const allPoints = Object.values(nextProps.routeData.patterns).reduce(
21-
(acc, ptn) => acc.concat(ptn.geometry.map(geomToArray)),
32+
(acc, ptn) => {
33+
return acc.concat(polyline.decode(ptn.geometry.points))
34+
},
2235
[]
2336
)
2437
this.context.map.fitBounds(allPoints)
@@ -38,14 +51,14 @@ class RouteViewerOverlay extends MapLayer {
3851
const segments = []
3952
Object.values(routeData.patterns).forEach(pattern => {
4053
if (!pattern.geometry) return
41-
const pts = pattern.geometry.map(geomToArray)
54+
const pts = polyline.decode(pattern.geometry.points)
4255
segments.push(
4356
<Polyline
4457
positions={pts}
4558
weight={4}
4659
color={routeColor}
4760
opacity={1}
48-
key={pattern.patternId}
61+
key={pattern.id}
4962
/>
5063
)
5164
})

Diff for: lib/components/map/vehicle-rental-overlay.js

+9-6
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,19 @@ class VehicleRentalOverlay extends MapLayer {
159159

160160
_renderStationAsMarker = (station, symbolDef) => {
161161
const {baseIconClass} = this.props
162-
let className = `fa fa-map-marker ${baseIconClass}`
162+
let classes = `fa fa-map-marker ${baseIconClass}`
163163
// If this station is exclusive to a single network, apply the the class for that network
164164
if (station.networks.length === 1) {
165-
className += ` ${baseIconClass}-${station.networks[0].toLowerCase()}`
165+
classes += ` ${baseIconClass}-${station.networks[0].toLowerCase()}`
166166
}
167+
const color = symbolDef && symbolDef.fillColor
168+
? symbolDef.fillColor
169+
: 'gray'
167170
const markerIcon = divIcon({
171+
className: '',
168172
iconSize: [11, 16],
169173
popupAnchor: [0, -6],
170-
html: '<i />',
171-
className
174+
html: `<i class="${classes}" style="color: ${color}"/>`
172175
})
173176

174177
return (
@@ -211,8 +214,8 @@ class VehicleRentalOverlay extends MapLayer {
211214
}
212215

213216
render () {
214-
const { stations, companies } = this.props
215-
217+
const { mapSymbols, stations, companies } = this.props
218+
if (!mapSymbols) console.warn(`No map symbols provided for layer ${this.props.name}`, companies)
216219
let filteredStations = stations
217220
if (companies) {
218221
filteredStations = stations.filter(

Diff for: lib/components/narrative/default/access-leg.js

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ import { distanceString } from '../../../util/distance'
77
import { getStepInstructions } from '../../../util/itinerary'
88
import { formatDuration } from '../../../util/time'
99

10+
/**
11+
* Default access leg component for narrative itinerary.
12+
*/
1013
export default class AccessLeg extends Component {
1114
static propTypes = {
1215
activeStep: PropTypes.number,

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class ItineraryCarousel extends Component {
5454

5555
render () {
5656
const { activeItinerary, itineraries, itineraryClass, hideHeader, pending, showProfileSummary } = this.props
57-
if (pending) return <Loading />
57+
if (pending) return <Loading small />
5858
if (!itineraries) return null
5959

6060
let views = []

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

+35-7
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,23 @@ import currencyFormatter from 'currency-formatter'
66
import LegDiagramPreview from '../leg-diagram-preview'
77

88
import { distanceString } from '../../../util/distance'
9-
import { getLegModeLabel, getLegIcon, getPlaceName, getStepDirection, getStepStreetName } from '../../../util/itinerary'
9+
import {
10+
getLegModeLabel,
11+
getLegIcon,
12+
getPlaceName,
13+
getStepDirection,
14+
getStepStreetName
15+
} from '../../../util/itinerary'
1016
import { formatDuration, formatTime } from '../../../util/time'
1117
import { isMobile } from '../../../util/ui'
1218

1319
import DirectionIcon from '../../icons/direction-icon'
1420

21+
/**
22+
* Component for access (e.g. walk/bike/etc.) leg in narrative itinerary. This
23+
* particular component is used in the line-itin (i.e., trimet-mod-otp) version
24+
* of the narrative itinerary.
25+
*/
1526
export default class AccessLegBody extends Component {
1627
static propTypes = {
1728
leg: PropTypes.object,
@@ -32,15 +43,27 @@ export default class AccessLegBody extends Component {
3243
}
3344

3445
render () {
35-
const { customIcons, followsTransit, leg, timeOptions } = this.props
46+
const { config, customIcons, followsTransit, leg, timeOptions } = this.props
3647

3748
if (leg.mode === 'CAR' && leg.hailedCar) {
38-
return <TNCLeg leg={leg} onSummaryClick={this._onSummaryClick} timeOptions={timeOptions} followsTransit={followsTransit} customIcons={customIcons} />
49+
return (
50+
<TNCLeg
51+
config={config}
52+
leg={leg}
53+
onSummaryClick={this._onSummaryClick}
54+
timeOptions={timeOptions}
55+
followsTransit={followsTransit}
56+
customIcons={customIcons} />
57+
)
3958
}
4059

4160
return (
4261
<div className='leg-body'>
43-
<AccessLegSummary leg={leg} onSummaryClick={this._onSummaryClick} customIcons={customIcons} />
62+
<AccessLegSummary
63+
config={config}
64+
leg={leg}
65+
onSummaryClick={this._onSummaryClick}
66+
customIcons={customIcons} />
4467

4568
<div onClick={this._onStepsHeaderClick} className='steps-header'>
4669
{formatDuration(leg.duration)}
@@ -60,6 +83,7 @@ class TNCLeg extends Component {
6083
render () {
6184
// TODO: ensure that client ID fields are populated
6285
const {
86+
config,
6387
LYFT_CLIENT_ID,
6488
UBER_CLIENT_ID,
6589
customIcons,
@@ -82,7 +106,11 @@ class TNCLeg extends Component {
82106

83107
<div className='leg-body'>
84108
{/* The icon/summary row */}
85-
<AccessLegSummary leg={leg} onSummaryClick={this.props.onSummaryClick} customIcons={customIcons} />
109+
<AccessLegSummary
110+
config={config}
111+
leg={leg}
112+
onSummaryClick={this.props.onSummaryClick}
113+
customIcons={customIcons} />
86114

87115
{/* The "Book Ride" button */}
88116
<div style={{ marginTop: 10, marginBottom: 10, height: 32, position: 'relative' }}>
@@ -125,7 +153,7 @@ class TNCLeg extends Component {
125153

126154
class AccessLegSummary extends Component {
127155
render () {
128-
const { customIcons, leg } = this.props
156+
const { config, customIcons, leg } = this.props
129157
return (
130158
<div className='summary leg-description' onClick={this.props.onSummaryClick}>
131159
{/* Mode-specific icon */}
@@ -136,7 +164,7 @@ class AccessLegSummary extends Component {
136164
{getLegModeLabel(leg)}
137165
{' '}
138166
{leg.distance && <span> {distanceString(leg.distance)}</span>}
139-
{` to ${getPlaceName(leg.to)}`}
167+
{` to ${getPlaceName(leg.to, config.companies)}`}
140168
</div>
141169
</div>
142170
)

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

-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@ export default class ItineraryBody extends Component {
3636
place={leg.from}
3737
time={leg.startTime}
3838
leg={leg}
39-
previousLeg={i > 0 ? itinerary.legs[i - 1] : null}
4039
legIndex={i}
4140
followsTransit={followsTransit}
4241
{...this.props}

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

+12-2
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,19 @@ export default class LineItinerary extends NarrativeItinerary {
6060

6161
return (
6262
<div className='line-itin'>
63-
<ItinerarySummary companies={companies} itinerary={itinerary} timeOptions={timeOptions} onClick={onClick} customIcons={customIcons} />
63+
<ItinerarySummary
64+
companies={companies}
65+
itinerary={itinerary}
66+
timeOptions={timeOptions}
67+
onClick={onClick}
68+
customIcons={customIcons} />
6469
{showRealtimeAnnotation && <SimpleRealtimeAnnotation />}
65-
{active || expanded ? <ItineraryBody {...this.props} itinerary={itinerary} timeOptions={timeOptions} /> : null}
70+
{active || expanded
71+
? <ItineraryBody
72+
{...this.props}
73+
itinerary={itinerary}
74+
timeOptions={timeOptions} />
75+
: null}
6676
{itineraryFooter}
6777
</div>
6878
)

0 commit comments

Comments
 (0)