Skip to content

Mobile batch results #339

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 51 commits into from
Apr 13, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
ec0662d
feat(mobile/batch-results-screen): Add mobile batch results screen.
binh-dam-ibigroup Mar 3, 2021
d35ce7f
refactor(mobile/BatchResultsScreen): Clean up code.
binh-dam-ibigroup Mar 3, 2021
b1a84b6
refactor(BatchResultsScreen): Fix fitting itinerary after expanding map.
binh-dam-ibigroup Mar 4, 2021
9c21e13
refactor(BatchResultsScreen): Tweak styles.
binh-dam-ibigroup Mar 4, 2021
90be15a
refactor(mobile/ResultsHeaderAndError): Extract component. Refactors.
binh-dam-ibigroup Mar 5, 2021
50d8d23
style(mobile/*results*): Tweak comments and sort props and imports.
binh-dam-ibigroup Mar 5, 2021
e802be6
refactor(batch results): Mention component is required, fix typo.
binh-dam-ibigroup Mar 12, 2021
c10d7ca
fix(narrative-itineraries.js, default-itinerary.js): Added setActiveL…
Mar 11, 2021
edea628
fix(default-itinerary.js): Removed some unused code.
Mar 11, 2021
100c1d6
fix(BatchResultsScreen): Fix leg focus, address some PR comments.
binh-dam-ibigroup Mar 23, 2021
df664e0
refactor(BatchResultsScreen): Show result screen with correct #itins …
binh-dam-ibigroup Mar 23, 2021
79488a8
refactor(mobile/main): Show mobile results screen on plan.
binh-dam-ibigroup Mar 23, 2021
4a1d32a
refactor(ResultsError): Split results header and error section.
binh-dam-ibigroup Mar 23, 2021
d615fd8
style(ResultsScreen): Commit indents
binh-dam-ibigroup Mar 23, 2021
22beb2c
style(mobile/main): Fix indent
binh-dam-ibigroup Mar 23, 2021
15329fe
refactor(BoundsUpdatingOverlay): Remove fit bounds mobile restriction.
binh-dam-ibigroup Mar 24, 2021
fc76d3e
refactor(BatchResultsScreen): Investigate imperative resizing.
binh-dam-ibigroup Mar 24, 2021
2e7757c
refactor(map/default-map): Use key prop to force transitive remount o…
binh-dam-ibigroup Mar 24, 2021
557bfc7
refactor(BatchResultsScreen): Refactor, tweak split height.
binh-dam-ibigroup Mar 24, 2021
3edc3d4
refactor(BatchResultScreen): Move itin state to URL param, remove sta…
binh-dam-ibigroup Mar 24, 2021
9e71d59
refactor(mobile/BatchResultsScreen): Tweak layout for no-results.
binh-dam-ibigroup Mar 25, 2021
922e28c
refactor(NarrativeItineraries): Initialize component with itin view U…
binh-dam-ibigroup Mar 25, 2021
2b77be6
refactor(BoundsUpdatingOverlay): Reset transitive on leg click from e…
binh-dam-ibigroup Mar 25, 2021
ef95547
refactor(BoundsUpdatingOverlay): Fix lint
binh-dam-ibigroup Mar 25, 2021
794aeaf
docs: Update comments from PR reviews.
binh-dam-ibigroup Mar 30, 2021
b1ab768
refactor(BoundsUpdatingOverlay): Revert block regarding #133.
binh-dam-ibigroup Mar 30, 2021
b738bd2
refactor(BoundsUpdatingOverlay): Move code per PR comment
binh-dam-ibigroup Mar 30, 2021
19f0569
refactor(BatchResultsScreen): Replace showDetails state with itinerar…
binh-dam-ibigroup Mar 30, 2021
7c82cd7
refactor(actions/ui): Rename ItineraryView.SPLIT>LIST
binh-dam-ibigroup Mar 30, 2021
d0a4f35
refactor(BatchResultsScreen): Add uncommited refactors from 7c82cd7
binh-dam-ibigroup Mar 30, 2021
df927a8
refactor(mobile/ResultsHeader): Reset itineraryView state when clicki…
binh-dam-ibigroup Mar 30, 2021
7678132
refactor(NarrativeItineraries): Toggle focus between leg and itinerar…
binh-dam-ibigroup Mar 31, 2021
dffebbf
refactor(NarrativeItineraries): Fix lint
binh-dam-ibigroup Mar 31, 2021
77bfc8f
refactor(mobile/results-screen): Convert options header into button+s…
binh-dam-ibigroup Mar 31, 2021
d773783
refactor(mobile/ResultsError): Convert some components to styled- per…
binh-dam-ibigroup Mar 31, 2021
48bafb6
refactor: Address PR comments.
binh-dam-ibigroup Apr 1, 2021
d634ac9
refactor(mobile/BatchResultsScreen): Style container, fix lint.
binh-dam-ibigroup Apr 1, 2021
25e497d
refactor(NarrativeItineraries): Attempt to fix lint
binh-dam-ibigroup Apr 1, 2021
1c48f41
refactor(NarrativeItineraries): Fix lint 2/
binh-dam-ibigroup Apr 1, 2021
cf678bb
refactor: Address PR comments
binh-dam-ibigroup Apr 1, 2021
3b2b880
refactor(NarrativeItineraries): Remove prop spreading.
binh-dam-ibigroup Apr 2, 2021
72fad25
Merge branch 'dev' into mobile-batch-results
binh-dam-ibigroup Apr 2, 2021
5d6a393
refactor(mobile/ResultsHeader): Reset view before clearing search.
binh-dam-ibigroup Apr 5, 2021
804b53c
refactor(mobile/EditSearchButton): Extract duplicate code.
binh-dam-ibigroup Apr 5, 2021
af9f653
fix(actions/ui): Split ItineraryView hidden state.
binh-dam-ibigroup Apr 9, 2021
403ca61
Merge branch 'dev' into mobile-batch-results
binh-dam-ibigroup Apr 9, 2021
7a8b67e
refactor(state.js): remove noisy/unneeded log statement
landonreed Apr 9, 2021
3f138bb
refactor(NarrativeItineraries): Remove unused prop.
binh-dam-ibigroup Apr 12, 2021
602e2ff
Merge branch 'mobile-batch-results' of https://github.com/opentrippla…
binh-dam-ibigroup Apr 12, 2021
43fef77
refactor(actions/ui): Extract batch results and edit search actions.
binh-dam-ibigroup Apr 13, 2021
cabab54
fix(mobile.css): Make batch settings appear under hamburger dropdown.
binh-dam-ibigroup Apr 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions example.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ import createLogger from 'redux-logger'

// import OTP-RR components
import {
BatchResultsScreen,
BatchRoutingPanel,
BatchSearchScreen,
CallTakerControls,
CallTakerPanel,
CallTakerWindows,
DefaultItinerary,
DefaultMainPanel,
MobileResultsScreen,
MobileSearchScreen,
ResponsiveWebapp,
createCallTakerReducer,
Expand Down Expand Up @@ -58,6 +60,7 @@ if (useCustomIcons) {
// - MainControls (optional)
// - MainPanel (required)
// - MapWindows (optional)
// - MobileResultsScreen (required)
// - MobileSearchScreen (required)
// - ModeIcon (required)
const components = {
Expand All @@ -71,6 +74,9 @@ const components = {
? BatchRoutingPanel
: DefaultMainPanel,
MapWindows: isCallTakerModuleEnabled ? CallTakerWindows : null,
MobileResultsScreen: isBatchRoutingEnabled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add this component as a required component in the comment about the creation of the components variable.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in e802be6.

? BatchResultsScreen
: MobileResultsScreen,
MobileSearchScreen: isBatchRoutingEnabled
? BatchSearchScreen
: MobileSearchScreen,
Expand Down
123 changes: 123 additions & 0 deletions lib/components/mobile/batch-results-screen.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import styled from 'styled-components'

import Map from '../map/map'
import Icon from '../narrative/icon'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import { getActiveError } from '../../util/state'

import MobileContainer from './container'
import ResultsHeaderAndError from './results-header-and-error'

const StyledMobileContainer = styled(MobileContainer)`
.options > .header {
margin: 10px;
}

&.otp.mobile .mobile-narrative-container {
bottom: 0;
left: 0;
overflow-y: auto;
padding: 0;
position: fixed;
right: 0;
}
`

const ExpandMapButton = styled(Button)`
bottom: 25px;
position: absolute;
right: 10px;
z-index: 999999;
`

class BatchMobileResultsScreen extends Component {
static propTypes = {
error: PropTypes.object
}

constructor () {
super()
this.state = {
itineraryExpanded: false,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if it should be in this PR, but I'd like this itin expanded item to perhaps be moved to a UI query param. Might require some changes to the desktop view as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went ahead and added a URL parameter ui_itineraryView in 3edc3d4 to replace passing props around to track the map expanded state.

mapExpanded: false
}
}

componentDidUpdate (prevProps) {
// Check if the active leg changed
if (this.props.activeLeg !== prevProps.activeLeg) {
this._setItineraryExpanded(false)
}
}

_setItineraryExpanded = itineraryExpanded => {
this.setState({ itineraryExpanded })
}

_toggleMapExpanded = () => {
this.setState({ mapExpanded: !this.state.mapExpanded })
}

renderMap () {
const { mapExpanded } = this.state
return (
<div className='results-map' style={{bottom: mapExpanded ? 0 : '60%'}}>
<Map />
<ExpandMapButton
bsSize='small'
onClick={this._toggleMapExpanded}
>
<Icon name={mapExpanded ? 'list-ul' : 'arrows-alt'} />
{mapExpanded ? 'Show results' : 'Expand map'}
</ExpandMapButton>
</div>
)
}

render () {
const { error } = this.props
const { itineraryExpanded, mapExpanded } = this.state

return (
<StyledMobileContainer>
<ResultsHeaderAndError />
{!error && (mapExpanded
// Set up two separate renderings of the map according to mapExpanded,
// so that the map is properly sized and itineraries fit under either conditions.
// (Otherwise, if just the narrative is added/removed, the map doesn't resize properly.)
? this.renderMap()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to have this transition be animated (transition animation to expand the map div and possibly remove the refresh on the map tiles and have a smoother zoom to itinerary)? I find the current approach kind of jarring.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't rerender the map and simply resize it (what we'd have to do to enable the animated transition), then the inner map canvas is not properly resized... any suggestions for triggering that?
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you would have to reload the tiles anyway after expanding/collapsing the map because the zoom and fit would be different in either case.

Copy link
Collaborator Author

@binh-dam-ibigroup binh-dam-ibigroup Mar 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I found a way to do the transition without rerendering the map with 557bfc7 (after almost giving up... - see the transitive trick in 2e7757c)

: (
<>
{!itineraryExpanded && this.renderMap()}
<div className='mobile-narrative-container' style={{top: itineraryExpanded ? '100px' : '40%'}}>
<NarrativeItineraries
containerStyle={{
display: 'flex',
flexDirection: 'column',
height: '100%',
width: '100%'
}}
onToggleDetailedItinerary={this._setItineraryExpanded}
/>
</div>
</>
))
}
</StyledMobileContainer>
)
}
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
return {
error: getActiveError(state.otp)
}
}

export default connect(mapStateToProps)(BatchMobileResultsScreen)
5 changes: 3 additions & 2 deletions lib/components/mobile/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import React, { Component } from 'react'

export default class MobileContainer extends Component {
render () {
const { children, className } = this.props
return (
<div className='otp mobile'>
{this.props.children}
<div className={`otp mobile${className ? ` ${className}` : ''}`}>
{children}
</div>
)
}
Expand Down
3 changes: 1 addition & 2 deletions lib/components/mobile/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import MobileDateTimeScreen from './date-time-screen'
import MobileOptionsScreen from './options-screen'
import MobileLocationSearch from './location-search'
import MobileWelcomeScreen from './welcome-screen'
import MobileResultsScreen from './results-screen'
import MobileStopViewer from './stop-viewer'
import MobileTripViewer from './trip-viewer'
import MobileRouteViewer from './route-viewer'
Expand Down Expand Up @@ -45,7 +44,7 @@ class MobileMain extends Component {
}

render () {
const { MobileSearchScreen } = this.context
const { MobileResultsScreen, MobileSearchScreen } = this.context
const { uiState } = this.props

// check for route viewer
Expand Down
142 changes: 142 additions & 0 deletions lib/components/mobile/results-header-and-error.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import LocationIcon from '@opentripplanner/location-icon'
import PropTypes from 'prop-types'
import React, { Component } from 'react'
import { Button, 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 ErrorMessage from '../form/error-message'
import Map from '../map/map'
import {
getActiveError,
getActiveItineraries,
getActiveSearch
} from '../../util/state'

import MobileNavigationBar from './navigation-bar'

const LocationContainer = styled.div`
font-weight: 300;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`

const LocationSummaryContainer = styled.div`
height: 50px;
left: 0;
padding-right: 10px;
position: fixed;
right: 0;
top: 50px;
`

const LocationsSummaryColFromTo = styled(Col)`
font-size: 1.1em;
line-height: 1.2em;
`

const LocationsSummaryRow = styled(Row)`
padding: 4px 8px;
`

const StyledLocationIcon = styled(LocationIcon)`
margin: 3px;
`

class ResultsHeaderAndError extends Component {
static propTypes = {
query: PropTypes.object,
resultCount: PropTypes.number,
setMobileScreen: PropTypes.func
}

_editSearchClicked = () => {
this.props.clearActiveSearch()
this.props.setMobileScreen(uiActions.MobileScreens.SEARCH_FORM)
}

render () {
const { error, query, resultCount } = this.props
const headerText = error
? 'No Trip Found'
: (resultCount
? `We Found ${resultCount} Option${resultCount > 1 ? 's' : ''}`
: 'Waiting...'
)

return (
<>
<MobileNavigationBar headerText={headerText} />

<LocationSummaryContainer>
<LocationsSummaryRow className='locations-summary'>
<LocationsSummaryColFromTo sm={11} xs={8}>
<LocationContainer>
<StyledLocationIcon type='from' /> { query.from ? query.from.name : '' }
</LocationContainer>
<LocationContainer style={{ marginTop: 2 }}>
<StyledLocationIcon type='to' /> { query.to ? query.to.name : '' }
</LocationContainer>
</LocationsSummaryColFromTo>
<Col sm={1} xs={4}>
<Button
className='edit-search-button pull-right'
onClick={this._editSearchClicked}
>Edit</Button>
</Col>
</LocationsSummaryRow>
</LocationSummaryContainer>

{error && (
<>
<div className='results-error-map'><Map /></div>
<div className='results-error-message'>
<ErrorMessage error={error} />
<div className='options-lower-tray mobile-padding'>
<Button
className='back-to-search-button'
onClick={this._editSearchClicked}
style={{ width: '100%' }}
>
<i className='fa fa-arrow-left' /> Back to Search
</Button>
</div>
</div>
</>
)}
</>
)
}
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
const activeSearch = getActiveSearch(state.otp)
const {useRealtime} = state.otp
const response = !activeSearch
? null
: useRealtime ? activeSearch.response : activeSearch.nonRealtimeResponse

const itineraries = getActiveItineraries(state.otp)
return {
error: getActiveError(state.otp),
query: state.otp.currentQuery,
resultCount:
response
? activeSearch.query.routingType === 'ITINERARY'
? itineraries.length
: response.otp.profile.length
: null
}
}

const mapDispatchToProps = {
clearActiveSearch: formActions.clearActiveSearch,
setMobileScreen: uiActions.setMobileScreen
}

export default connect(mapStateToProps, mapDispatchToProps)(ResultsHeaderAndError)
Loading