Date: Thu, 25 Mar 2021 10:43:27 -0400
Subject: [PATCH 22/48] refactor(NarrativeItineraries): Initialize component
with itin view URL param
---
lib/actions/ui.js | 43 +++++++++++--------
lib/components/mobile/batch-results-screen.js | 13 +++---
.../narrative/narrative-itineraries.js | 12 +++++-
3 files changed, 45 insertions(+), 23 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index c24a5a324..9be778ff8 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -8,8 +8,7 @@ import { setMapCenter, setMapZoom, setRouterId } from './config'
import {
clearActiveSearch,
parseUrlQueryString,
- setActiveSearch,
- settingQueryParam
+ setActiveSearch
} from './form'
import { clearLocation } from './map'
import { setActiveItinerary } from './narrative'
@@ -150,21 +149,6 @@ export function handleBackButtonPress (e) {
}
}
-/**
- * Sets the itinerary view state ('full', 'split', or 'hidden') in:
- * - the currentQuery otp redux state,
- * - in the URL params.
- */
-export function setItineraryView (value) {
- return function (dispatch, getState) {
- dispatch(settingQueryParam({ ui_itineraryView: value }))
-
- const urlParams = coreUtils.query.getUrlParams()
- urlParams.ui_itineraryView = value
- dispatch(setUrlSearch(urlParams))
- }
-}
-
export const setMobileScreen = createAction('SET_MOBILE_SCREEN')
/**
@@ -250,3 +234,28 @@ export const MobileScreens = {
SET_DATETIME: 7,
RESULTS_SUMMARY: 8
}
+
+export const ItineraryView = {
+ FULL: 'full',
+ HIDDEN: 'hidden',
+ SPLIT: 'split'
+}
+const DEFAULT_ITINERARY_VIEW = ItineraryView.SPLIT
+
+/**
+ * Sets the itinerary view state (see values above) in the URL params.
+ */
+export function setItineraryView (value) {
+ return function (dispatch, getState) {
+ const urlParams = coreUtils.query.getUrlParams()
+
+ // Set desired ui query param, or remove it if equal to default.
+ if (value !== DEFAULT_ITINERARY_VIEW) {
+ urlParams.ui_itineraryView = value
+ } else if (urlParams.ui_itineraryView) {
+ delete urlParams.ui_itineraryView
+ }
+
+ dispatch(setUrlSearch(urlParams))
+ }
+}
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index ff655e57e..b77d37ec0 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -40,10 +40,13 @@ const ExpandMapButton = styled(Button)`
z-index: 999999;
`
+const VIEW = uiActions.ItineraryView
+
const NARRATIVE_SPLIT_TOP_PERCENT = 45
/**
- * This component renders the mobile view of itinerary results from batch routing.
+ * This component renders the mobile view of itinerary results from batch routing,
+ * and features a split view between the map and itinerary results or narratives.
*/
class BatchMobileResultsScreen extends Component {
componentDidUpdate (prevProps) {
@@ -56,18 +59,18 @@ class BatchMobileResultsScreen extends Component {
}
_setItineraryExpanded = itineraryExpanded => {
- this.props.setItineraryView(itineraryExpanded ? 'full' : 'split')
+ this.props.setItineraryView(itineraryExpanded ? VIEW.FULL : VIEW.SPLIT)
}
_toggleMapExpanded = () => {
- this.props.setItineraryView(this.props.itineraryView === 'hidden' ? 'split' : 'hidden')
+ this.props.setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? VIEW.SPLIT : VIEW.HIDDEN)
}
render () {
const { errors, itineraries, itineraryView } = this.props
const hasNoResult = itineraries.length === 0 && errors.length > 0
- const mapExpanded = itineraryView === 'hidden'
- const itineraryExpanded = itineraryView === 'full'
+ const mapExpanded = itineraryView === VIEW.HIDDEN
+ const itineraryExpanded = itineraryView === VIEW.FULL
const narrativeTop = mapExpanded ? '100%' : (itineraryExpanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`)
const mapBottom = mapExpanded ? 0 : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index ce5377d3d..0dd79bbee 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -12,6 +12,7 @@ import {
setVisibleItinerary,
updateItineraryFilter
} from '../../actions/narrative'
+import { ItineraryView } from '../../actions/ui'
import Icon from '../narrative/icon'
import { ComponentContext } from '../../util/contexts'
import {
@@ -51,7 +52,13 @@ class NarrativeItineraries extends Component {
static contextType = ComponentContext
- state = {}
+ constructor (props) {
+ super(props)
+ this.state = {
+ // If URL indicates full (expanded) itinerary view, then show itinerary details.
+ showDetails: props.itineraryView === ItineraryView.FULL
+ }
+ }
_toggleDetailedItinerary = () => {
const showDetails = !this.state.showDetails
@@ -236,11 +243,14 @@ const mapStateToProps = (state, ownProps) => {
const itineraries = getActiveItineraries(state.otp)
const realtimeEffects = getRealtimeEffects(state.otp)
const useRealtime = state.otp.useRealtime
+ const urlParams = coreUtils.query.getUrlParams()
+
return {
activeSearch,
errors: getResponsesWithErrors(state.otp),
// swap out realtime itineraries with non-realtime depending on boolean
itineraries,
+ itineraryView: urlParams.ui_itineraryView,
pending,
realtimeEffects,
activeItinerary: activeSearch && activeSearch.activeItinerary,
From 2b77be64b4786442c0a334b1a825ab3e283730dc Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 25 Mar 2021 12:01:19 -0400
Subject: [PATCH 23/48] refactor(BoundsUpdatingOverlay): Reset transitive on
leg click from exp. itin
---
lib/actions/ui.js | 17 ++++----
lib/components/map/bounds-updating-overlay.js | 39 ++++++++++---------
2 files changed, 31 insertions(+), 25 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index 9be778ff8..0fdf329f9 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -249,13 +249,16 @@ export function setItineraryView (value) {
return function (dispatch, getState) {
const urlParams = coreUtils.query.getUrlParams()
- // Set desired ui query param, or remove it if equal to default.
- if (value !== DEFAULT_ITINERARY_VIEW) {
- urlParams.ui_itineraryView = value
- } else if (urlParams.ui_itineraryView) {
- delete urlParams.ui_itineraryView
- }
+ // If the itinerary value is changed,
+ // set the desired ui query param, or remove it if equal to default.
+ if (value !== urlParams.ui_itineraryView) {
+ if (value !== DEFAULT_ITINERARY_VIEW) {
+ urlParams.ui_itineraryView = value
+ } else if (urlParams.ui_itineraryView) {
+ delete urlParams.ui_itineraryView
+ }
- dispatch(setUrlSearch(urlParams))
+ dispatch(setUrlSearch(urlParams))
+ }
}
}
diff --git a/lib/components/map/bounds-updating-overlay.js b/lib/components/map/bounds-updating-overlay.js
index 48afe3f61..b12c8f24e 100644
--- a/lib/components/map/bounds-updating-overlay.js
+++ b/lib/components/map/bounds-updating-overlay.js
@@ -73,7 +73,27 @@ class BoundsUpdatingOverlay extends MapLayer {
// Also refit map if itineraryView prop has changed.
const itineraryViewChanged = oldProps.itineraryView !== newProps.itineraryView
- if (
+ if (itineraryViewChanged) {
+ // If itineraryView has changed,
+ // force a resize of the map before re-fitting the active itinerary or active leg,
+ // and do that after a delay to that canvas heights have stabilized in the DOM.
+ setTimeout(() => {
+ map.invalidateSize(true)
+
+ if (newProps.itinerary) {
+ if (newProps.activeLeg !== null) {
+ // Fit to active leg if set.
+ map.fitBounds(
+ getLeafletLegBounds(newProps.itinerary.legs[newProps.activeLeg]),
+ { padding }
+ )
+ } else {
+ // Fit to whole itinerary otherwise.
+ map.fitBounds(newItinBounds, { padding })
+ }
+ }
+ }, 250)
+ } else if (
(!oldItinBounds && newItinBounds) ||
(oldItinBounds && newItinBounds && !oldItinBounds.equals(newItinBounds))
) {
@@ -126,23 +146,6 @@ class BoundsUpdatingOverlay extends MapLayer {
const leg = newProps.itinerary.legs[newProps.activeLeg]
const step = leg.steps[newProps.activeStep]
map.panTo([step.lat, step.lon])
- } else if (itineraryViewChanged) {
- // If itineraryView has changed,
- // force a resize of the map before re-fitting the active itinerary or active leg.
- map.invalidateSize(true)
-
- if (newProps.itinerary) {
- if (newProps.activeLeg !== null) {
- // Fit to active leg if set.
- map.fitBounds(
- getLeafletLegBounds(newProps.itinerary.legs[newProps.activeLeg]),
- { padding }
- )
- } else {
- // Fit to whole itinerary otherwise.
- map.fitBounds(newItinBounds, { padding })
- }
- }
}
}
}
From ef9554794272cbac5b73c75772e39dd69e674315 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 25 Mar 2021 12:12:40 -0400
Subject: [PATCH 24/48] refactor(BoundsUpdatingOverlay): Fix lint
---
lib/components/map/bounds-updating-overlay.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/components/map/bounds-updating-overlay.js b/lib/components/map/bounds-updating-overlay.js
index b12c8f24e..883b09493 100644
--- a/lib/components/map/bounds-updating-overlay.js
+++ b/lib/components/map/bounds-updating-overlay.js
@@ -77,7 +77,7 @@ class BoundsUpdatingOverlay extends MapLayer {
// If itineraryView has changed,
// force a resize of the map before re-fitting the active itinerary or active leg,
// and do that after a delay to that canvas heights have stabilized in the DOM.
- setTimeout(() => {
+ setTimeout(() => {
map.invalidateSize(true)
if (newProps.itinerary) {
From 794aeafcdf59f7ea394a00aac565daa4e7a9b2f0 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 10:37:48 -0400
Subject: [PATCH 25/48] docs: Update comments from PR reviews.
---
lib/actions/ui.js | 9 +++++++--
lib/components/map/bounds-updating-overlay.js | 2 +-
lib/components/map/map.js | 2 +-
3 files changed, 9 insertions(+), 4 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index 0fdf329f9..f9c591f9a 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -235,6 +235,10 @@ export const MobileScreens = {
RESULTS_SUMMARY: 8
}
+/**
+ * Enum to describe the layout of the itinerary view
+ * (currently only used in mobile batch results).
+ */
export const ItineraryView = {
FULL: 'full',
HIDDEN: 'hidden',
@@ -243,14 +247,15 @@ export const ItineraryView = {
const DEFAULT_ITINERARY_VIEW = ItineraryView.SPLIT
/**
- * Sets the itinerary view state (see values above) in the URL params.
+ * Sets the itinerary view state (see values above) in the URL params
+ * (currently only used in mobile batch results).
*/
export function setItineraryView (value) {
return function (dispatch, getState) {
const urlParams = coreUtils.query.getUrlParams()
// If the itinerary value is changed,
- // set the desired ui query param, or remove it if equal to default.
+ // set the desired ui query param, or remove it if same as default.
if (value !== urlParams.ui_itineraryView) {
if (value !== DEFAULT_ITINERARY_VIEW) {
urlParams.ui_itineraryView = value
diff --git a/lib/components/map/bounds-updating-overlay.js b/lib/components/map/bounds-updating-overlay.js
index 883b09493..722a7fd9a 100644
--- a/lib/components/map/bounds-updating-overlay.js
+++ b/lib/components/map/bounds-updating-overlay.js
@@ -76,7 +76,7 @@ class BoundsUpdatingOverlay extends MapLayer {
if (itineraryViewChanged) {
// If itineraryView has changed,
// force a resize of the map before re-fitting the active itinerary or active leg,
- // and do that after a delay to that canvas heights have stabilized in the DOM.
+ // and do that after a delay to ensure that canvas heights have stabilized in the DOM.
setTimeout(() => {
map.invalidateSize(true)
diff --git a/lib/components/map/map.js b/lib/components/map/map.js
index 4edf47a0e..c3474437d 100644
--- a/lib/components/map/map.js
+++ b/lib/components/map/map.js
@@ -14,7 +14,7 @@ class Map extends Component {
}
}
- getComponentForView = view => {
+ getComponentForView (view) {
// TODO: allow a 'CUSTOM' type
switch (view.type) {
case 'DEFAULT': return
From b1ab768e30ed011781d6ab4c4174a6ad746949d0 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 11:45:04 -0400
Subject: [PATCH 26/48] refactor(BoundsUpdatingOverlay): Revert block regarding
#133.
---
lib/components/map/bounds-updating-overlay.js | 36 ++++++++++++-------
1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/lib/components/map/bounds-updating-overlay.js b/lib/components/map/bounds-updating-overlay.js
index 722a7fd9a..b77dc6a44 100644
--- a/lib/components/map/bounds-updating-overlay.js
+++ b/lib/components/map/bounds-updating-overlay.js
@@ -111,19 +111,29 @@ class BoundsUpdatingOverlay extends MapLayer {
// If no itinerary update but from/to locations are present, fit to those
} else if (newFrom && newTo && (fromChanged || toChanged)) {
- const bounds = L.bounds([
- [newFrom.lat, newFrom.lon],
- [newTo.lat, newTo.lon]
- ])
- // Ensure bounds extend to include intermediatePlaces
- extendBoundsByPlaces(bounds, newIntermediate)
- const { x: left, y: bottom } = bounds.getBottomLeft()
- const { x: right, y: top } = bounds.getTopRight()
- map.fitBounds([
- [left, bottom],
- [right, top]
- ], { padding })
-
+ // On certain mobile devices (e.g., Android + Chrome), setting from and to
+ // locations via the location search component causes issues for this
+ // fitBounds invocation. The map does not appear to be visible when these
+ // prop changes are detected, so for now we should perhaps just skip this
+ // fitBounds on mobile.
+ // See https://github.com/opentripplanner/otp-react-redux/issues/133 for
+ // more info.
+ // TODO: Fix this so mobile devices will also update the bounds to the
+ // from/to locations.
+ if (!coreUtils.ui.isMobile()) {
+ const bounds = L.bounds([
+ [newFrom.lat, newFrom.lon],
+ [newTo.lat, newTo.lon]
+ ])
+ // Ensure bounds extend to include intermediatePlaces
+ extendBoundsByPlaces(bounds, newIntermediate)
+ const { x: left, y: bottom } = bounds.getBottomLeft()
+ const { x: right, y: top } = bounds.getTopRight()
+ map.fitBounds([
+ [left, bottom],
+ [right, top]
+ ], { padding })
+ }
// If only from or to is set, pan to that
} else if (newFrom && fromChanged) {
map.panTo([newFrom.lat, newFrom.lon])
From b738bd20222e0614ab23025d94634b769981bac7 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 13:04:37 -0400
Subject: [PATCH 27/48] refactor(BoundsUpdatingOverlay): Move code per PR
comment
---
lib/components/map/bounds-updating-overlay.js | 54 ++++++++++---------
1 file changed, 30 insertions(+), 24 deletions(-)
diff --git a/lib/components/map/bounds-updating-overlay.js b/lib/components/map/bounds-updating-overlay.js
index b77dc6a44..4ba59ab06 100644
--- a/lib/components/map/bounds-updating-overlay.js
+++ b/lib/components/map/bounds-updating-overlay.js
@@ -22,6 +22,9 @@ function extendBoundsByPlaces (bounds, places = []) {
})
}
+/** Padding around itinerary bounds and map bounds. */
+const BOUNDS_PADDING = [30, 30]
+
/**
* This MapLayer component will automatically update the leaflet bounds
* depending on what data is in the redux store. This component does not
@@ -42,6 +45,29 @@ class BoundsUpdatingOverlay extends MapLayer {
componentWillUnmount () {}
+ _fitItineraryViewToMap (newProps, bounds, map) {
+ // If itineraryView has changed (currently: only in mobile batch results),
+ // force a resize of the map before re-fitting the active itinerary or active leg,
+ // and do that after a delay to ensure that canvas heights have stabilized in the DOM.
+ setTimeout(() => {
+ map.invalidateSize(true)
+
+ const { activeLeg, itinerary } = newProps
+ if (itinerary) {
+ if (activeLeg !== null) {
+ // Fit to active leg if set.
+ map.fitBounds(
+ getLeafletLegBounds(itinerary.legs[activeLeg]),
+ { ITINERARY_MAP_PADDING: BOUNDS_PADDING }
+ )
+ } else {
+ // Fit to whole itinerary otherwise.
+ map.fitBounds(bounds, { ITINERARY_MAP_PADDING: BOUNDS_PADDING })
+ }
+ }
+ }, 250)
+ }
+
/* eslint-disable-next-line complexity */
updateBounds (oldProps, newProps) {
// TODO: maybe setting bounds ought to be handled in map props...
@@ -55,8 +81,6 @@ class BoundsUpdatingOverlay extends MapLayer {
const { map } = newProps.leaflet
if (!map) return
- const padding = [30, 30]
-
// Fit map to to entire itinerary if active itinerary bounds changed
const newFrom = newProps.query && newProps.query.from
const newItinBounds = newProps.itinerary && getLeafletItineraryBounds(newProps.itinerary)
@@ -74,30 +98,12 @@ class BoundsUpdatingOverlay extends MapLayer {
const itineraryViewChanged = oldProps.itineraryView !== newProps.itineraryView
if (itineraryViewChanged) {
- // If itineraryView has changed,
- // force a resize of the map before re-fitting the active itinerary or active leg,
- // and do that after a delay to ensure that canvas heights have stabilized in the DOM.
- setTimeout(() => {
- map.invalidateSize(true)
-
- if (newProps.itinerary) {
- if (newProps.activeLeg !== null) {
- // Fit to active leg if set.
- map.fitBounds(
- getLeafletLegBounds(newProps.itinerary.legs[newProps.activeLeg]),
- { padding }
- )
- } else {
- // Fit to whole itinerary otherwise.
- map.fitBounds(newItinBounds, { padding })
- }
- }
- }, 250)
+ this._fitItineraryViewToMap(newProps, newItinBounds, map)
} else if (
(!oldItinBounds && newItinBounds) ||
(oldItinBounds && newItinBounds && !oldItinBounds.equals(newItinBounds))
) {
- map.fitBounds(newItinBounds, { padding })
+ map.fitBounds(newItinBounds, { padding: BOUNDS_PADDING })
// Pan to to itinerary leg if made active (clicked); newly active leg must be non-null
} else if (
newProps.itinerary &&
@@ -106,7 +112,7 @@ class BoundsUpdatingOverlay extends MapLayer {
) {
map.fitBounds(
getLeafletLegBounds(newProps.itinerary.legs[newProps.activeLeg]),
- { padding }
+ { padding: BOUNDS_PADDING }
)
// If no itinerary update but from/to locations are present, fit to those
@@ -132,7 +138,7 @@ class BoundsUpdatingOverlay extends MapLayer {
map.fitBounds([
[left, bottom],
[right, top]
- ], { padding })
+ ], { padding: BOUNDS_PADDING })
}
// If only from or to is set, pan to that
} else if (newFrom && fromChanged) {
From 19f056929e4f8ee17fadc8f1ac3c795ee29f3878 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 13:07:24 -0400
Subject: [PATCH 28/48] refactor(BatchResultsScreen): Replace showDetails state
with itineraryView redux state.
---
lib/actions/ui.js | 4 +--
lib/components/mobile/batch-results-screen.js | 1 -
.../narrative/narrative-itineraries.js | 28 ++++++-------------
3 files changed, 11 insertions(+), 22 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index f9c591f9a..a80f44239 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -237,7 +237,7 @@ export const MobileScreens = {
/**
* Enum to describe the layout of the itinerary view
- * (currently only used in mobile batch results).
+ * (currently only used in batch results).
*/
export const ItineraryView = {
FULL: 'full',
@@ -248,7 +248,7 @@ const DEFAULT_ITINERARY_VIEW = ItineraryView.SPLIT
/**
* Sets the itinerary view state (see values above) in the URL params
- * (currently only used in mobile batch results).
+ * (currently only used in batch results).
*/
export function setItineraryView (value) {
return function (dispatch, getState) {
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index b77d37ec0..e49f8d631 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -111,7 +111,6 @@ class BatchMobileResultsScreen extends Component {
height: '100%',
width: '100%'
}}
- onToggleDetailedItinerary={this._setItineraryExpanded}
/>
)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 0dd79bbee..c61edce1a 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -12,7 +12,7 @@ import {
setVisibleItinerary,
updateItineraryFilter
} from '../../actions/narrative'
-import { ItineraryView } from '../../actions/ui'
+import { ItineraryView, setItineraryView } from '../../actions/ui'
import Icon from '../narrative/icon'
import { ComponentContext } from '../../util/contexts'
import {
@@ -41,33 +41,20 @@ class NarrativeItineraries extends Component {
activeItinerary: PropTypes.number,
containerStyle: PropTypes.object,
itineraries: PropTypes.array,
- onToggleDetailedItinerary: PropTypes.func,
pending: PropTypes.bool,
setActiveItinerary: PropTypes.func,
setActiveLeg: PropTypes.func,
setActiveStep: PropTypes.func,
+ setItineraryView: PropTypes.func,
setUseRealtimeResponse: PropTypes.func,
useRealtime: PropTypes.bool
}
static contextType = ComponentContext
- constructor (props) {
- super(props)
- this.state = {
- // If URL indicates full (expanded) itinerary view, then show itinerary details.
- showDetails: props.itineraryView === ItineraryView.FULL
- }
- }
-
_toggleDetailedItinerary = () => {
- const showDetails = !this.state.showDetails
- this.setState({ showDetails })
-
- const { onToggleDetailedItinerary } = this.props
- if (onToggleDetailedItinerary) {
- onToggleDetailedItinerary(showDetails)
- }
+ const { itineraryView, setItineraryView } = this.props
+ setItineraryView(itineraryView === ItineraryView.FULL ? ItineraryView.SPLIT : ItineraryView.FULL)
}
_onFilterChange = evt => {
@@ -118,6 +105,7 @@ class NarrativeItineraries extends Component {
containerStyle,
errors,
itineraries,
+ itineraryView,
pending,
realtimeEffects,
sort,
@@ -126,7 +114,8 @@ class NarrativeItineraries extends Component {
const { ItineraryBody, LegIcon } = this.context
if (!activeSearch) return null
- const itineraryIsExpanded = activeItinerary !== undefined && activeItinerary !== null && this.state.showDetails
+ const showDetails = itineraryView === ItineraryView.FULL
+ const itineraryIsExpanded = activeItinerary !== undefined && activeItinerary !== null && showDetails
const showRealtimeAnnotation = realtimeEffects.isAffectedByRealtimeData && (
realtimeEffects.exceedsThreshold ||
@@ -199,7 +188,7 @@ class NarrativeItineraries extends Component {
return (
{
setActiveStep: (index, step) => {
dispatch(setActiveStep({index, step}))
},
+ setItineraryView: payload => dispatch(setItineraryView(payload)),
setUseRealtimeResponse: payload => dispatch(setUseRealtimeResponse(payload)),
setVisibleItinerary: payload => dispatch(setVisibleItinerary(payload)),
updateItineraryFilter: payload => dispatch(updateItineraryFilter(payload))
From 7c82cd75c4bfd45860644e82e9371b260019d75e Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 13:10:00 -0400
Subject: [PATCH 29/48] refactor(actions/ui): Rename ItineraryView.SPLIT>LIST
---
lib/actions/ui.js | 4 ++--
lib/components/narrative/narrative-itineraries.js | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index a80f44239..ae0d9fe61 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -242,9 +242,9 @@ export const MobileScreens = {
export const ItineraryView = {
FULL: 'full',
HIDDEN: 'hidden',
- SPLIT: 'split'
+ LIST: 'list'
}
-const DEFAULT_ITINERARY_VIEW = ItineraryView.SPLIT
+const DEFAULT_ITINERARY_VIEW = ItineraryView.LIST
/**
* Sets the itinerary view state (see values above) in the URL params
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index c61edce1a..d6eef1d72 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -54,7 +54,7 @@ class NarrativeItineraries extends Component {
_toggleDetailedItinerary = () => {
const { itineraryView, setItineraryView } = this.props
- setItineraryView(itineraryView === ItineraryView.FULL ? ItineraryView.SPLIT : ItineraryView.FULL)
+ setItineraryView(itineraryView === ItineraryView.FULL ? ItineraryView.LIST : ItineraryView.FULL)
}
_onFilterChange = evt => {
From d0a4f3531f62c34c9fad61e26e6a02c1b3e287fc Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 15:07:15 -0400
Subject: [PATCH 30/48] refactor(BatchResultsScreen): Add uncommited refactors
from 7c82cd7
---
lib/components/mobile/batch-results-screen.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index e49f8d631..036fe4895 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -59,11 +59,11 @@ class BatchMobileResultsScreen extends Component {
}
_setItineraryExpanded = itineraryExpanded => {
- this.props.setItineraryView(itineraryExpanded ? VIEW.FULL : VIEW.SPLIT)
+ this.props.setItineraryView(itineraryExpanded ? VIEW.FULL : VIEW.LIST)
}
_toggleMapExpanded = () => {
- this.props.setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? VIEW.SPLIT : VIEW.HIDDEN)
+ this.props.setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? VIEW.LIST : VIEW.HIDDEN)
}
render () {
From df927a8f852ee3ec599d8f14bdd44406cf9376af Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 30 Mar 2021 16:05:30 -0400
Subject: [PATCH 31/48] refactor(mobile/ResultsHeader): Reset itineraryView
state when clicking Edit.
---
lib/components/mobile/results-header.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/components/mobile/results-header.js b/lib/components/mobile/results-header.js
index 9c498da3d..588982134 100644
--- a/lib/components/mobile/results-header.js
+++ b/lib/components/mobile/results-header.js
@@ -59,6 +59,7 @@ class ResultsHeader extends Component {
_editSearchClicked = () => {
this.props.clearActiveSearch()
this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
+ this.props.setItineraryView(uiActions.ItineraryView.LIST)
}
render () {
@@ -119,6 +120,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = {
clearActiveSearch: formActions.clearActiveSearch,
+ setItineraryView: uiActions.setItineraryView,
setMobileScreen: uiActions.setMobileScreen
}
From 7678132763b027dc21ff3d7784230b7fe5577913 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 31 Mar 2021 11:37:29 -0400
Subject: [PATCH 32/48] refactor(NarrativeItineraries): Toggle focus between
leg and itinerary when clicking leg.
---
lib/actions/ui.js | 5 +--
lib/components/map/bounds-updating-overlay.js | 2 +-
lib/components/mobile/batch-results-screen.js | 18 ++++------
lib/components/mobile/results-header.js | 1 +
.../narrative/narrative-itineraries.js | 35 +++++++++++++++----
5 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index ae0d9fe61..f3463eb49 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -240,11 +240,12 @@ export const MobileScreens = {
* (currently only used in batch results).
*/
export const ItineraryView = {
+ DEFAULT: 'list',
FULL: 'full',
HIDDEN: 'hidden',
+ LEG: 'leg',
LIST: 'list'
}
-const DEFAULT_ITINERARY_VIEW = ItineraryView.LIST
/**
* Sets the itinerary view state (see values above) in the URL params
@@ -257,7 +258,7 @@ export function setItineraryView (value) {
// If the itinerary value is changed,
// set the desired ui query param, or remove it if same as default.
if (value !== urlParams.ui_itineraryView) {
- if (value !== DEFAULT_ITINERARY_VIEW) {
+ if (value !== ItineraryView.DEFAULT) {
urlParams.ui_itineraryView = value
} else if (urlParams.ui_itineraryView) {
delete urlParams.ui_itineraryView
diff --git a/lib/components/map/bounds-updating-overlay.js b/lib/components/map/bounds-updating-overlay.js
index 4ba59ab06..e4ce308e6 100644
--- a/lib/components/map/bounds-updating-overlay.js
+++ b/lib/components/map/bounds-updating-overlay.js
@@ -125,7 +125,7 @@ class BoundsUpdatingOverlay extends MapLayer {
// See https://github.com/opentripplanner/otp-react-redux/issues/133 for
// more info.
// TODO: Fix this so mobile devices will also update the bounds to the
- // from/to locations.
+ // from/to locations.
if (!coreUtils.ui.isMobile()) {
const bounds = L.bounds([
[newFrom.lat, newFrom.lon],
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index 036fe4895..58f68c81b 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -49,21 +49,17 @@ const NARRATIVE_SPLIT_TOP_PERCENT = 45
* and features a split view between the map and itinerary results or narratives.
*/
class BatchMobileResultsScreen extends Component {
- componentDidUpdate (prevProps) {
- if (this.props.activeLeg !== prevProps.activeLeg) {
- // Check if the active leg has changed. If a different leg is selected,
- // unexpand the itinerary to show the map focused on the selected leg
- // (similar to the behavior of LineItinerary).
- this._setItineraryExpanded(false)
- }
+ state = {
+ previousItineraryView: null
}
- _setItineraryExpanded = itineraryExpanded => {
- this.props.setItineraryView(itineraryExpanded ? VIEW.FULL : VIEW.LIST)
+ _setItineraryView = view => {
+ this.setState({ previousItineraryView: this.props.itineraryView })
+ this.props.setItineraryView(view)
}
_toggleMapExpanded = () => {
- this.props.setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? VIEW.LIST : VIEW.HIDDEN)
+ this._setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? this.state.previousItineraryView : VIEW.HIDDEN)
}
render () {
@@ -130,7 +126,7 @@ const mapStateToProps = (state, ownProps) => {
activeLeg: activeSearch ? activeSearch.activeLeg : null,
errors: getResponsesWithErrors(state.otp),
itineraries: getActiveItineraries(state.otp),
- itineraryView: urlParams.ui_itineraryView
+ itineraryView: urlParams.ui_itineraryView || VIEW.DEFAULT
}
}
diff --git a/lib/components/mobile/results-header.js b/lib/components/mobile/results-header.js
index 588982134..b615e007c 100644
--- a/lib/components/mobile/results-header.js
+++ b/lib/components/mobile/results-header.js
@@ -59,6 +59,7 @@ class ResultsHeader extends Component {
_editSearchClicked = () => {
this.props.clearActiveSearch()
this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
+ // Reset itinerary view state to show the list of results.
this.props.setItineraryView(uiActions.ItineraryView.LIST)
}
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index d6eef1d72..d2e7fd9e9 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -52,9 +52,32 @@ class NarrativeItineraries extends Component {
static contextType = ComponentContext
+ _setActiveLeg = (index, leg) => {
+ const { activeLeg, setActiveLeg, setItineraryView } = this.props
+ const isSameLeg = activeLeg === index
+ if (isSameLeg) {
+ // If clicking on the same leg again, reset it to null,
+ // and show the full itinerary (both desktop and mobile view)
+ setActiveLeg(null, null)
+ setItineraryView(ItineraryView.FULL)
+ } else {
+ // Focus on the newly selected leg.
+ setActiveLeg(index, leg)
+ setItineraryView(ItineraryView.LEG)
+ }
+ }
+
+ _isShowingDetails = () => {
+ const { itineraryView } = this.props
+ return itineraryView === ItineraryView.FULL || itineraryView === ItineraryView.LEG
+ }
+
_toggleDetailedItinerary = () => {
- const { itineraryView, setItineraryView } = this.props
- setItineraryView(itineraryView === ItineraryView.FULL ? ItineraryView.LIST : ItineraryView.FULL)
+ const { setActiveLeg, setItineraryView } = this.props
+ const newView = this._isShowingDetails() ? ItineraryView.LIST : ItineraryView.FULL
+ setItineraryView(newView)
+ // Reset the active leg.
+ setActiveLeg(null, null)
}
_onFilterChange = evt => {
@@ -105,7 +128,6 @@ class NarrativeItineraries extends Component {
containerStyle,
errors,
itineraries,
- itineraryView,
pending,
realtimeEffects,
sort,
@@ -114,7 +136,7 @@ class NarrativeItineraries extends Component {
const { ItineraryBody, LegIcon } = this.context
if (!activeSearch) return null
- const showDetails = itineraryView === ItineraryView.FULL
+ const showDetails = this._isShowingDetails()
const itineraryIsExpanded = activeItinerary !== undefined && activeItinerary !== null && showDetails
const showRealtimeAnnotation = realtimeEffects.isAffectedByRealtimeData && (
@@ -193,12 +215,13 @@ class NarrativeItineraries extends Component {
itinerary={itinerary}
key={index}
LegIcon={LegIcon}
- setActiveLeg={setActiveLeg}
onClick={active ? this._toggleDetailedItinerary : undefined}
routingType='ITINERARY'
showRealtimeAnnotation={showRealtimeAnnotation}
sort={sort}
{...this.props}
+ // Override setActiveLeg from props spreading
+ setActiveLeg={this._setActiveLeg}
/>
)
})}
@@ -239,7 +262,7 @@ const mapStateToProps = (state, ownProps) => {
errors: getResponsesWithErrors(state.otp),
// swap out realtime itineraries with non-realtime depending on boolean
itineraries,
- itineraryView: urlParams.ui_itineraryView,
+ itineraryView: urlParams.ui_itineraryView || ItineraryView.DEFAULT,
pending,
realtimeEffects,
activeItinerary: activeSearch && activeSearch.activeItinerary,
From dffebbf445cca179f9b2043ab56cc499d05a330a Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 31 Mar 2021 11:49:42 -0400
Subject: [PATCH 33/48] refactor(NarrativeItineraries): Fix lint
---
lib/components/narrative/narrative-itineraries.js | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index d2e7fd9e9..77738aa27 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -207,6 +207,11 @@ class NarrativeItineraries extends Component {
const active = index === activeItinerary
// Hide non-active itineraries.
if (!active && itineraryIsExpanded) return null
+ const itineraryBodyProps = {
+ ...this.props,
+ // Override setActiveLeg from props spreading
+ setActiveLeg: this._setActiveLeg
+ }
return (
)
})}
From 77bfc8f678830e18fa9ed828d9d6e6652969747a Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Wed, 31 Mar 2021 15:28:49 -0400
Subject: [PATCH 34/48] refactor(mobile/results-screen): Convert options header
into button+styles.
---
lib/components/mobile/mobile.css | 1 -
lib/components/mobile/results-screen.js | 19 +++++++++++++++----
2 files changed, 15 insertions(+), 5 deletions(-)
diff --git a/lib/components/mobile/mobile.css b/lib/components/mobile/mobile.css
index 1e6475c6e..4b5409dc8 100644
--- a/lib/components/mobile/mobile.css
+++ b/lib/components/mobile/mobile.css
@@ -159,7 +159,6 @@
text-align: center;
font-size: 20px;
font-weight: 500;
- padding-top: 5px;
}
.otp.mobile .mobile-narrative-container {
diff --git a/lib/components/mobile/results-screen.js b/lib/components/mobile/results-screen.js
index 9ff918b83..d2e20518e 100644
--- a/lib/components/mobile/results-screen.js
+++ b/lib/components/mobile/results-screen.js
@@ -2,6 +2,7 @@ import coreUtils from '@opentripplanner/core-utils'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { connect } from 'react-redux'
+import styled from 'styled-components'
import * as narrativeActions from '../../actions/narrative'
import Map from '../map/map'
@@ -17,6 +18,16 @@ import MobileContainer from './container'
import ResultsError from './results-error'
import ResultsHeader from './results-header'
+const OptionExpanderButton = styled.button`
+ border: none;
+ bottom: ${props => props.expanded ? 'inherit' : '100px'};
+ outline: none;
+ padding-bottom: 3px;
+ display: block;
+ top: ${props => props.expanded ? '100px' : 'inherit'};
+ width: 100%;
+`
+
class MobileResultsScreen extends Component {
static propTypes = {
activeItineraryIndex: PropTypes.number,
@@ -113,14 +124,14 @@ class MobileResultsScreen extends Component {
?
: (
<>
-
- Option {activeItineraryIndex + 1}
+ Option {activeItineraryIndex + 1}
-
+
Date: Wed, 31 Mar 2021 16:11:11 -0400
Subject: [PATCH 35/48] refactor(mobile/ResultsError): Convert some components
to styled- per PR comments
---
lib/components/mobile/batch-results-screen.js | 39 ++++++++++++-------
lib/components/mobile/mobile.css | 1 -
lib/components/mobile/results-error.js | 11 ++++--
lib/components/mobile/results-screen.js | 26 ++++++-------
4 files changed, 47 insertions(+), 30 deletions(-)
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index 58f68c81b..5a82e1131 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -40,10 +40,26 @@ const ExpandMapButton = styled(Button)`
z-index: 999999;
`
-const VIEW = uiActions.ItineraryView
-
const NARRATIVE_SPLIT_TOP_PERCENT = 45
+// Styles for the results map also include prop-independent styles copied from mobile.css.
+const ResultsMap = styled.div`
+ bottom: ${props => props.expanded ? '0' : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`};
+ display: ${props => props.visible ? 'inherit' : 'none'};
+ left: 0;
+ position: fixed;
+ right: 0;
+ top: 100px;
+`
+
+const StyledResultsError = styled(ResultsError)`
+ display: ${props => props.visible ? 'inherit' : 'none'};
+ top: ${props => props.visible ? (props.expanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`) : '100%'};
+ transition: top 300ms;
+`
+
+const VIEW = uiActions.ItineraryView
+
/**
* This component renders the mobile view of itinerary results from batch routing,
* and features a split view between the map and itinerary results or narratives.
@@ -68,14 +84,13 @@ class BatchMobileResultsScreen extends Component {
const mapExpanded = itineraryView === VIEW.HIDDEN
const itineraryExpanded = itineraryView === VIEW.FULL
const narrativeTop = mapExpanded ? '100%' : (itineraryExpanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`)
- const mapBottom = mapExpanded ? 0 : `${100 - NARRATIVE_SPLIT_TOP_PERCENT}%`
return (
-
{' '}
{mapExpanded ? 'Show results' : 'Expand map'}
-
+
{hasNoResult
- ?
+ expanded={itineraryExpanded}
+ visible={!mapExpanded}
+ />
: (
+
{
@@ -52,4 +57,4 @@ const mapDispatchToProps = {
setMobileScreen: uiActions.setMobileScreen
}
-export default connect(mapStateToProps, mapDispatchToProps)(ResultsError)
+export default connect(mapStateToProps, mapDispatchToProps)(StyledResultsError)
diff --git a/lib/components/mobile/results-screen.js b/lib/components/mobile/results-screen.js
index d2e20518e..ece1501bc 100644
--- a/lib/components/mobile/results-screen.js
+++ b/lib/components/mobile/results-screen.js
@@ -18,7 +18,7 @@ import MobileContainer from './container'
import ResultsError from './results-error'
import ResultsHeader from './results-header'
-const OptionExpanderButton = styled.button`
+const OptionExpander = styled.button`
border: none;
bottom: ${props => props.expanded ? 'inherit' : '100px'};
outline: none;
@@ -28,6 +28,13 @@ const OptionExpanderButton = styled.button`
width: 100%;
`
+const NarrativeContainer = styled.div`
+ background-color: white;
+ ${props => props.expanded
+ ? 'top: 140px; overflow-y: auto;'
+ : 'height: 80px; overflow-y: hidden;'}
+`
+
class MobileResultsScreen extends Component {
static propTypes = {
activeItineraryIndex: PropTypes.number,
@@ -101,13 +108,6 @@ class MobileResultsScreen extends Component {
} = this.props
const { expanded } = this.state
- const narrativeContainerStyle = expanded
- ? { top: 140, overflowY: 'auto' }
- : { height: 80, overflowY: 'hidden' }
-
- // Ensure that narrative covers map.
- narrativeContainerStyle.backgroundColor = 'white'
-
const showRealtimeAnnotation = realtimeEffects.isAffectedByRealtimeData && (
realtimeEffects.exceedsThreshold ||
realtimeEffects.routesDiffer ||
@@ -124,19 +124,19 @@ class MobileResultsScreen extends Component {
?
: (
<>
-
Option {activeItineraryIndex + 1}
-
+
-
-
+
{this.renderDots()}
>
)
From 48bafb663209bf2e84d22b0c491709cba7c31919 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 1 Apr 2021 10:37:41 -0400
Subject: [PATCH 36/48] refactor: Address PR comments.
---
lib/components/mobile/batch-results-screen.js | 32 ++++++++++++-------
.../narrative/narrative-itineraries.js | 27 +++++++---------
2 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index 5a82e1131..6f6454af9 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -58,7 +58,10 @@ const StyledResultsError = styled(ResultsError)`
transition: top 300ms;
`
-const VIEW = uiActions.ItineraryView
+const NarrativeContainer = styled.div`
+`
+
+const { ItineraryView } = uiActions
/**
* This component renders the mobile view of itinerary results from batch routing,
@@ -66,23 +69,30 @@ const VIEW = uiActions.ItineraryView
*/
class BatchMobileResultsScreen extends Component {
state = {
- previousItineraryView: null
- }
-
- _setItineraryView = view => {
- this.setState({ previousItineraryView: this.props.itineraryView })
- this.props.setItineraryView(view)
+ // Holds the previous split view state
+ previousSplitView: null
}
+ /**
+ * Switch between full map view and the split state (itinerary list or itinerary leg view)
+ * that was in place prior.
+ */
_toggleMapExpanded = () => {
- this._setItineraryView(this.props.itineraryView === VIEW.HIDDEN ? this.state.previousItineraryView : VIEW.HIDDEN)
+ const { itineraryView, setItineraryView } = this.props
+
+ if (itineraryView !== ItineraryView.HIDDEN) {
+ this.setState({ previousSplitView: itineraryView })
+ setItineraryView(ItineraryView.HIDDEN)
+ } else {
+ setItineraryView(this.state.previousSplitView)
+ }
}
render () {
const { errors, itineraries, itineraryView } = this.props
const hasNoResult = itineraries.length === 0 && errors.length > 0
- const mapExpanded = itineraryView === VIEW.HIDDEN
- const itineraryExpanded = itineraryView === VIEW.FULL
+ const mapExpanded = itineraryView === ItineraryView.HIDDEN
+ const itineraryExpanded = itineraryView === ItineraryView.FULL
const narrativeTop = mapExpanded ? '100%' : (itineraryExpanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`)
return (
@@ -139,7 +149,7 @@ const mapStateToProps = (state, ownProps) => {
activeLeg: activeSearch ? activeSearch.activeLeg : null,
errors: getResponsesWithErrors(state.otp),
itineraries: getActiveItineraries(state.otp),
- itineraryView: urlParams.ui_itineraryView || VIEW.DEFAULT
+ itineraryView: urlParams.ui_itineraryView || ItineraryView.DEFAULT
}
}
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 77738aa27..465c2b45c 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -4,15 +4,8 @@ import PropTypes from 'prop-types'
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'
import { connect } from 'react-redux'
-import {
- setActiveItinerary,
- setActiveLeg,
- setActiveStep,
- setUseRealtimeResponse,
- setVisibleItinerary,
- updateItineraryFilter
-} from '../../actions/narrative'
-import { ItineraryView, setItineraryView } from '../../actions/ui'
+import * as narrativeActions from '../../actions/narrative'
+import * as uiActions from '../../actions/ui'
import Icon from '../narrative/icon'
import { ComponentContext } from '../../util/contexts'
import {
@@ -24,6 +17,8 @@ import {
import SaveTripButton from './save-trip-button'
+const { ItineraryView } = uiActions
+
// TODO: move to utils?
function humanReadableMode (modeStr) {
if (!modeStr) return 'N/A'
@@ -285,19 +280,19 @@ const mapDispatchToProps = (dispatch, ownProps) => {
// so that only one argument is passed,
// e.g. setActiveLeg({ index, leg })
return {
- setActiveItinerary: payload => dispatch(setActiveItinerary(payload)),
+ setActiveItinerary: payload => dispatch(narrativeActions.setActiveItinerary(payload)),
// FIXME
setActiveLeg: (index, leg) => {
- dispatch(setActiveLeg({index, leg}))
+ dispatch(narrativeActions.setActiveLeg({index, leg}))
},
// FIXME
setActiveStep: (index, step) => {
- dispatch(setActiveStep({index, step}))
+ dispatch(narrativeActions.setActiveStep({index, step}))
},
- setItineraryView: payload => dispatch(setItineraryView(payload)),
- setUseRealtimeResponse: payload => dispatch(setUseRealtimeResponse(payload)),
- setVisibleItinerary: payload => dispatch(setVisibleItinerary(payload)),
- updateItineraryFilter: payload => dispatch(updateItineraryFilter(payload))
+ setItineraryView: payload => dispatch(uiActions.setItineraryView(payload)),
+ setUseRealtimeResponse: payload => dispatch(narrativeActions.setUseRealtimeResponse(payload)),
+ setVisibleItinerary: payload => dispatch(narrativeActions.setVisibleItinerary(payload)),
+ updateItineraryFilter: payload => dispatch(narrativeActions.updateItineraryFilter(payload))
}
}
From d634ac93f0c0675e9f0b30a999cb7f56ccb7a837 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 1 Apr 2021 11:02:42 -0400
Subject: [PATCH 37/48] refactor(mobile/BatchResultsScreen): Style container,
fix lint.
---
lib/components/mobile/batch-results-screen.js | 23 +++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index 6f6454af9..83941aed3 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -2,7 +2,7 @@ import coreUtils from '@opentripplanner/core-utils'
import React, { Component } from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
-import styled from 'styled-components'
+import styled, { css } from 'styled-components'
import * as uiActions from '../../actions/ui'
import Map from '../map/map'
@@ -52,13 +52,18 @@ const ResultsMap = styled.div`
top: 100px;
`
-const StyledResultsError = styled(ResultsError)`
- display: ${props => props.visible ? 'inherit' : 'none'};
+const narrativeCss = css`
top: ${props => props.visible ? (props.expanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`) : '100%'};
transition: top 300ms;
`
+const StyledResultsError = styled(ResultsError)`
+ display: ${props => props.visible ? 'inherit' : 'none'};
+ ${narrativeCss}
+`
+
const NarrativeContainer = styled.div`
+ ${narrativeCss}
`
const { ItineraryView } = uiActions
@@ -73,12 +78,12 @@ class BatchMobileResultsScreen extends Component {
previousSplitView: null
}
- /**
+ /**
* Switch between full map view and the split state (itinerary list or itinerary leg view)
* that was in place prior.
*/
_toggleMapExpanded = () => {
- const { itineraryView, setItineraryView } = this.props
+ const { itineraryView, setItineraryView } = this.props
if (itineraryView !== ItineraryView.HIDDEN) {
this.setState({ previousSplitView: itineraryView })
@@ -93,7 +98,6 @@ class BatchMobileResultsScreen extends Component {
const hasNoResult = itineraries.length === 0 && errors.length > 0
const mapExpanded = itineraryView === ItineraryView.HIDDEN
const itineraryExpanded = itineraryView === ItineraryView.FULL
- const narrativeTop = mapExpanded ? '100%' : (itineraryExpanded ? '100px' : `${NARRATIVE_SPLIT_TOP_PERCENT}%`)
return (
@@ -118,9 +122,10 @@ class BatchMobileResultsScreen extends Component {
visible={!mapExpanded}
/>
: (
-
-
+
)
}
From 25e497daee3740b82961826373855869b0c306a8 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 1 Apr 2021 11:20:35 -0400
Subject: [PATCH 38/48] refactor(NarrativeItineraries): Attempt to fix lint
---
lib/components/narrative/narrative-itineraries.js | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 465c2b45c..e2b9ad8fc 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -142,6 +142,12 @@ class NarrativeItineraries extends Component {
const resultText = pending
? 'Finding your options...'
: `${itineraries.length} itineraries found.`
+ const itineraryBodyProps = {
+ ...this.props,
+ // Override setActiveLeg from props spreading
+ setActiveLeg: this._setActiveLeg
+
+ }
return (
Date: Thu, 1 Apr 2021 11:34:39 -0400
Subject: [PATCH 39/48] refactor(NarrativeItineraries): Fix lint 2/
---
.../narrative/narrative-itineraries.js | 23 ++++++++++++-------
1 file changed, 15 insertions(+), 8 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index e2b9ad8fc..471f7b688 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -4,7 +4,14 @@ import PropTypes from 'prop-types'
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'
import { connect } from 'react-redux'
-import * as narrativeActions from '../../actions/narrative'
+import {
+ setActiveItinerary,
+ setActiveLeg,
+ setActiveStep,
+ setUseRealtimeResponse,
+ setVisibleItinerary,
+ updateItineraryFilter
+} from '../../actions/narrative'
import * as uiActions from '../../actions/ui'
import Icon from '../narrative/icon'
import { ComponentContext } from '../../util/contexts'
@@ -146,8 +153,8 @@ class NarrativeItineraries extends Component {
...this.props,
// Override setActiveLeg from props spreading
setActiveLeg: this._setActiveLeg
-
}
+
return (
{
// so that only one argument is passed,
// e.g. setActiveLeg({ index, leg })
return {
- setActiveItinerary: payload => dispatch(narrativeActions.setActiveItinerary(payload)),
+ setActiveItinerary: payload => dispatch(setActiveItinerary(payload)),
// FIXME
setActiveLeg: (index, leg) => {
- dispatch(narrativeActions.setActiveLeg({index, leg}))
+ dispatch(setActiveLeg({index, leg}))
},
// FIXME
setActiveStep: (index, step) => {
- dispatch(narrativeActions.setActiveStep({index, step}))
+ dispatch(setActiveStep({index, step}))
},
setItineraryView: payload => dispatch(uiActions.setItineraryView(payload)),
- setUseRealtimeResponse: payload => dispatch(narrativeActions.setUseRealtimeResponse(payload)),
- setVisibleItinerary: payload => dispatch(narrativeActions.setVisibleItinerary(payload)),
- updateItineraryFilter: payload => dispatch(narrativeActions.updateItineraryFilter(payload))
+ setUseRealtimeResponse: payload => dispatch(setUseRealtimeResponse(payload)),
+ setVisibleItinerary: payload => dispatch(setVisibleItinerary(payload)),
+ updateItineraryFilter: payload => dispatch(updateItineraryFilter(payload))
}
}
From cf678bbf51da21206f401c18e87cb719c805f6ff Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Thu, 1 Apr 2021 18:31:47 -0400
Subject: [PATCH 40/48] refactor: Address PR comments
---
lib/actions/ui.js | 4 ++++
lib/components/mobile/batch-results-screen.js | 4 ++--
lib/components/narrative/narrative-itineraries.js | 3 ++-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index f3463eb49..a435fe027 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -241,9 +241,13 @@ export const MobileScreens = {
*/
export const ItineraryView = {
DEFAULT: 'list',
+ /** One itinerary is shown. (In mobile view, the map is hidden.) */
FULL: 'full',
+ /** Itinerary is hidden. (In mobile view, the map is expanded.) */
HIDDEN: 'hidden',
+ /** One itinerary is shown, itinerary and map are focused on a leg. (The mobile view is split.) */
LEG: 'leg',
+ /** The list of itineraries is shown. (The mobile view is split.) */
LIST: 'list'
}
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index 83941aed3..45b505e20 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -95,7 +95,7 @@ class BatchMobileResultsScreen extends Component {
render () {
const { errors, itineraries, itineraryView } = this.props
- const hasNoResult = itineraries.length === 0 && errors.length > 0
+ const hasErrorsAndNoResult = itineraries.length === 0 && errors.length > 0
const mapExpanded = itineraryView === ItineraryView.HIDDEN
const itineraryExpanded = itineraryView === ItineraryView.FULL
@@ -115,7 +115,7 @@ class BatchMobileResultsScreen extends Component {
{mapExpanded ? 'Show results' : 'Expand map'}
- {hasNoResult
+ {hasErrorsAndNoResult
?
)
})}
+ {/* Don't show errors if an itinerary is expanded. */}
{/* FIXME: Flesh out error design/move to component? */}
- {errors.map((e, i) => {
+ {!itineraryIsExpanded && errors.map((e, i) => {
const mode = humanReadableMode(e.requestParameters.mode)
return (
From 3b2b8801f7c708392ca787f0401dc08f6be9103b Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 2 Apr 2021 10:03:32 -0400
Subject: [PATCH 41/48] refactor(NarrativeItineraries): Remove prop spreading.
---
.../narrative/narrative-itineraries.js | 35 ++++++++++++-------
1 file changed, 22 insertions(+), 13 deletions(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 50e4016eb..5bc4c91d1 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -126,14 +126,21 @@ class NarrativeItineraries extends Component {
render () {
const {
activeItinerary,
+ activeLeg,
activeSearch,
+ activeStep,
containerStyle,
errors,
itineraries,
pending,
realtimeEffects,
+ setActiveItinerary,
+ setActiveStep,
+ setVisibleItinerary,
sort,
- useRealtime
+ timeFormat,
+ useRealtime,
+ visibleItinerary
} = this.props
const { ItineraryBody, LegIcon } = this.context
@@ -149,11 +156,6 @@ class NarrativeItineraries extends Component {
const resultText = pending
? 'Finding your options...'
: `${itineraries.length} itineraries found.`
- const itineraryBodyProps = {
- ...this.props,
- // Override setActiveLeg from props spreading
- setActiveLeg: this._setActiveLeg
- }
return (
@@ -218,6 +220,8 @@ class NarrativeItineraries extends Component {
return (
)
})}
@@ -265,18 +274,18 @@ const mapStateToProps = (state, ownProps) => {
const urlParams = coreUtils.query.getUrlParams()
return {
- activeSearch,
- errors: getResponsesWithErrors(state.otp),
// swap out realtime itineraries with non-realtime depending on boolean
- itineraries,
- itineraryView: urlParams.ui_itineraryView || ItineraryView.DEFAULT,
- pending,
- realtimeEffects,
activeItinerary: activeSearch && activeSearch.activeItinerary,
activeLeg: activeSearch && activeSearch.activeLeg,
+ activeSearch,
activeStep: activeSearch && activeSearch.activeStep,
+ errors: getResponsesWithErrors(state.otp),
filter,
+ itineraries,
+ itineraryView: urlParams.ui_itineraryView || ItineraryView.DEFAULT,
modes,
+ pending,
+ realtimeEffects,
sort,
timeFormat: coreUtils.time.getTimeFormat(state.otp.config),
useRealtime,
From 5d6a39383a7fdf48555477b87a800237921fa56f Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 5 Apr 2021 11:43:13 -0400
Subject: [PATCH 42/48] refactor(mobile/ResultsHeader): Reset view before
clearing search.
---
lib/components/mobile/results-error.js | 5 +++++
lib/components/mobile/results-header.js | 6 ++++--
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/lib/components/mobile/results-error.js b/lib/components/mobile/results-error.js
index 123b6758b..2114ed00e 100644
--- a/lib/components/mobile/results-error.js
+++ b/lib/components/mobile/results-error.js
@@ -15,10 +15,14 @@ import ErrorMessage from '../form/error-message'
class ResultsError extends Component {
static propTypes = {
error: PropTypes.object,
+ setItineraryView: PropTypes.func,
setMobileScreen: PropTypes.func
}
_editSearchClicked = () => {
+ // Reset itinerary view state to show the list of results *before* clearing the search.
+ // (Otherwise, if the map is expanded, the search is not cleared.)
+ this.props.setItineraryView(uiActions.ItineraryView.LIST)
this.props.clearActiveSearch()
this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
}
@@ -54,6 +58,7 @@ const mapStateToProps = (state, ownProps) => {
const mapDispatchToProps = {
clearActiveSearch: formActions.clearActiveSearch,
+ setItineraryView: uiActions.setItineraryView,
setMobileScreen: uiActions.setMobileScreen
}
diff --git a/lib/components/mobile/results-header.js b/lib/components/mobile/results-header.js
index b615e007c..14b478e49 100644
--- a/lib/components/mobile/results-header.js
+++ b/lib/components/mobile/results-header.js
@@ -53,14 +53,16 @@ class ResultsHeader extends Component {
errors: PropTypes.array,
query: PropTypes.object,
resultCount: PropTypes.number,
+ setItineraryView: PropTypes.func,
setMobileScreen: PropTypes.func
}
_editSearchClicked = () => {
+ // Reset itinerary view state to show the list of results *before* clearing the search.
+ // (Otherwise, if the map is expanded, the search is not cleared.)
+ this.props.setItineraryView(uiActions.ItineraryView.LIST)
this.props.clearActiveSearch()
this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
- // Reset itinerary view state to show the list of results.
- this.props.setItineraryView(uiActions.ItineraryView.LIST)
}
render () {
From 804b53c6ac1f57d99f825d55c394138b9ea88244 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 5 Apr 2021 12:11:46 -0400
Subject: [PATCH 43/48] refactor(mobile/EditSearchButton): Extract duplicate
code.
---
lib/components/mobile/edit-search-button.js | 52 +++++++++++++++
lib/components/mobile/results-error.js | 70 ++++++---------------
lib/components/mobile/results-header.js | 32 +++-------
3 files changed, 79 insertions(+), 75 deletions(-)
create mode 100644 lib/components/mobile/edit-search-button.js
diff --git a/lib/components/mobile/edit-search-button.js b/lib/components/mobile/edit-search-button.js
new file mode 100644
index 000000000..d1ad67ea3
--- /dev/null
+++ b/lib/components/mobile/edit-search-button.js
@@ -0,0 +1,52 @@
+import PropTypes from 'prop-types'
+import React, { Component } from 'react'
+import { Button } from 'react-bootstrap'
+import { connect } from 'react-redux'
+
+import * as formActions from '../../actions/form'
+import * as uiActions from '../../actions/ui'
+
+/**
+ * Renders the "Edit" or "Back to search" button in mobile result views
+ * that takes the user back to the mobile search screen.
+ */
+class EditSearchButton extends Component {
+ static propTypes = {
+ clearActiveSearch: PropTypes.func,
+ setItineraryView: PropTypes.func,
+ setMobileScreen: PropTypes.func
+ }
+
+ _handleClick = () => {
+ const { clearActiveSearch, setItineraryView, setMobileScreen } = this.props
+
+ // Reset itinerary view state to show the list of results *before* clearing the search.
+ // (Otherwise, if the map is expanded, the search is not cleared.)
+ setItineraryView(uiActions.ItineraryView.LIST)
+ clearActiveSearch()
+ setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
+ }
+
+ render () {
+ const { children, className, style } = this.props
+ return (
+
+ {children}
+
+ )
+ }
+}
+
+// connect to the redux store
+
+const mapDispatchToProps = {
+ clearActiveSearch: formActions.clearActiveSearch,
+ setItineraryView: uiActions.setItineraryView,
+ setMobileScreen: uiActions.setMobileScreen
+}
+
+export default connect(null, mapDispatchToProps)(EditSearchButton)
diff --git a/lib/components/mobile/results-error.js b/lib/components/mobile/results-error.js
index 2114ed00e..eb8728a1e 100644
--- a/lib/components/mobile/results-error.js
+++ b/lib/components/mobile/results-error.js
@@ -1,65 +1,35 @@
import PropTypes from 'prop-types'
-import React, { Component } from 'react'
-import { Button } from 'react-bootstrap'
-import { connect } from 'react-redux'
+import React from 'react'
import styled from 'styled-components'
-import * as formActions from '../../actions/form'
-import * as uiActions from '../../actions/ui'
import ErrorMessage from '../form/error-message'
+import EditSearchButton from './edit-search-button'
+
/**
* This component is used on mobile views to
* render an error message if no results are found.
*/
-class ResultsError extends Component {
- static propTypes = {
- error: PropTypes.object,
- setItineraryView: PropTypes.func,
- setMobileScreen: PropTypes.func
- }
-
- _editSearchClicked = () => {
- // Reset itinerary view state to show the list of results *before* clearing the search.
- // (Otherwise, if the map is expanded, the search is not cleared.)
- this.props.setItineraryView(uiActions.ItineraryView.LIST)
- this.props.clearActiveSearch()
- this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
- }
-
- render () {
- const { className, error } = this.props
- return (
-
-
-
-
- Back to Search
-
-
-
- )
- }
+const ResultsError = ({ className, error }) => (
+
+
+
+
+ Back to Search
+
+
+
+)
+
+ResultsError.propTypes = {
+ error: PropTypes.object
}
const StyledResultsError = styled(ResultsError)`
top: 300px;
`
-// connect to the redux store
-
-const mapStateToProps = (state, ownProps) => {
- return {}
-}
-
-const mapDispatchToProps = {
- clearActiveSearch: formActions.clearActiveSearch,
- setItineraryView: uiActions.setItineraryView,
- setMobileScreen: uiActions.setMobileScreen
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(StyledResultsError)
+export default StyledResultsError
diff --git a/lib/components/mobile/results-header.js b/lib/components/mobile/results-header.js
index 14b478e49..d0aa51c4b 100644
--- a/lib/components/mobile/results-header.js
+++ b/lib/components/mobile/results-header.js
@@ -1,18 +1,17 @@
import LocationIcon from '@opentripplanner/location-icon'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
-import { Button, Col, Row } from 'react-bootstrap'
+import { Col, Row } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled from 'styled-components'
-import * as formActions from '../../actions/form'
-import * as uiActions from '../../actions/ui'
import {
getActiveItineraries,
getActiveSearch,
getResponsesWithErrors
} from '../../util/state'
+import EditSearchButton from './edit-search-button'
import MobileNavigationBar from './navigation-bar'
const LocationContainer = styled.div`
@@ -52,17 +51,7 @@ class ResultsHeader extends Component {
static propTypes = {
errors: PropTypes.array,
query: PropTypes.object,
- resultCount: PropTypes.number,
- setItineraryView: PropTypes.func,
- setMobileScreen: PropTypes.func
- }
-
- _editSearchClicked = () => {
- // Reset itinerary view state to show the list of results *before* clearing the search.
- // (Otherwise, if the map is expanded, the search is not cleared.)
- this.props.setItineraryView(uiActions.ItineraryView.LIST)
- this.props.clearActiveSearch()
- this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
+ resultCount: PropTypes.number
}
render () {
@@ -90,10 +79,9 @@ class ResultsHeader extends Component {
-
Edit
+
+ Edit
+
@@ -121,10 +109,4 @@ const mapStateToProps = (state, ownProps) => {
}
}
-const mapDispatchToProps = {
- clearActiveSearch: formActions.clearActiveSearch,
- setItineraryView: uiActions.setItineraryView,
- setMobileScreen: uiActions.setMobileScreen
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(ResultsHeader)
+export default connect(mapStateToProps)(ResultsHeader)
From af9f653f1d0dec934913ef1ec57fb42eeb995f42 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Fri, 9 Apr 2021 15:10:27 -0400
Subject: [PATCH 44/48] fix(actions/ui): Split ItineraryView hidden state.
---
lib/actions/ui.js | 8 +++++---
lib/components/mobile/batch-results-screen.js | 9 ++++++---
lib/components/narrative/narrative-itineraries.js | 4 +++-
3 files changed, 14 insertions(+), 7 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index a435fe027..7379dfeee 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -243,12 +243,14 @@ export const ItineraryView = {
DEFAULT: 'list',
/** One itinerary is shown. (In mobile view, the map is hidden.) */
FULL: 'full',
- /** Itinerary is hidden. (In mobile view, the map is expanded.) */
- HIDDEN: 'hidden',
/** One itinerary is shown, itinerary and map are focused on a leg. (The mobile view is split.) */
LEG: 'leg',
+ /** One itinerary leg is hidden. (In mobile view, the map is expanded.) */
+ LEG_HIDDEN: 'leg-hidden',
/** The list of itineraries is shown. (The mobile view is split.) */
- LIST: 'list'
+ LIST: 'list',
+ /** The list of itineraries is hidden. (In mobile view, the map is expanded.) */
+ LIST_HIDDEN: 'list-hidden'
}
/**
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index 45b505e20..da1750bb3 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -85,9 +85,12 @@ class BatchMobileResultsScreen extends Component {
_toggleMapExpanded = () => {
const { itineraryView, setItineraryView } = this.props
- if (itineraryView !== ItineraryView.HIDDEN) {
+ if (itineraryView === ItineraryView.LEG) {
this.setState({ previousSplitView: itineraryView })
- setItineraryView(ItineraryView.HIDDEN)
+ setItineraryView(ItineraryView.LEG_HIDDEN)
+ } else if (itineraryView === ItineraryView.LIST) {
+ this.setState({ previousSplitView: itineraryView })
+ setItineraryView(ItineraryView.LIST_HIDDEN)
} else {
setItineraryView(this.state.previousSplitView)
}
@@ -96,7 +99,7 @@ class BatchMobileResultsScreen extends Component {
render () {
const { errors, itineraries, itineraryView } = this.props
const hasErrorsAndNoResult = itineraries.length === 0 && errors.length > 0
- const mapExpanded = itineraryView === ItineraryView.HIDDEN
+ const mapExpanded = itineraryView === ItineraryView.LEG_HIDDEN || itineraryView === ItineraryView.LIST_HIDDEN
const itineraryExpanded = itineraryView === ItineraryView.FULL
return (
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index 12beb7af9..cdcaec0ff 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -71,7 +71,9 @@ class NarrativeItineraries extends Component {
_isShowingDetails = () => {
const { itineraryView } = this.props
- return itineraryView === ItineraryView.FULL || itineraryView === ItineraryView.LEG
+ return itineraryView === ItineraryView.FULL ||
+ itineraryView === ItineraryView.LEG ||
+ itineraryView === ItineraryView.LEG_HIDDEN
}
_toggleDetailedItinerary = () => {
From 7a8b67e5e5555bb641af54e4415b83bfb99f767d Mon Sep 17 00:00:00 2001
From: Landon Reed
Date: Fri, 9 Apr 2021 16:23:28 -0400
Subject: [PATCH 45/48] refactor(state.js): remove noisy/unneeded log statement
---
lib/util/state.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/util/state.js b/lib/util/state.js
index a3459b805..4caab3f7f 100644
--- a/lib/util/state.js
+++ b/lib/util/state.js
@@ -99,7 +99,6 @@ export function getActiveItineraries (otpState) {
})
return hasCar
default:
- console.warn(`Filter (${filter}) not supported`)
return true
}
})
From 3f138bb57c187373a0dea19cc90aea90f8fb92bd Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Mon, 12 Apr 2021 09:36:31 -0400
Subject: [PATCH 46/48] refactor(NarrativeItineraries): Remove unused prop.
---
lib/components/narrative/narrative-itineraries.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js
index cdcaec0ff..b241ac753 100644
--- a/lib/components/narrative/narrative-itineraries.js
+++ b/lib/components/narrative/narrative-itineraries.js
@@ -279,7 +279,6 @@ const mapStateToProps = (state, ownProps) => {
activeSearch,
activeStep: activeSearch && activeSearch.activeStep,
errors: getResponsesWithErrors(state.otp),
- filter: state.otp.filter,
itineraries,
itineraryView: urlParams.ui_itineraryView || ItineraryView.DEFAULT,
modes,
From 43fef77367b6d788c401198500108f49fff1f355 Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 13 Apr 2021 11:39:22 -0400
Subject: [PATCH 47/48] refactor(actions/ui): Extract batch results and edit
search actions.
---
lib/actions/ui.js | 40 +++++-
lib/components/mobile/batch-results-screen.js | 124 +++++++-----------
lib/components/mobile/edit-search-button.js | 42 +-----
lib/reducers/create-otp-reducer.js | 2 +
4 files changed, 97 insertions(+), 111 deletions(-)
diff --git a/lib/actions/ui.js b/lib/actions/ui.js
index 7379dfeee..955515798 100644
--- a/lib/actions/ui.js
+++ b/lib/actions/ui.js
@@ -253,6 +253,8 @@ export const ItineraryView = {
LIST_HIDDEN: 'list-hidden'
}
+const setPreviousItineraryView = createAction('SET_PREVIOUS_ITINERARY_VIEW')
+
/**
* Sets the itinerary view state (see values above) in the URL params
* (currently only used in batch results).
@@ -260,9 +262,11 @@ export const ItineraryView = {
export function setItineraryView (value) {
return function (dispatch, getState) {
const urlParams = coreUtils.query.getUrlParams()
+ const prevItineraryView = urlParams.ui_itineraryView || ItineraryView.DEFAULT
// If the itinerary value is changed,
- // set the desired ui query param, or remove it if same as default.
+ // set the desired ui query param, or remove it if same as default,
+ // and store the current view as previousItineraryView.
if (value !== urlParams.ui_itineraryView) {
if (value !== ItineraryView.DEFAULT) {
urlParams.ui_itineraryView = value
@@ -271,6 +275,40 @@ export function setItineraryView (value) {
}
dispatch(setUrlSearch(urlParams))
+ dispatch(setPreviousItineraryView(prevItineraryView))
+ }
+ }
+}
+
+/**
+ * Switch the mobile batch results view between full map view and the split state
+ * (itinerary list or itinerary leg view) that was in place prior.
+ */
+export function toggleBatchResultsMap () {
+ return function (dispatch, getState) {
+ const urlParams = coreUtils.query.getUrlParams()
+ const itineraryView = urlParams.ui_itineraryView || ItineraryView.DEFAULT
+
+ if (itineraryView === ItineraryView.LEG) {
+ dispatch(setItineraryView(ItineraryView.LEG_HIDDEN))
+ } else if (itineraryView === ItineraryView.LIST) {
+ dispatch(setItineraryView(ItineraryView.LIST_HIDDEN))
+ } else {
+ const { previousItineraryView } = getState().otp.ui
+ dispatch(setItineraryView(previousItineraryView))
}
}
}
+
+/**
+ * Takes the user back to the mobile search screen in mobile views.
+ */
+export function showMobileSearchScreen () {
+ return function (dispatch, getState) {
+ // Reset itinerary view state to show the list of results *before* clearing the search.
+ // (Otherwise, if the map is expanded, the search is not cleared.)
+ dispatch(setItineraryView(ItineraryView.LIST))
+ dispatch(clearActiveSearch())
+ dispatch(setMobileScreen(MobileScreens.SEARCH_FORM))
+ }
+}
diff --git a/lib/components/mobile/batch-results-screen.js b/lib/components/mobile/batch-results-screen.js
index da1750bb3..51370a897 100644
--- a/lib/components/mobile/batch-results-screen.js
+++ b/lib/components/mobile/batch-results-screen.js
@@ -1,5 +1,5 @@
import coreUtils from '@opentripplanner/core-utils'
-import React, { Component } from 'react'
+import React from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled, { css } from 'styled-components'
@@ -72,79 +72,58 @@ const { ItineraryView } = uiActions
* This component renders the mobile view of itinerary results from batch routing,
* and features a split view between the map and itinerary results or narratives.
*/
-class BatchMobileResultsScreen extends Component {
- state = {
- // Holds the previous split view state
- previousSplitView: null
- }
-
- /**
- * Switch between full map view and the split state (itinerary list or itinerary leg view)
- * that was in place prior.
- */
- _toggleMapExpanded = () => {
- const { itineraryView, setItineraryView } = this.props
-
- if (itineraryView === ItineraryView.LEG) {
- this.setState({ previousSplitView: itineraryView })
- setItineraryView(ItineraryView.LEG_HIDDEN)
- } else if (itineraryView === ItineraryView.LIST) {
- this.setState({ previousSplitView: itineraryView })
- setItineraryView(ItineraryView.LIST_HIDDEN)
- } else {
- setItineraryView(this.state.previousSplitView)
- }
- }
-
- render () {
- const { errors, itineraries, itineraryView } = this.props
- const hasErrorsAndNoResult = itineraries.length === 0 && errors.length > 0
- const mapExpanded = itineraryView === ItineraryView.LEG_HIDDEN || itineraryView === ItineraryView.LIST_HIDDEN
- const itineraryExpanded = itineraryView === ItineraryView.FULL
-
- return (
-
-
- {
+ const hasErrorsAndNoResult = itineraries.length === 0 && errors.length > 0
+ const mapExpanded = itineraryView === ItineraryView.LEG_HIDDEN || itineraryView === ItineraryView.LIST_HIDDEN
+ const itineraryExpanded = itineraryView === ItineraryView.FULL
+
+ return (
+
+
+
+
+
-
-
- {' '}
- {mapExpanded ? 'Show results' : 'Expand map'}
-
-
- {hasErrorsAndNoResult
- ? {' '}
+ {mapExpanded ? 'Show results' : 'Expand map'}
+
+
+ {hasErrorsAndNoResult
+ ?
+ : (
+
- : (
-
-
-
- )
- }
-
- )
- }
+ >
+
+
+ )
+ }
+
+ )
}
// connect to the redux store
@@ -152,7 +131,6 @@ class BatchMobileResultsScreen extends Component {
const mapStateToProps = (state, ownProps) => {
const activeSearch = getActiveSearch(state.otp)
const urlParams = coreUtils.query.getUrlParams()
-
return {
activeLeg: activeSearch ? activeSearch.activeLeg : null,
errors: getResponsesWithErrors(state.otp),
@@ -162,7 +140,7 @@ const mapStateToProps = (state, ownProps) => {
}
const mapDispatchToProps = {
- setItineraryView: uiActions.setItineraryView
+ toggleBatchResultsMap: uiActions.toggleBatchResultsMap
}
export default connect(mapStateToProps, mapDispatchToProps)(BatchMobileResultsScreen)
diff --git a/lib/components/mobile/edit-search-button.js b/lib/components/mobile/edit-search-button.js
index d1ad67ea3..bdf514857 100644
--- a/lib/components/mobile/edit-search-button.js
+++ b/lib/components/mobile/edit-search-button.js
@@ -1,52 +1,20 @@
-import PropTypes from 'prop-types'
-import React, { Component } from 'react'
+import React from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
-import * as formActions from '../../actions/form'
import * as uiActions from '../../actions/ui'
/**
* Renders the "Edit" or "Back to search" button in mobile result views
* that takes the user back to the mobile search screen.
*/
-class EditSearchButton extends Component {
- static propTypes = {
- clearActiveSearch: PropTypes.func,
- setItineraryView: PropTypes.func,
- setMobileScreen: PropTypes.func
- }
-
- _handleClick = () => {
- const { clearActiveSearch, setItineraryView, setMobileScreen } = this.props
-
- // Reset itinerary view state to show the list of results *before* clearing the search.
- // (Otherwise, if the map is expanded, the search is not cleared.)
- setItineraryView(uiActions.ItineraryView.LIST)
- clearActiveSearch()
- setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
- }
-
- render () {
- const { children, className, style } = this.props
- return (
-
- {children}
-
- )
- }
-}
+const EditSearchButton = ({ showMobileSearchScreen, ...props }) => (
+
+)
// connect to the redux store
-
const mapDispatchToProps = {
- clearActiveSearch: formActions.clearActiveSearch,
- setItineraryView: uiActions.setItineraryView,
- setMobileScreen: uiActions.setMobileScreen
+ showMobileSearchScreen: uiActions.showMobileSearchScreen
}
export default connect(null, mapDispatchToProps)(EditSearchButton)
diff --git a/lib/reducers/create-otp-reducer.js b/lib/reducers/create-otp-reducer.js
index 863b94bbb..1fadd42c0 100644
--- a/lib/reducers/create-otp-reducer.js
+++ b/lib/reducers/create-otp-reducer.js
@@ -945,6 +945,8 @@ function createOtpReducer (config) {
return update(state,
{ filter: { $set: action.payload } }
)
+ case 'SET_PREVIOUS_ITINERARY_VIEW':
+ return update(state, { ui: { previousItineraryView: { $set: action.payload } } })
default:
return state
}
From cabab54614aab814be33065848ef69c68670877e Mon Sep 17 00:00:00 2001
From: binh-dam-ibigroup <56846598+binh-dam-ibigroup@users.noreply.github.com>
Date: Tue, 13 Apr 2021 11:56:46 -0400
Subject: [PATCH 48/48] fix(mobile.css): Make batch settings appear under
hamburger dropdown.
Fix #348
---
lib/components/mobile/mobile.css | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lib/components/mobile/mobile.css b/lib/components/mobile/mobile.css
index 3ff8dc0c1..eaa89f452 100644
--- a/lib/components/mobile/mobile.css
+++ b/lib/components/mobile/mobile.css
@@ -115,7 +115,8 @@
left: 0;
right: 0;
height: 216px;
- z-index: 99999999;
+ /* Must appear under the 'hamburger' dropdown which has z-index of 1000. */
+ z-index: 999;
box-shadow: 3px 0px 12px #00000052;
}