From f31f73ca685175c0a845616c2cd635c947bb3785 Mon Sep 17 00:00:00 2001 From: Landon Reed Date: Fri, 19 Feb 2021 11:46:01 -0500 Subject: [PATCH 1/9] fix(batch-routing): add mobile search screen for batch routing --- lib/components/app/batch-routing-panel.js | 166 +------------ lib/components/app/styled.js | 97 -------- ...settings-panel.js => batch-preferences.js} | 8 +- lib/components/form/batch-settings.js | 202 ++++++++++++++++ lib/components/form/batch-styled.js | 222 ++++++++++++++++++ lib/components/form/mode-buttons.js | 2 +- lib/components/form/settings-preview.js | 2 +- lib/components/form/styled.js | 142 +---------- lib/components/mobile/batch-search-screen.js | 71 ++++++ lib/components/mobile/main.js | 12 +- lib/components/mobile/mobile.css | 21 ++ 11 files changed, 546 insertions(+), 399 deletions(-) delete mode 100644 lib/components/app/styled.js rename lib/components/form/{batch-settings-panel.js => batch-preferences.js} (94%) create mode 100644 lib/components/form/batch-settings.js create mode 100644 lib/components/form/batch-styled.js create mode 100644 lib/components/mobile/batch-search-screen.js diff --git a/lib/components/app/batch-routing-panel.js b/lib/components/app/batch-routing-panel.js index 93d2e1975..c663d9965 100644 --- a/lib/components/app/batch-routing-panel.js +++ b/lib/components/app/batch-routing-panel.js @@ -5,77 +5,12 @@ import styled from 'styled-components' import * as apiActions from '../../actions/api' import * as formActions from '../../actions/form' -import BatchSettingsPanel from '../form/batch-settings-panel' +import BatchSettings from '../form/batch-settings' import LocationField from '../form/connected-location-field' -import DateTimeModal from '../form/date-time-modal' -import ModeButtons, {MODE_OPTIONS, StyledModeButton} from '../form/mode-buttons' -// import UserSettings from '../form/user-settings' -import Icon from '../narrative/icon' import NarrativeItineraries from '../narrative/narrative-itineraries' -import { - BatchSettingsPanelContainer, - DateTimeModalContainer, - Dot, - MainSettingsRow, - PlanTripButton, - SettingsPreview, - StyledDateTimePreview -} from './styled' -import { hasValidLocation, getActiveSearch, getShowUserSettings } from '../../util/state' +import { getActiveSearch, getShowUserSettings } from '../../util/state' import ViewerContainer from '../viewers/viewer-container' -/** - * Simple utility to check whether a list of mode strings contains the provided - * mode. This handles exact match and prefix/suffix matches (i.e., checking - * 'BICYCLE' will return true if 'BICYCLE' or 'BICYCLE_RENT' is in the list). - * - * FIXME: This might need to be modified to be a bit looser in how it handles - * the 'contains' check. E.g., we might not want to remove WALK,TRANSIT if walk - * is turned off, but we DO want to remove it if TRANSIT is turned off. - */ -function listHasMode (modes, mode) { - return modes.some(m => mode.indexOf(m) !== -1) -} - -function combinationHasAnyOfModes (combination, modes) { - return combination.mode.split(',').some(m => listHasMode(modes, m)) -} - -// List of possible modes that can be selected via mode buttons. -const POSSIBLE_MODES = MODE_OPTIONS.map(b => b.mode) - -const ModeButtonsFullWidthContainer = styled.div` - display: flex; - justify-content: space-between; - margin-bottom: 5px; -` - -// Define Mode Button styled components here to avoid circular imports. I.e., we -// cannot define them in styled.js (because mode-buttons.js imports buttonCss -// and then we would need to import ModeButtons/StyledModeButton from that file -// in turn). -const StyledModeButtonsFullWidth = styled(ModeButtons)` - &:last-child { - margin-right: 0px; - } -` - -const ModeButtonsContainerCompressed = styled.div` - display: contents; -` - -const ModeButtonsCompressed = styled(ModeButtons)` - ${StyledModeButton} { - border-radius: 0px; - } - &:first-child { - border-radius: 5px 0px 0px 5px; - } - &:last-child { - margin-right: 5px; - border-radius: 0px 5px 5px 0px; - } -` // Style for setting the top of the narrative itineraries based on the width of the window. // If the window width is less than 1200px (Bootstrap's "large" size), the // mode buttons will be shown on their own row, meaning that the @@ -97,56 +32,8 @@ const NarrativeContainer = styled.div` * Main panel for the batch/trip comparison form. */ class BatchRoutingPanel extends Component { - state = { - expanded: null, - selectedModes: POSSIBLE_MODES - } - - _onClickMode = (mode) => { - const {possibleCombinations, setQueryParam} = this.props - const {selectedModes} = this.state - const index = selectedModes.indexOf(mode) - const enableMode = index === -1 - const newModes = [...selectedModes] - if (enableMode) newModes.push(mode) - else newModes.splice(index, 1) - // Update selected modes for mode buttons. - this.setState({selectedModes: newModes}) - // Update the available mode combinations based on the new modes selection. - const disabledModes = POSSIBLE_MODES.filter(m => !newModes.includes(m)) - // Do not include combination if any of its modes are found in disabled - // modes list. - const newCombinations = possibleCombinations - .filter(c => !combinationHasAnyOfModes(c, disabledModes)) - setQueryParam({combinations: newCombinations}) - } - - _planTrip = () => { - const {currentQuery, routingQuery} = this.props - // Check for any validation issues in query. - const issues = [] - if (!hasValidLocation(currentQuery, 'from')) issues.push('from') - if (!hasValidLocation(currentQuery, 'to')) issues.push('to') - if (issues.length > 0) { - // TODO: replace with less obtrusive validation. - window.alert(`Please define the following fields to plan a trip: ${issues.join(', ')}`) - return - } - // Close any expanded panels. - this.setState({expanded: null}) - // Plan trip. - routingQuery() - } - - _updateExpanded = (type) => ({expanded: this.state.expanded === type ? null : type}) - - _toggleDateTime = () => this.setState(this._updateExpanded('DATE_TIME')) - - _toggleSettings = () => this.setState(this._updateExpanded('SETTINGS')) - render () { - const {config, currentQuery, mobile} = this.props - const {expanded, selectedModes} = this.state + const {mobile} = this.props const actionText = mobile ? 'tap' : 'click' return ( @@ -160,52 +47,7 @@ class BatchRoutingPanel extends Component { locationType='to' showClearButton={!mobile} /> - - - - - - {coreUtils.query.isNotDefaultQuery(currentQuery, config) && - - } - - - - - - - - - - - {expanded === 'DATE_TIME' && - - - - } - {expanded === 'SETTINGS' && - - - - } + {/* FIXME: Add back user settings (home, work, etc.) once connected to the middleware persistence. !activeSearch && showUserSettings && diff --git a/lib/components/app/styled.js b/lib/components/app/styled.js deleted file mode 100644 index 71b92d005..000000000 --- a/lib/components/app/styled.js +++ /dev/null @@ -1,97 +0,0 @@ -import styled, {css} from 'styled-components' - -import DateTimePreview from '../form/date-time-preview' - -const SHADOW = 'inset 0px 0px 5px #c1c1c1' - -const activeCss = css` - background: #e5e5e5; - -webkit-box-shadow: ${SHADOW}; - -moz-box-shadow: ${SHADOW}; - box-shadow: ${SHADOW}; - outline: none; -` - -export const buttonCss = css` - height: 45px; - width: 45px; - margin: 0px; - border: 0px; - border-radius: 5px; - &:active { - ${activeCss} - } -` - -export const Button = styled.button` - ${buttonCss} -` - -export const StyledDateTimePreview = styled(DateTimePreview)` - ${buttonCss} - background-color: rgb(239, 239, 239); - cursor: pointer; - font-size: 12px; - margin-right: 5px; - padding: 7px 5px; - text-align: left; - white-space: nowrap; - width: 120px; - ${props => props.expanded ? activeCss : null} -` -export const SettingsPreview = styled(Button)` - line-height: 22px; - margin-right: 5px; - padding: 10px 0px; - position: relative; - ${props => props.expanded ? activeCss : null} -` - -export const Dot = styled.div` - position: absolute; - top: -3px; - right: -3px; - width: 10px; - height: 10px; - border-radius: 5px; - background-color: #f00; -` - -export const PlanTripButton = styled(Button)` - background-color: #F5F5A7; - margin-left: auto; - padding: 5px; - &:active { - ${activeCss} - background-color: #ededaf - } -` - -const expandableBoxCss = css` - background-color: rgb(239, 239, 239); - box-shadow: rgba(0, 0, 0, 0.32) 7px 12px 10px; - height: 245px; - border-radius: 5px 5px 5px 5px; - left: 10px; - position: absolute; - right: 10px; - z-index: 99999; -` - -export const DateTimeModalContainer = styled.div` - ${expandableBoxCss} - padding: 10px 20px; -` - -export const BatchSettingsPanelContainer = styled.div` - ${expandableBoxCss} - padding: 5px 10px; -` - -export const MainSettingsRow = styled.div` - align-items: top; - display: flex; - flex-direction: row; - justify-content: flex-start; - margin-bottom: 5px; -` diff --git a/lib/components/form/batch-settings-panel.js b/lib/components/form/batch-preferences.js similarity index 94% rename from lib/components/form/batch-settings-panel.js rename to lib/components/form/batch-preferences.js index 4e5dbb0e0..29718eac2 100644 --- a/lib/components/form/batch-settings-panel.js +++ b/lib/components/form/batch-preferences.js @@ -6,10 +6,10 @@ import { setQueryParam } from '../../actions/form' import { ComponentContext } from '../../util/contexts' import { getShowUserSettings } from '../../util/state' -import { StyledBatchSettingsPanel } from './styled' +import { StyledBatchPreferences } from './batch-styled' import UserTripSettings from './user-trip-settings' -class BatchSettingsPanel extends Component { +class BatchPreferences extends Component { static contextType = ComponentContext render () { @@ -26,7 +26,7 @@ class BatchSettingsPanel extends Component {
{showUserSettings && } - mode.indexOf(m) !== -1) +} + +function combinationHasAnyOfModes (combination, modes) { + return combination.mode.split(',').some(m => listHasMode(modes, m)) +} + +// List of possible modes that can be selected via mode buttons. +const POSSIBLE_MODES = MODE_OPTIONS.map(b => b.mode) + +const ModeButtonsFullWidthContainer = styled.div` + display: flex; + justify-content: space-between; + margin-bottom: 5px; +` + +// Define Mode Button styled components here to avoid circular imports. I.e., we +// cannot define them in styled.js (because mode-buttons.js imports buttonCss +// and then we would need to import ModeButtons/StyledModeButton from that file +// in turn). +const StyledModeButtonsFullWidth = styled(ModeButtons)` + &:last-child { + margin-right: 0px; + } +` + +const ModeButtonsContainerCompressed = styled.div` + display: contents; +` + +const ModeButtonsCompressed = styled(ModeButtons)` + ${StyledModeButton} { + border-radius: 0px; + } + &:first-child { + border-radius: 5px 0px 0px 5px; + } + &:last-child { + margin-right: 5px; + border-radius: 0px 5px 5px 0px; + } +` + +/** + * Main panel for the batch/trip comparison form. + */ +class BatchSettings extends Component { + state = { + expanded: null, + selectedModes: POSSIBLE_MODES + } + + _onClickMode = (mode) => { + const {possibleCombinations, setQueryParam} = this.props + const {selectedModes} = this.state + const index = selectedModes.indexOf(mode) + const enableMode = index === -1 + const newModes = [...selectedModes] + if (enableMode) newModes.push(mode) + else newModes.splice(index, 1) + // Update selected modes for mode buttons. + this.setState({selectedModes: newModes}) + // Update the available mode combinations based on the new modes selection. + const disabledModes = POSSIBLE_MODES.filter(m => !newModes.includes(m)) + // Do not include combination if any of its modes are found in disabled + // modes list. + const newCombinations = possibleCombinations + .filter(c => !combinationHasAnyOfModes(c, disabledModes)) + setQueryParam({combinations: newCombinations}) + } + + _planTrip = () => { + const {currentQuery, routingQuery} = this.props + // Check for any validation issues in query. + const issues = [] + if (!hasValidLocation(currentQuery, 'from')) issues.push('from') + if (!hasValidLocation(currentQuery, 'to')) issues.push('to') + if (issues.length > 0) { + // TODO: replace with less obtrusive validation. + window.alert(`Please define the following fields to plan a trip: ${issues.join(', ')}`) + return + } + // Close any expanded panels. + this.setState({expanded: null}) + // Plan trip. + routingQuery() + } + + _updateExpanded = (type) => ({expanded: this.state.expanded === type ? null : type}) + + _toggleDateTime = () => this.setState(this._updateExpanded('DATE_TIME')) + + _toggleSettings = () => this.setState(this._updateExpanded('SETTINGS')) + + render () { + const {config, currentQuery} = this.props + const {expanded, selectedModes} = this.state + return ( + <> + + + + + + {coreUtils.query.isNotDefaultQuery(currentQuery, config) && + + } + + + + + + + + + + + {expanded === 'DATE_TIME' && + + + + } + {expanded === 'SETTINGS' && + + + + } + + ) + } +} + +// connect to the redux store +const mapStateToProps = (state, ownProps) => { + const showUserSettings = getShowUserSettings(state.otp) + return { + activeSearch: getActiveSearch(state.otp), + config: state.otp.config, + currentQuery: state.otp.currentQuery, + expandAdvanced: state.otp.user.expandAdvanced, + possibleCombinations: state.otp.config.modes.combinations, + showUserSettings + } +} + +const mapDispatchToProps = { + routingQuery: apiActions.routingQuery, + setQueryParam: formActions.setQueryParam +} + +export default connect(mapStateToProps, mapDispatchToProps)(BatchSettings) diff --git a/lib/components/form/batch-styled.js b/lib/components/form/batch-styled.js new file mode 100644 index 000000000..7bd3fbb38 --- /dev/null +++ b/lib/components/form/batch-styled.js @@ -0,0 +1,222 @@ +import * as TripFormClasses from '@opentripplanner/trip-form/lib/styled' +import { SettingsSelectorPanel } from '@opentripplanner/trip-form' +import styled, {css} from 'styled-components' + +import DateTimePreview from './date-time-preview' +import {commonInputCss, modeButtonButtonCss} from './styled' + +const SHADOW = 'inset 0px 0px 5px #c1c1c1' + +const activeCss = css` + background: #e5e5e5; + -webkit-box-shadow: ${SHADOW}; + -moz-box-shadow: ${SHADOW}; + box-shadow: ${SHADOW}; + outline: none; +` + +export const buttonCss = css` + height: 45px; + width: 45px; + margin: 0px; + border: 0px; + border-radius: 5px; + &:active { + ${activeCss} + } +` + +export const Button = styled.button` + ${buttonCss} +` + +export const StyledDateTimePreview = styled(DateTimePreview)` + ${buttonCss} + background-color: rgb(239, 239, 239); + cursor: pointer; + font-size: 12px; + margin-right: 5px; + padding: 7px 5px; + text-align: left; + white-space: nowrap; + width: 120px; + ${props => props.expanded ? activeCss : null} +` +export const SettingsPreview = styled(Button)` + line-height: 22px; + margin-right: 5px; + padding: 10px 0px; + position: relative; + ${props => props.expanded ? activeCss : null} +` + +export const PlanTripButton = styled(Button)` + background-color: #F5F5A7; + margin-left: auto; + padding: 5px; + &:active { + ${activeCss} + background-color: #ededaf + } +` + +const expandableBoxCss = css` + background-color: rgb(239, 239, 239); + box-shadow: rgba(0, 0, 0, 0.32) 7px 12px 10px; + height: 245px; + border-radius: 5px 5px 5px 5px; + left: 10px; + position: absolute; + right: 10px; + z-index: 99999; +` + +export const DateTimeModalContainer = styled.div` + ${expandableBoxCss} + padding: 10px 20px; +` + +export const BatchPreferencesContainer = styled.div` + ${expandableBoxCss} + padding: 5px 10px; +` + +export const MainSettingsRow = styled.div` + align-items: top; + display: flex; + flex-direction: row; + justify-content: flex-start; + margin-bottom: 5px; +` + +// FIXME: This is identical to StyledSettingsSelectorPanel, with a +// couple of items set to display: none (SettingsHeader and ModeSelector) +export const StyledBatchPreferences = styled(SettingsSelectorPanel)` + ${modeButtonButtonCss} + + ${TripFormClasses.SettingLabel} { + color: #808080; + font-size: 14px; + font-weight: 100; + letter-spacing: 1px; + padding-top: 8px; + text-transform: uppercase; + } + ${TripFormClasses.SettingsHeader} { + display: none; + color: #333333; + font-size: 18px; + margin: 16px 0px; + } + ${TripFormClasses.SettingsSection} { + margin-bottom: 16px; + } + ${TripFormClasses.DropdownSelector} { + select { + ${commonInputCss} + -webkit-appearance: none; + border-radius: 3px; + font-size: 14px; + height: 34px; + line-height: 1.42857; + margin-bottom: 20px; + + &:focus { + border-color: #66afe9; + box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102,175,233,.6); + outline: 0; + } + } + > div:last-child::after { + box-sizing: border-box; + color: #000; + content: "▼"; + font-size: 67%; + pointer-events: none; + position: absolute; + right: 8px; + top: 10px; + } + } + + ${TripFormClasses.ModeSelector} { + display: none; + font-weight: 300; + ${TripFormClasses.ModeButton.Button} { + box-shadow: none; + outline: none; + padding: 3px; + } + ${TripFormClasses.ModeButton.Title} { + font-size: 10px; + line-height: 12px; + padding: 4px 0px 0px; + + &.active { + font-weight: 600; + } + } + } + ${TripFormClasses.ModeSelector.MainRow} { + box-sizing: border-box; + font-size: 170%; + margin: 0px -10px 18px; + padding: 0px 5px; + ${TripFormClasses.ModeButton.Button} { + height: 54px; + width: 100%; + &.active { + font-weight: 600; + } + } + } + ${TripFormClasses.ModeSelector.SecondaryRow} { + margin: 0px -10px 10px; + ${TripFormClasses.ModeButton.Button} { + font-size: 130%; + font-weight: 800; + height: 46px; + > svg { + margin: 0 0.20em; + } + } + } + ${TripFormClasses.ModeSelector.TertiaryRow} { + font-size: 80%; + font-weight: 300; + margin: 0px -10px 10px; + text-align: center; + ${TripFormClasses.ModeButton.Button} { + height: 36px; + } + } + ${TripFormClasses.SubmodeSelector.Row} { + font-size: 12px; + > * { + padding: 3px 5px 3px 0px; + } + > :last-child { + padding-right: 0px; + } + ${TripFormClasses.ModeButton.Button} { + height: 35px; + } + svg, + img { + margin-left: 0px; + } + } + ${TripFormClasses.SubmodeSelector} { + ${TripFormClasses.SettingLabel} { + margin-bottom: 0; + } + } + ${TripFormClasses.SubmodeSelector.InlineRow} { + margin: -3px 0px; + svg, + img { + height: 18px; + max-width: 32px; + } + } +` diff --git a/lib/components/form/mode-buttons.js b/lib/components/form/mode-buttons.js index 735573c57..5dd575aad 100644 --- a/lib/components/form/mode-buttons.js +++ b/lib/components/form/mode-buttons.js @@ -3,7 +3,7 @@ import styled from 'styled-components' import Icon from '../narrative/icon' import { ComponentContext } from '../../util/contexts' -import {buttonCss} from '../app/styled' +import {buttonCss} from './batch-styled' export const MODE_OPTIONS = [ { diff --git a/lib/components/form/settings-preview.js b/lib/components/form/settings-preview.js index 212631025..8e8d26ba5 100644 --- a/lib/components/form/settings-preview.js +++ b/lib/components/form/settings-preview.js @@ -4,7 +4,7 @@ import React, { Component } from 'react' import { Button } from 'react-bootstrap' import { connect } from 'react-redux' -import { Dot } from '../app/styled' +import { Dot } from './styled' import { mergeMessages } from '../../util/messages' class SettingsPreview extends Component { diff --git a/lib/components/form/styled.js b/lib/components/form/styled.js index c7ccb2e80..9c2bede6c 100644 --- a/lib/components/form/styled.js +++ b/lib/components/form/styled.js @@ -26,7 +26,7 @@ const commonButtonCss = css` } ` -const commonInputCss = css` +export const commonInputCss = css` background: none; border: 1px solid #ccc; box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075); @@ -43,137 +43,17 @@ export const modeButtonButtonCss = css` } ` -export const StyledSettingsSelectorPanel = styled(SettingsSelectorPanel)` - ${modeButtonButtonCss} - - ${TripFormClasses.SettingLabel} { - color: #808080; - font-size: 14px; - font-weight: 100; - letter-spacing: 1px; - padding-top: 8px; - text-transform: uppercase; - } - ${TripFormClasses.SettingsHeader} { - color: #333333; - font-size: 18px; - margin: 16px 0px; - } - ${TripFormClasses.SettingsSection} { - margin-bottom: 16px; - } - ${TripFormClasses.DropdownSelector} { - select { - ${commonInputCss} - -webkit-appearance: none; - border-radius: 3px; - font-size: 14px; - height: 34px; - line-height: 1.42857; - margin-bottom: 20px; - - &:focus { - border-color: #66afe9; - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102,175,233,.6); - outline: 0; - } - } - > div:last-child::after { - box-sizing: border-box; - color: #000; - content: "▼"; - font-size: 67%; - pointer-events: none; - position: absolute; - right: 8px; - top: 10px; - } - } - - ${TripFormClasses.ModeSelector} { - font-weight: 300; - ${TripFormClasses.ModeButton.Button} { - box-shadow: none; - outline: none; - padding: 3px; - } - ${TripFormClasses.ModeButton.Title} { - font-size: 10px; - line-height: 12px; - padding: 4px 0px 0px; - - &.active { - font-weight: 600; - } - } - } - ${TripFormClasses.ModeSelector.MainRow} { - box-sizing: border-box; - font-size: 170%; - margin: 0px -10px 18px; - padding: 0px 5px; - ${TripFormClasses.ModeButton.Button} { - height: 54px; - width: 100%; - &.active { - font-weight: 600; - } - } - } - ${TripFormClasses.ModeSelector.SecondaryRow} { - margin: 0px -10px 10px; - ${TripFormClasses.ModeButton.Button} { - font-size: 130%; - font-weight: 800; - height: 46px; - > svg { - margin: 0 0.20em; - } - } - } - ${TripFormClasses.ModeSelector.TertiaryRow} { - font-size: 80%; - font-weight: 300; - margin: 0px -10px 10px; - text-align: center; - ${TripFormClasses.ModeButton.Button} { - height: 36px; - } - } - ${TripFormClasses.SubmodeSelector.Row} { - font-size: 12px; - > * { - padding: 3px 5px 3px 0px; - } - > :last-child { - padding-right: 0px; - } - ${TripFormClasses.ModeButton.Button} { - height: 35px; - } - svg, - img { - margin-left: 0px; - } - } - ${TripFormClasses.SubmodeSelector} { - ${TripFormClasses.SettingLabel} { - margin-bottom: 0; - } - } - ${TripFormClasses.SubmodeSelector.InlineRow} { - margin: -3px 0px; - svg, - img { - height: 18px; - max-width: 32px; - } - } +export const Dot = styled.div` + position: absolute; + top: -3px; + right: -3px; + width: 10px; + height: 10px; + border-radius: 5px; + background-color: #f00; ` -// FIXME: This is identical to StyledSettingsSelectorPanel, with a -// couple of items set to display: none (SettingsHeader and ModeSelector) -export const StyledBatchSettingsPanel = styled(SettingsSelectorPanel)` +export const StyledSettingsSelectorPanel = styled(SettingsSelectorPanel)` ${modeButtonButtonCss} ${TripFormClasses.SettingLabel} { @@ -185,7 +65,6 @@ export const StyledBatchSettingsPanel = styled(SettingsSelectorPanel)` text-transform: uppercase; } ${TripFormClasses.SettingsHeader} { - display: none; color: #333333; font-size: 18px; margin: 16px 0px; @@ -222,7 +101,6 @@ export const StyledBatchSettingsPanel = styled(SettingsSelectorPanel)` } ${TripFormClasses.ModeSelector} { - display: none; font-weight: 300; ${TripFormClasses.ModeButton.Button} { box-shadow: none; diff --git a/lib/components/mobile/batch-search-screen.js b/lib/components/mobile/batch-search-screen.js new file mode 100644 index 000000000..e6582fa96 --- /dev/null +++ b/lib/components/mobile/batch-search-screen.js @@ -0,0 +1,71 @@ +import React, { Component } from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' + +import BatchSettings from '../form/batch-settings' +import DefaultMap from '../map/default-map' +import LocationField from '../form/connected-location-field' +import SwitchButton from '../form/switch-button' + +import MobileContainer from './container' +import MobileNavigationBar from './navigation-bar' + +import { MobileScreens, setMobileScreen } from '../../actions/ui' + +const { + SET_DATETIME, + SET_FROM_LOCATION, + SET_TO_LOCATION +} = MobileScreens + +class BatchSearchScreen extends Component { + static propTypes = { + map: PropTypes.element, + setMobileScreen: PropTypes.func + } + + _fromFieldClicked = () => this.props.setMobileScreen(SET_FROM_LOCATION) + + _toFieldClicked = () => this.props.setMobileScreen(SET_TO_LOCATION) + + _expandDateTimeClicked = () => this.props.setMobileScreen(SET_DATETIME) + + render () { + return ( + + +
+ + +
+ } /> +
+ +
+
+ +
+
+ ) + } +} + +// connect to the redux store + +const mapStateToProps = (state, ownProps) => { + return { } +} + +const mapDispatchToProps = { + setMobileScreen +} + +export default connect(mapStateToProps, mapDispatchToProps)(BatchSearchScreen) diff --git a/lib/components/mobile/main.js b/lib/components/mobile/main.js index a7ae607d2..03463e90b 100644 --- a/lib/components/mobile/main.js +++ b/lib/components/mobile/main.js @@ -2,6 +2,7 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' +import BatchSearchScreen from './batch-search-screen' import MobileDateTimeScreen from './date-time-screen' import MobileOptionsScreen from './options-screen' import MobileLocationSearch from './location-search' @@ -13,6 +14,7 @@ import MobileTripViewer from './trip-viewer' import MobileRouteViewer from './route-viewer' import { MobileScreens, MainPanelContent, setMobileScreen } from '../../actions/ui' +import { isBatchRoutingEnabled } from '../../util/itinerary' import { getActiveItinerary } from '../../util/state' class MobileMain extends Component { @@ -43,7 +45,7 @@ class MobileMain extends Component { } render () { - const { map, title, uiState } = this.props + const { config, map, title, uiState } = this.props // check for route viewer if (uiState.mainPanelContent === MainPanelContent.ROUTE_VIEWER) { @@ -69,8 +71,13 @@ class MobileMain extends Component { ) case MobileScreens.SEARCH_FORM: + // Render batch search screen if batch routing enabled. Otherwise, + // default to standard search screen. + const SearchScreen = isBatchRoutingEnabled(config) + ? BatchSearchScreen + : MobileSearchScreen return ( - @@ -112,6 +119,7 @@ class MobileMain extends Component { const mapStateToProps = (state, ownProps) => { return { + config: state.otp.config, uiState: state.otp.ui, currentQuery: state.otp.currentQuery, currentPosition: state.otp.location.currentPosition, diff --git a/lib/components/mobile/mobile.css b/lib/components/mobile/mobile.css index 679e44a63..1e6475c6e 100644 --- a/lib/components/mobile/mobile.css +++ b/lib/components/mobile/mobile.css @@ -96,6 +96,7 @@ left: 0; right: 0; height: 250px; + box-shadow: 3px 0px 12px #00000052; } .otp.mobile .search-map { @@ -106,6 +107,26 @@ bottom: 0; } +/* Batch routing search screen */ + +.otp.mobile .batch-search-settings { + position: fixed; + top: 50px; + left: 0; + right: 0; + height: 216px; + z-index: 99999999; + box-shadow: 3px 0px 12px #00000052; +} + +.otp.mobile .batch-search-map { + position: fixed; + top: 266px; + left: 0; + right: 0; + bottom: 0; +} + /* Detailed options screen */ .otp.mobile .options-main-content { From 0252d7035aae0752c076c4abce3f9a55e462f28a Mon Sep 17 00:00:00 2001 From: Landon Reed Date: Mon, 22 Feb 2021 09:44:20 -0500 Subject: [PATCH 2/9] refactor(batch-routing): remove redundant mode filter dropdown --- lib/components/narrative/narrative-itineraries.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/components/narrative/narrative-itineraries.js b/lib/components/narrative/narrative-itineraries.js index eb8585e9a..a96ba5a3d 100644 --- a/lib/components/narrative/narrative-itineraries.js +++ b/lib/components/narrative/narrative-itineraries.js @@ -152,17 +152,6 @@ class NarrativeItineraries extends Component { }}> {resultText}
- { // FIXME: Enable only when ITINERARY/BATCH routing type enabled. - - }
+
+ + ) + } - /* Old navbar alert - if (showRealtimeAnnotation) { - headerAction = ( - - ) - */ + renderLocationsSummary = () => { + const { query } = this.props - const locationsSummary = ( + return ( @@ -156,29 +161,34 @@ class MobileResultsScreen extends Component { ) + } - if (error) { - return ( - - - {locationsSummary} -
-
- -
- -
-
-
- ) - } + render () { + const { + activeItineraryIndex, + error, + realtimeEffects, + resultCount, + useRealtime + } = this.props + const { expanded } = this.state - // Construct the 'dots' - const dots = [] - for (let i = 0; i < resultCount; i++) { - dots.push(
) + const narrativeContainerStyle = expanded + ? { top: 140, overflowY: 'auto' } + : { height: 80, overflowY: 'hidden' } + + // Ensure that narrative covers map. + narrativeContainerStyle.backgroundColor = 'white' + + let headerAction = null + const showRealtimeAnnotation = realtimeEffects.isAffectedByRealtimeData && ( + realtimeEffects.exceedsThreshold || + realtimeEffects.routesDiffer || + !useRealtime + ) + + if (error) { + return this.renderError() } return ( @@ -190,10 +200,10 @@ class MobileResultsScreen extends Component { } headerAction={headerAction} /> - {locationsSummary} + {this.renderLocationsSummary()}
- {this.props.map} +
- -
{dots}
+ {this.renderDots()} ) } diff --git a/lib/components/mobile/welcome-screen.js b/lib/components/mobile/welcome-screen.js index d31712c05..31ced700b 100644 --- a/lib/components/mobile/welcome-screen.js +++ b/lib/components/mobile/welcome-screen.js @@ -12,8 +12,6 @@ import { setLocationToCurrent } from '../../actions/map' class MobileWelcomeScreen extends Component { static propTypes = { - map: PropTypes.element, - setLocationToCurrent: PropTypes.func, setMobileScreen: PropTypes.func } @@ -36,10 +34,9 @@ class MobileWelcomeScreen extends Component { } render () { - const { title } = this.props return ( - +
({ ...l, type: 'suggested' }))) @@ -243,8 +243,8 @@ export function getInitialState (userDefinedConfig, initialQuery) { } } -function createOtpReducer (config, initialQuery) { - const initialState = getInitialState(config, initialQuery) +function createOtpReducer (config) { + const initialState = getInitialState(config) // validate the initial state validateInitialState(initialState) From a1e63b3cd18544d40eeae993ecaaa4933f88072c Mon Sep 17 00:00:00 2001 From: Evan Siroky Date: Tue, 9 Mar 2021 16:27:33 -0800 Subject: [PATCH 6/9] refactor: refactor ResponsiveWebapp and some other things BREAKING CHANGE: refactored example.js, ResponsiveWebapp and associated component signatures to use components provided to component context --- __tests__/reducers/create-otp-reducer.js | 2 +- __tests__/test-utils/mock-data/store.js | 7 +- example.js | 156 ++++++------------ lib/components/app/batch-routing-panel.js | 1 - lib/components/app/responsive-webapp.js | 48 +++++- lib/components/mobile/main.js | 23 +-- lib/components/mobile/navigation-bar.js | 12 +- lib/components/mobile/results-screen.js | 131 ++++++++------- lib/components/mobile/welcome-screen.js | 5 +- .../narrative/narrative-itineraries.js | 1 - lib/index.js | 11 +- lib/reducers/create-otp-reducer.js | 8 +- 12 files changed, 200 insertions(+), 205 deletions(-) diff --git a/__tests__/reducers/create-otp-reducer.js b/__tests__/reducers/create-otp-reducer.js index 05fcdf475..979268d0b 100644 --- a/__tests__/reducers/create-otp-reducer.js +++ b/__tests__/reducers/create-otp-reducer.js @@ -6,6 +6,6 @@ describe('lib > reducers > create-otp-reducer', () => { it('should be able to create the initial state', () => { setDefaultTestTime() - expect(getInitialState({}, {})).toMatchSnapshot() + expect(getInitialState({})).toMatchSnapshot() }) }) diff --git a/__tests__/test-utils/mock-data/store.js b/__tests__/test-utils/mock-data/store.js index 90e7a696e..724435f0d 100644 --- a/__tests__/test-utils/mock-data/store.js +++ b/__tests__/test-utils/mock-data/store.js @@ -22,10 +22,11 @@ const storeMiddleWare = [ * Get the initial stop of the redux reducer for otp-rr */ export function getMockInitialState () { - const mockConfig = {} - const mockInitialQuery = {} + const mockConfig = { + initialQuery: {} + } return clone({ - otp: getInitialState(mockConfig, mockInitialQuery), + otp: getInitialState(mockConfig), router: connectRouter(history) }) } diff --git a/example.js b/example.js index 1845f3ee5..0f4484e8c 100644 --- a/example.js +++ b/example.js @@ -4,35 +4,37 @@ import 'es6-math' import {ClassicLegIcon, ClassicModeIcon} from '@opentripplanner/icons' import { createHashHistory } from 'history' import { connectRouter, routerMiddleware } from 'connected-react-router' -import React, { Component } from 'react' +import React from 'react' import { render } from 'react-dom' import { createStore, combineReducers, applyMiddleware, compose } from 'redux' import { Provider } from 'react-redux' import thunk from 'redux-thunk' import createLogger from 'redux-logger' -// import Bootstrap Grid components for layout -import { Grid, Row, Col } from 'react-bootstrap' - // import OTP-RR components import { + BatchRoutingPanel, + BatchSearchScreen, CallTakerControls, CallTakerPanel, CallTakerWindows, DefaultItinerary, DefaultMainPanel, - DesktopNav, - BatchRoutingPanel, - Map, - MobileMain, + MobileSearchScreen, ResponsiveWebapp, createCallTakerReducer, createOtpReducer, - createUserReducer + createUserReducer, + otpUtils } from './lib' // load the OTP configuration import otpConfig from './config.yml' +const isBatchRoutingEnabled = otpUtils.itinerary.isBatchRoutingEnabled( + otpConfig +) +const isCallTakerModuleEnabled = !!otpConfig.datastoreUrl + // Set useCustomIcons to true to override classic icons with the exports from // custom-icons.js const useCustomIcons = false @@ -49,18 +51,32 @@ if (useCustomIcons) { // define some application-wide components that should be used in // various places. The following components can be provided here: +// - defaultMobileTitle (required) // - ItineraryBody (required) // - ItineraryFooter (optional) // - LegIcon (required) +// - MainControls (optional) +// - MainPanel (required) +// - MapWindows (optional) +// - MobileSearchScreen (required) // - ModeIcon (required) const components = { + defaultMobileTitle: () =>
OpenTripPlanner
, ItineraryBody: DefaultItinerary, LegIcon: MyLegIcon, + MainControls: isCallTakerModuleEnabled ? CallTakerControls : null, + MainPanel: isCallTakerModuleEnabled + ? CallTakerPanel + : isBatchRoutingEnabled + ? BatchRoutingPanel + : DefaultMainPanel, + MapWindows: isCallTakerModuleEnabled ? CallTakerWindows : null, + MobileSearchScreen: isBatchRoutingEnabled + ? BatchSearchScreen + : MobileSearchScreen, ModeIcon: MyModeIcon } -// Get the initial query from config (for demo/testing purposes). -const {initialQuery} = otpConfig const history = createHashHistory() const middleware = [ thunk, @@ -76,109 +92,41 @@ if (process.env.NODE_ENV === 'development') { const store = createStore( combineReducers({ callTaker: createCallTakerReducer(), - otp: createOtpReducer(otpConfig, initialQuery), + otp: createOtpReducer(otpConfig), user: createUserReducer(), router: connectRouter(history) }), compose(applyMiddleware(...middleware)) ) -// define a simple responsive UI using Bootstrap and OTP-RR -class OtpRRExample extends Component { - render () { - /** desktop view **/ - const desktopView = ( -
- - - - - {/* - Note: the main tag provides a way for users of screen readers - to skip to the primary page content. - TODO: Find a better place. - */} -
- {/* TODO: extract the BATCH elements out of CallTakerPanel. */} - {otpConfig.datastoreUrl - ? - : otpConfig.routingTypes.find(t => t.key === 'BATCH') - ? - : - } -
- - {otpConfig.datastoreUrl ? : null} - - {otpConfig.datastoreUrl ? : null} - - -
-
-
- ) - - /** mobile view **/ - const mobileView = ( - //
Needed for accessibility checks. TODO: Find a better place. -
- } - title={
OpenTripPlanner
} - /> -
- ) - - /** - * The main webapp. - * - * Note: the ResponsiveWebapp creates a React context provider - * (./util/contexts#ComponentContext to be specific) to supply custom - * components to various other subcomponents throughout otp-react-redux. If - * the ResponsiveWebapp is not used and instead some subcomponents that use - * the components in the `components` variable are imported and rendered - * outside of the ResponsiveWebapp component, then the ComponentContext will - * need to wrap that component in order for the subcomponents to be able to - * access the component context. For example: - * - * ```js - * import RouteViewer from 'otp-react-redux/build/components/viewers/route-viewer' - * import { ComponentContext } from 'otp-react-redux/build/util/contexts' - * - * const components = { - * ModeIcon: MyCustomModeIconComponent - * } - * const ContextAwareRouteViewer = () => ( - * - * - * - * ) - * ``` - */ - return ( - - ) - } -} - // render the app render( ( - { /** - * If not using router history, simply include OtpRRExample here: - * e.g. - * - */ - } - + {/** + * Note: the ResponsiveWebapp creates a React context provider + * (./util/contexts#ComponentContext to be specific) to supply custom + * components to various other subcomponents throughout otp-react-redux. If + * the ResponsiveWebapp is not used and instead some subcomponents that use + * the components in the `components` variable are imported and rendered + * outside of the ResponsiveWebapp component, then the ComponentContext will + * need to wrap that component in order for the subcomponents to be able to + * access the component context. For example: + * + * ```js + * import RouteViewer from 'otp-react-redux/build/components/viewers/route-viewer' + * import { ComponentContext } from 'otp-react-redux/build/util/contexts' + * + * const components = { ModeIcon: MyCustomModeIconComponent } + * const ContextAwareRouteViewer = () => ( + * + * + * + * ) + * ``` + */} + - ) - , - + ), document.getElementById('root') ) diff --git a/lib/components/app/batch-routing-panel.js b/lib/components/app/batch-routing-panel.js index 14fee5bc5..0cc9a36a8 100644 --- a/lib/components/app/batch-routing-panel.js +++ b/lib/components/app/batch-routing-panel.js @@ -1,4 +1,3 @@ -import coreUtils from '@opentripplanner/core-utils' import React, { Component } from 'react' import { connect } from 'react-redux' import styled from 'styled-components' diff --git a/lib/components/app/responsive-webapp.js b/lib/components/app/responsive-webapp.js index 7b2b9b27d..2d1ac0c4d 100644 --- a/lib/components/app/responsive-webapp.js +++ b/lib/components/app/responsive-webapp.js @@ -5,6 +5,7 @@ import isEqual from 'lodash.isequal' import coreUtils from '@opentripplanner/core-utils' import PropTypes from 'prop-types' import React, { Component } from 'react' +import { Col, Grid, Row } from 'react-bootstrap' import { connect } from 'react-redux' import { Redirect, Route, Switch, withRouter } from 'react-router' @@ -16,6 +17,9 @@ import * as formActions from '../../actions/form' import * as locationActions from '../../actions/location' import * as mapActions from '../../actions/map' import * as uiActions from '../../actions/ui' +import Map from '../map/map' +import MobileMain from '../mobile/main' +import DesktopNav from './desktop-nav' import { getAuth0Config } from '../../util/auth' import { ACCOUNT_PATH, @@ -39,12 +43,12 @@ const { isMobile } = coreUtils.ui class ResponsiveWebapp extends Component { static propTypes = { - desktopView: PropTypes.element, initZoomOnLocate: PropTypes.number, - mobileView: PropTypes.element, query: PropTypes.object } + static contextType = ComponentContext + /** Lifecycle methods **/ componentDidUpdate (prevProps) { @@ -144,9 +148,45 @@ class ResponsiveWebapp extends Component { window.removeEventListener('popstate', this.props.handleBackButtonPress) } + renderDesktopView = () => { + const { MainControls, MainPanel, MapWindows } = this.context + return ( +
+ + + + + {/* + Note: the main tag provides a way for users of screen readers + to skip to the primary page content. + TODO: Find a better place. + */} +
+ {} +
+ + {MainControls && } + + {MapWindows && } + + +
+
+
+ ) + } + + renderMobileView = () => { + return ( + //
Needed for accessibility checks. TODO: Find a better place. +
+ +
+ ) + } + render () { - const { desktopView, mobileView } = this.props - return isMobile() ? mobileView : desktopView + return isMobile() ? this.renderMobileView() : this.renderDesktopView() } } diff --git a/lib/components/mobile/main.js b/lib/components/mobile/main.js index 03463e90b..dc9eb2344 100644 --- a/lib/components/mobile/main.js +++ b/lib/components/mobile/main.js @@ -2,19 +2,17 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' -import BatchSearchScreen from './batch-search-screen' 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 MobileSearchScreen from './search-screen' import MobileStopViewer from './stop-viewer' import MobileTripViewer from './trip-viewer' import MobileRouteViewer from './route-viewer' import { MobileScreens, MainPanelContent, setMobileScreen } from '../../actions/ui' -import { isBatchRoutingEnabled } from '../../util/itinerary' +import { ComponentContext } from '../../util/contexts' import { getActiveItinerary } from '../../util/state' class MobileMain extends Component { @@ -26,6 +24,8 @@ class MobileMain extends Component { uiState: PropTypes.object } + static contextType = ComponentContext + componentDidUpdate (prevProps) { // Check if we are in the welcome screen and both locations have been set OR // auto-detect is denied and one location is set @@ -45,7 +45,8 @@ class MobileMain extends Component { } render () { - const { config, map, title, uiState } = this.props + const { MobileSearchScreen } = this.context + const { uiState } = this.props // check for route viewer if (uiState.mainPanelContent === MainPanelContent.ROUTE_VIEWER) { @@ -60,7 +61,7 @@ class MobileMain extends Component { switch (uiState.mobileScreen) { case MobileScreens.WELCOME_SCREEN: - return + return case MobileScreens.SET_INITIAL_LOCATION: return ( @@ -73,14 +74,8 @@ class MobileMain extends Component { case MobileScreens.SEARCH_FORM: // Render batch search screen if batch routing enabled. Otherwise, // default to standard search screen. - const SearchScreen = isBatchRoutingEnabled(config) - ? BatchSearchScreen - : MobileSearchScreen return ( - + ) case MobileScreens.SET_FROM_LOCATION: @@ -106,9 +101,7 @@ class MobileMain extends Component { return case MobileScreens.RESULTS_SUMMARY: - return ( - - ) + return default: return

Invalid mobile screen

} diff --git a/lib/components/mobile/navigation-bar.js b/lib/components/mobile/navigation-bar.js index cac315e1c..41d4e274e 100644 --- a/lib/components/mobile/navigation-bar.js +++ b/lib/components/mobile/navigation-bar.js @@ -8,6 +8,7 @@ import { setMobileScreen } from '../../actions/ui' import AppMenu from '../app/app-menu' import NavLoginButtonAuth0 from '../../components/user/nav-login-button-auth0' import { accountLinks, getAuth0Config } from '../../util/auth' +import { ComponentContext } from '../../util/contexts' class MobileNavigationBar extends Component { static propTypes = { @@ -15,10 +16,11 @@ class MobileNavigationBar extends Component { headerAction: PropTypes.element, headerText: PropTypes.string, showBackButton: PropTypes.bool, - setMobileScreen: PropTypes.func, - title: PropTypes.element + setMobileScreen: PropTypes.func } + static contextType = ComponentContext + _backButtonPressed = () => { const { backScreen, onBackClicked } = this.props if (backScreen) this.props.setMobileScreen(this.props.backScreen) @@ -26,12 +28,12 @@ class MobileNavigationBar extends Component { } render () { + const { defaultMobileTitle } = this.context const { auth0Config, headerAction, headerText, - showBackButton, - title + showBackButton } = this.props return ( @@ -49,7 +51,7 @@ class MobileNavigationBar extends Component {
{headerText ?
{headerText}
- :
{title}
+ :
{defaultMobileTitle}
}
diff --git a/lib/components/mobile/results-screen.js b/lib/components/mobile/results-screen.js index 4fe96e7d8..93bb9bb61 100644 --- a/lib/components/mobile/results-screen.js +++ b/lib/components/mobile/results-screen.js @@ -6,7 +6,7 @@ import { Button, Col, Row } from 'react-bootstrap' import { connect } from 'react-redux' import styled from 'styled-components' -import DefaultMap from '../map/default-map' +import Map from '../map/map' import ErrorMessage from '../form/error-message' import ItineraryCarousel from '../narrative/itinerary-carousel' @@ -55,10 +55,8 @@ const StyledLocationIcon = styled(LocationIcon)` class MobileResultsScreen extends Component { static propTypes = { activeItineraryIndex: PropTypes.number, - map: PropTypes.element, query: PropTypes.object, resultCount: PropTypes.number, - setMobileScreen: PropTypes.func } @@ -97,46 +95,53 @@ class MobileResultsScreen extends Component { this._setExpanded(!this.state.expanded) } - _toggleRealtime = () => this.props.setUseRealtimeResponse({useRealtime: !this.props.useRealtime}) + _toggleRealtime = () => this.props.setUseRealtimeResponse( + {useRealtime: !this.props.useRealtime} + ) - render () { - const { - activeItineraryIndex, - error, - query, - realtimeEffects, - resultCount, - useRealtime - } = this.props - const { expanded } = this.state + renderDots = () => { + const { activeItineraryIndex, resultCount } = this.props - const narrativeContainerStyle = expanded - ? { top: 140, overflowY: 'auto' } - : { height: 80, overflowY: 'hidden' } + // Construct the 'dots' + const dots = [] + for (let i = 0; i < resultCount; i++) { + dots.push( +
+ ) + } - // Ensure that narrative covers map. - narrativeContainerStyle.backgroundColor = 'white' + return ( +
{dots}
+ ) + } - let headerAction = null - const showRealtimeAnnotation = realtimeEffects.isAffectedByRealtimeData && ( - realtimeEffects.exceedsThreshold || - realtimeEffects.routesDiffer || - !useRealtime + renderError = () => { + const { error } = this.props + + return ( + + + {this.renderLocationsSummary()} +
+
+ +
+ +
+
+
) + } - /* Old navbar alert - if (showRealtimeAnnotation) { - headerAction = ( - - ) - */ + renderLocationsSummary = () => { + const { query } = this.props - const locationsSummary = ( + return ( @@ -156,29 +161,34 @@ class MobileResultsScreen extends Component { ) + } - if (error) { - return ( - - - {locationsSummary} -
-
- -
- -
-
-
- ) - } + render () { + const { + activeItineraryIndex, + error, + realtimeEffects, + resultCount, + useRealtime + } = this.props + const { expanded } = this.state - // Construct the 'dots' - const dots = [] - for (let i = 0; i < resultCount; i++) { - dots.push(
) + const narrativeContainerStyle = expanded + ? { top: 140, overflowY: 'auto' } + : { height: 80, overflowY: 'hidden' } + + // Ensure that narrative covers map. + narrativeContainerStyle.backgroundColor = 'white' + + let headerAction = null + const showRealtimeAnnotation = realtimeEffects.isAffectedByRealtimeData && ( + realtimeEffects.exceedsThreshold || + realtimeEffects.routesDiffer || + !useRealtime + ) + + if (error) { + return this.renderError() } return ( @@ -190,10 +200,10 @@ class MobileResultsScreen extends Component { } headerAction={headerAction} /> - {locationsSummary} + {this.renderLocationsSummary()}
- {this.props.map} +
- -
{dots}
+ {this.renderDots()} ) } diff --git a/lib/components/mobile/welcome-screen.js b/lib/components/mobile/welcome-screen.js index d31712c05..31ced700b 100644 --- a/lib/components/mobile/welcome-screen.js +++ b/lib/components/mobile/welcome-screen.js @@ -12,8 +12,6 @@ import { setLocationToCurrent } from '../../actions/map' class MobileWelcomeScreen extends Component { static propTypes = { - map: PropTypes.element, - setLocationToCurrent: PropTypes.func, setMobileScreen: PropTypes.func } @@ -36,10 +34,9 @@ class MobileWelcomeScreen extends Component { } render () { - const { title } = this.props return ( - +
({ ...l, type: 'suggested' }))) @@ -243,8 +243,8 @@ export function getInitialState (userDefinedConfig, initialQuery) { } } -function createOtpReducer (config, initialQuery) { - const initialState = getInitialState(config, initialQuery) +function createOtpReducer (config) { + const initialState = getInitialState(config) // validate the initial state validateInitialState(initialState) From 56336abc4970933a33e615233243084776049018 Mon Sep 17 00:00:00 2001 From: Evan Siroky Date: Tue, 9 Mar 2021 18:03:39 -0800 Subject: [PATCH 7/9] fix: make expanded itinerary body show up in ItineraryCarousel --- .../narrative/itinerary-carousel.js | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/lib/components/narrative/itinerary-carousel.js b/lib/components/narrative/itinerary-carousel.js index 631475db7..912126d88 100644 --- a/lib/components/narrative/itinerary-carousel.js +++ b/lib/components/narrative/itinerary-carousel.js @@ -86,17 +86,21 @@ class ItineraryCarousel extends Component { index={activeItinerary} onChangeIndex={this._onSwipe} > - {itineraries.map((itinerary, index) => ( - - ))} + {itineraries.map((itinerary, index) => { + const active = index === activeItinerary + return ( + + ) + })}
) From a217bc79739f6100008c2c332e9000ecd67661fc Mon Sep 17 00:00:00 2001 From: Landon Reed Date: Mon, 22 Feb 2021 10:32:19 -0500 Subject: [PATCH 8/9] refactor(batch-routing): fix lint, fully remove itin filter --- .../viewers/__snapshots__/stop-viewer.js.snap | 16 +++++++------- .../__snapshots__/create-otp-reducer.js.snap | 1 - .../narrative/narrative-itineraries.js | 22 ++++++++----------- lib/components/viewers/stop-time-cell.js | 2 +- lib/reducers/create-otp-reducer.js | 5 ++--- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap b/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap index 1de873e4f..47cd8838d 100644 --- a/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap +++ b/__tests__/components/viewers/__snapshots__/stop-viewer.js.snap @@ -874,7 +874,7 @@ exports[`components > viewers > stop viewer should render countdown times after >
viewers > stop viewer should render countdown times for st >
viewers > stop viewer should render times after midnight w >
viewers > stop viewer should render with OTP transit index >
viewers > stop viewer should render with OTP transit index >
viewers > stop viewer should render with OTP transit index >
viewers > stop viewer should render with OTP transit index >
viewers > stop viewer should render with TriMet transit in >
{ - const {sort, updateItineraryFilter} = this.props - const {value} = evt.target - updateItineraryFilter({filter: value, sort}) - } - _onSortChange = evt => { const {value: type} = evt.target - const {filter, sort, updateItineraryFilter} = this.props - updateItineraryFilter({filter, sort: {...sort, type}}) + const {sort, updateItineraryFilter} = this.props + updateItineraryFilter({sort: {...sort, type}}) } _onSortDirChange = () => { - const {filter, sort, updateItineraryFilter} = this.props + const {sort, updateItineraryFilter} = this.props const direction = sort.direction === 'ASC' ? 'DESC' : 'ASC' - updateItineraryFilter({filter, sort: {...sort, direction}}) + updateItineraryFilter({sort: {...sort, direction}}) } _toggleRealtimeItineraryClick = (e) => { @@ -157,7 +151,10 @@ class NarrativeItineraries extends Component { style={{marginRight: '5px'}}> - @@ -222,7 +219,7 @@ class NarrativeItineraries extends Component { const mapStateToProps = (state, ownProps) => { const activeSearch = getActiveSearch(state.otp) const {modes} = state.otp.config - const {filter, sort} = state.otp.filter + const {sort} = state.otp.filter const pending = activeSearch ? Boolean(activeSearch.pending) : false const itineraries = getActiveItineraries(state.otp) const realtimeEffects = getRealtimeEffects(state.otp) @@ -237,7 +234,6 @@ const mapStateToProps = (state, ownProps) => { activeItinerary: activeSearch && activeSearch.activeItinerary, activeLeg: activeSearch && activeSearch.activeLeg, activeStep: activeSearch && activeSearch.activeStep, - filter, modes, sort, timeFormat: coreUtils.time.getTimeFormat(state.otp.config), diff --git a/lib/components/viewers/stop-time-cell.js b/lib/components/viewers/stop-time-cell.js index 2bf548394..4ff44cefa 100644 --- a/lib/components/viewers/stop-time-cell.js +++ b/lib/components/viewers/stop-time-cell.js @@ -58,7 +58,7 @@ const StopTimeCell = ({ return (
-
+
Date: Wed, 10 Mar 2021 15:20:13 -0500 Subject: [PATCH 9/9] refactor(batch-settings): remove unused import --- lib/components/form/batch-settings.js | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/components/form/batch-settings.js b/lib/components/form/batch-settings.js index 818eadbc7..88deaadac 100644 --- a/lib/components/form/batch-settings.js +++ b/lib/components/form/batch-settings.js @@ -8,7 +8,6 @@ import * as formActions from '../../actions/form' import BatchPreferences from './batch-preferences' import DateTimeModal from './date-time-modal' import ModeButtons, {MODE_OPTIONS, StyledModeButton} from './mode-buttons' -// import UserSettings from '../form/user-settings' import Icon from '../narrative/icon' import { BatchPreferencesContainer,