Skip to content

Commit

Permalink
Merge pull request #77 from opentripplanner/dev
Browse files Browse the repository at this point in the history
Bug fix release
  • Loading branch information
landonreed authored Jul 12, 2019
2 parents 02a70c1 + d886c1e commit 21f2e52
Show file tree
Hide file tree
Showing 21 changed files with 635 additions and 287 deletions.
407 changes: 271 additions & 136 deletions lib/actions/api.js

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions lib/actions/map.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { createAction } from 'redux-actions'

import { routingQuery } from './api'
import { clearActiveSearch } from './form'
import { reverse } from '../util/geocoder'

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

export const clearingLocation = createAction('CLEAR_LOCATION')
export const settingLocation = createAction('SET_LOCATION')
export const switchingLocations = createAction('SWITCH_LOCATIONS')
// Private actions
const clearingLocation = createAction('CLEAR_LOCATION')
const settingLocation = createAction('SET_LOCATION')

// Public actions
export const forgetPlace = createAction('FORGET_PLACE')
export const rememberPlace = createAction('REMEMBER_PLACE')
export const forgetStop = createAction('FORGET_STOP')
export const rememberStop = createAction('REMEMBER_STOP')

export function clearLocation (payload) {
return function (dispatch, getState) {
// Dispatch the clear location action and then clear the active search (so
// that the map and narrative are not showing a search when one or both
// locations are not defined).
dispatch(clearingLocation(payload))
dispatch(clearActiveSearch())
}
}

Expand Down Expand Up @@ -72,6 +79,7 @@ export function setLocationToCurrent (payload) {
export function switchLocations () {
return function (dispatch, getState) {
const { from, to } = getState().otp.currentQuery
// First, reverse the locations.
dispatch(settingLocation({
type: 'from',
location: to
Expand All @@ -80,6 +88,8 @@ export function switchLocations () {
type: 'to',
location: from
}))
// Then kick off a routing query (if the query is invalid, search will abort).
dispatch(routingQuery())
}
}

Expand Down
10 changes: 6 additions & 4 deletions lib/components/form/plan-trip-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ class PlanTripButton extends Component {
profileTrip: PropTypes.func
}

static defaultProps = {
disabled: false
}

_onClick = () => {
this.props.routingQuery()
if (typeof this.props.onClick === 'function') this.props.onClick()
Expand All @@ -23,10 +27,8 @@ class PlanTripButton extends Component {

render () {
const { currentQuery, text } = this.props
const disabled = this.props.disabled === undefined
? !currentQuery.from || !currentQuery.to
: this.props.disabled

const locationMissing = !currentQuery.from || !currentQuery.to
const disabled = locationMissing || this.props.disabled
return (
<Button
className='plan-trip-button'
Expand Down
14 changes: 9 additions & 5 deletions lib/components/form/settings-selector-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,20 +263,21 @@ class SettingsSelectorPanel extends Component {
const {config, mode, icons} = this.props
const {exclusiveModes} = config.modes
const modeHasTransit = hasTransit(mode)

// Use int for array element keys
let key = 0
if (!exclusiveModes) return null

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

exclusiveModes.forEach((exclusiveMode, idx) => {
// add left padding for every evenly indexed exclusiveMode
if (idx % 2 === 0) {
children.push(spacer)
children.push(spacer())
}

switch (exclusiveMode) {
Expand All @@ -285,6 +286,7 @@ class SettingsSelectorPanel extends Component {
<Col xs={4}>
<ModeButton
enabled
key={key++}
active={mode === 'WALK'}
icons={icons}
mode={'WALK'}
Expand All @@ -301,6 +303,7 @@ class SettingsSelectorPanel extends Component {
<Col xs={4}>
<ModeButton
enabled
key={key++}
active={!modeHasTransit && hasBike(mode)}
icons={icons}
mode={'BICYCLE'}
Expand All @@ -317,6 +320,7 @@ class SettingsSelectorPanel extends Component {
<Col xs={4}>
<ModeButton
enabled
key={key++}
active={!modeHasTransit && hasMicromobility(mode)}
icons={icons}
mode={'MICROMOBILITY'}
Expand All @@ -334,7 +338,7 @@ class SettingsSelectorPanel extends Component {

// add right padding for every odd indexed exclusiveMode
if (idx % 2 !== 0) {
children.push(spacer)
children.push(spacer())
}
})

Expand Down
2 changes: 0 additions & 2 deletions lib/components/map/map.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,13 @@
/*** Car Rental Map Icons ***/

.otp .car-rental-icon {
color: gray;
font-size: 18px;
text-align: center;
}

/*** Micromobility Rental Map Icons ***/

.otp .micromobility-rental-icon {
color: gray;
font-size: 18px;
text-align: center;
}
Expand Down
25 changes: 19 additions & 6 deletions lib/components/map/route-viewer-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@ import React from 'react'
import { connect } from 'react-redux'
import { FeatureGroup, MapLayer, Polyline } from 'react-leaflet'

function geomToArray (point) {
return [point.lat, point.lon]
import polyline from '@mapbox/polyline'

// helper fn to check if geometry has been populated for all patterns in route
const isGeomComplete = routeData => {
return (
routeData &&
routeData.patterns &&
Object.values(routeData.patterns)
.every(ptn => typeof ptn.geometry !== 'undefined')
)
}

class RouteViewerOverlay extends MapLayer {
Expand All @@ -16,9 +24,14 @@ class RouteViewerOverlay extends MapLayer {

componentWillReceiveProps (nextProps) {
// if pattern geometry just finished populating, update the map points
if (nextProps.routeData && nextProps.routeData.patterns && Object.keys(nextProps.routeData.patterns).length > 0) {
if (
!isGeomComplete(this.props.routeData) &&
isGeomComplete(nextProps.routeData)
) {
const allPoints = Object.values(nextProps.routeData.patterns).reduce(
(acc, ptn) => acc.concat(ptn.geometry.map(geomToArray)),
(acc, ptn) => {
return acc.concat(polyline.decode(ptn.geometry.points))
},
[]
)
this.context.map.fitBounds(allPoints)
Expand All @@ -38,14 +51,14 @@ class RouteViewerOverlay extends MapLayer {
const segments = []
Object.values(routeData.patterns).forEach(pattern => {
if (!pattern.geometry) return
const pts = pattern.geometry.map(geomToArray)
const pts = polyline.decode(pattern.geometry.points)
segments.push(
<Polyline
positions={pts}
weight={4}
color={routeColor}
opacity={1}
key={pattern.patternId}
key={pattern.id}
/>
)
})
Expand Down
15 changes: 9 additions & 6 deletions lib/components/map/vehicle-rental-overlay.js
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,19 @@ class VehicleRentalOverlay extends MapLayer {

_renderStationAsMarker = (station, symbolDef) => {
const {baseIconClass} = this.props
let className = `fa fa-map-marker ${baseIconClass}`
let classes = `fa fa-map-marker ${baseIconClass}`
// If this station is exclusive to a single network, apply the the class for that network
if (station.networks.length === 1) {
className += ` ${baseIconClass}-${station.networks[0].toLowerCase()}`
classes += ` ${baseIconClass}-${station.networks[0].toLowerCase()}`
}
const color = symbolDef && symbolDef.fillColor
? symbolDef.fillColor
: 'gray'
const markerIcon = divIcon({
className: '',
iconSize: [11, 16],
popupAnchor: [0, -6],
html: '<i />',
className
html: `<i class="${classes}" style="color: ${color}"/>`
})

return (
Expand Down Expand Up @@ -211,8 +214,8 @@ class VehicleRentalOverlay extends MapLayer {
}

render () {
const { stations, companies } = this.props

const { mapSymbols, stations, companies } = this.props
if (!mapSymbols) console.warn(`No map symbols provided for layer ${this.props.name}`, companies)
let filteredStations = stations
if (companies) {
filteredStations = stations.filter(
Expand Down
3 changes: 3 additions & 0 deletions lib/components/narrative/default/access-leg.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import { distanceString } from '../../../util/distance'
import { getStepInstructions } from '../../../util/itinerary'
import { formatDuration } from '../../../util/time'

/**
* Default access leg component for narrative itinerary.
*/
export default class AccessLeg extends Component {
static propTypes = {
activeStep: PropTypes.number,
Expand Down
2 changes: 1 addition & 1 deletion lib/components/narrative/itinerary-carousel.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class ItineraryCarousel extends Component {

render () {
const { activeItinerary, itineraries, itineraryClass, hideHeader, pending, showProfileSummary } = this.props
if (pending) return <Loading />
if (pending) return <Loading small />
if (!itineraries) return null

let views = []
Expand Down
42 changes: 35 additions & 7 deletions lib/components/narrative/line-itin/access-leg-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,23 @@ import currencyFormatter from 'currency-formatter'
import LegDiagramPreview from '../leg-diagram-preview'

import { distanceString } from '../../../util/distance'
import { getLegModeLabel, getLegIcon, getPlaceName, getStepDirection, getStepStreetName } from '../../../util/itinerary'
import {
getLegModeLabel,
getLegIcon,
getPlaceName,
getStepDirection,
getStepStreetName
} from '../../../util/itinerary'
import { formatDuration, formatTime } from '../../../util/time'
import { isMobile } from '../../../util/ui'

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

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

render () {
const { customIcons, followsTransit, leg, timeOptions } = this.props
const { config, customIcons, followsTransit, leg, timeOptions } = this.props

if (leg.mode === 'CAR' && leg.hailedCar) {
return <TNCLeg leg={leg} onSummaryClick={this._onSummaryClick} timeOptions={timeOptions} followsTransit={followsTransit} customIcons={customIcons} />
return (
<TNCLeg
config={config}
leg={leg}
onSummaryClick={this._onSummaryClick}
timeOptions={timeOptions}
followsTransit={followsTransit}
customIcons={customIcons} />
)
}

return (
<div className='leg-body'>
<AccessLegSummary leg={leg} onSummaryClick={this._onSummaryClick} customIcons={customIcons} />
<AccessLegSummary
config={config}
leg={leg}
onSummaryClick={this._onSummaryClick}
customIcons={customIcons} />

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

<div className='leg-body'>
{/* The icon/summary row */}
<AccessLegSummary leg={leg} onSummaryClick={this.props.onSummaryClick} customIcons={customIcons} />
<AccessLegSummary
config={config}
leg={leg}
onSummaryClick={this.props.onSummaryClick}
customIcons={customIcons} />

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

class AccessLegSummary extends Component {
render () {
const { customIcons, leg } = this.props
const { config, customIcons, leg } = this.props
return (
<div className='summary leg-description' onClick={this.props.onSummaryClick}>
{/* Mode-specific icon */}
Expand All @@ -136,7 +164,7 @@ class AccessLegSummary extends Component {
{getLegModeLabel(leg)}
{' '}
{leg.distance && <span> {distanceString(leg.distance)}</span>}
{` to ${getPlaceName(leg.to)}`}
{` to ${getPlaceName(leg.to, config.companies)}`}
</div>
</div>
)
Expand Down
1 change: 0 additions & 1 deletion lib/components/narrative/line-itin/itin-body.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export default class ItineraryBody extends Component {
place={leg.from}
time={leg.startTime}
leg={leg}
previousLeg={i > 0 ? itinerary.legs[i - 1] : null}
legIndex={i}
followsTransit={followsTransit}
{...this.props}
Expand Down
14 changes: 12 additions & 2 deletions lib/components/narrative/line-itin/line-itinerary.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,19 @@ export default class LineItinerary extends NarrativeItinerary {

return (
<div className='line-itin'>
<ItinerarySummary companies={companies} itinerary={itinerary} timeOptions={timeOptions} onClick={onClick} customIcons={customIcons} />
<ItinerarySummary
companies={companies}
itinerary={itinerary}
timeOptions={timeOptions}
onClick={onClick}
customIcons={customIcons} />
{showRealtimeAnnotation && <SimpleRealtimeAnnotation />}
{active || expanded ? <ItineraryBody {...this.props} itinerary={itinerary} timeOptions={timeOptions} /> : null}
{active || expanded
? <ItineraryBody
{...this.props}
itinerary={itinerary}
timeOptions={timeOptions} />
: null}
{itineraryFooter}
</div>
)
Expand Down
Loading

0 comments on commit 21f2e52

Please sign in to comment.