Skip to content
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

Add Plan Trip Button to Advanced Mode Settings Page #1244

Merged
16 changes: 8 additions & 8 deletions lib/components/app/batch-routing-panel.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
import { connect } from 'react-redux'
import { CSSTransition, TransitionGroup } from 'react-transition-group'
import { FormattedMessage, injectIntl, IntlShape } from 'react-intl'

import { getActiveSearch, getShowUserSettings } from '../../util/state'
import { getPersistenceMode } from '../../util/user'
import AdvancedSettingsPanel from '../form/advanced-settings-panel'
import BatchSettings from '../form/batch-settings'
import InvisibleA11yLabel from '../util/invisible-a11y-label'
import LocationField from '../form/connected-location-field'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import React, { Component, FormEvent } from 'react'

import {
Expand All @@ -17,6 +9,13 @@ import {
transitionDuration,
TransitionStyles
} from '../form/styled'
import { getActiveSearch, getShowUserSettings } from '../../util/state'
import { getPersistenceMode } from '../../util/user'
import AdvancedSettingsPanel from '../form/advanced-settings-panel'
import BatchSettings from '../form/batch-settings'
import InvisibleA11yLabel from '../util/invisible-a11y-label'
import LocationField from '../form/connected-location-field'
import NarrativeItineraries from '../narrative/narrative-itineraries'
import SwitchButton from '../form/switch-button'
import UserSettings from '../form/user-settings'
import ViewerContainer from '../viewers/viewer-container'
Expand Down Expand Up @@ -113,6 +112,7 @@ class BatchRoutingPanel extends Component<Props> {
<AdvancedSettingsPanel
closeAdvancedSettings={this.handleCloseAdvanceSettings}
innerRef={this._advancedSettingRef}
onPlanTripClick={this.handlePlanTripClick}
/>
</CSSTransition>
)}
Expand Down
77 changes: 61 additions & 16 deletions lib/components/form/advanced-settings-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,42 @@ import {
ModeSettingRenderer,
populateSettingWithValue
} from '@opentripplanner/trip-form'

import { blue, getBaseColor } from '../util/colors'
import { Close } from '@styled-icons/fa-solid'

import { connect } from 'react-redux'
import { decodeQueryParams, DelimitedArrayParam } from 'serialize-query-params'
import { FormattedMessage, useIntl } from 'react-intl'

import { generateModeSettingValues } from '../../util/api'

import { invisibleCss } from '@opentripplanner/trip-form/lib/MetroModeSelector'
import {
ModeButtonDefinition,
ModeSetting,
ModeSettingValues
} from '@opentripplanner/types'
import { Search } from '@styled-icons/fa-solid/Search'
import React, { RefObject, useContext } from 'react'
import styled from 'styled-components'

import * as apiActions from '../../actions/api'
import * as formActions from '../../actions/form'
import { AppReduxState } from '../../util/state-types'
import { blue, getBaseColor } from '../util/colors'
import { ComponentContext } from '../../util/contexts'
import { generateModeSettingValues } from '../../util/api'
import PageTitle from '../util/page-title'

import React, { RefObject, useContext } from 'react'
import styled from 'styled-components'
import toast from 'react-hot-toast'

import {
addCustomSettingLabels,
addModeButtonIcon,
alertUserTripPlan,
onSettingsUpdate,
pipe,
populateSettingWithIcon,
setModeButton
} from './util'

import { invisibleCss } from '@opentripplanner/trip-form/lib/MetroModeSelector'

import { setModeButtonEnabled } from './batch-settings'
import { styledCheckboxCss } from './styled'

const PanelOverlay = styled.div`
background-color: #fff;
height: 100%;
left: 0;
padding: 1.5em;
Expand Down Expand Up @@ -79,26 +74,57 @@ const HeaderContainer = styled.div`
const Subheader = styled.h2`
${invisibleCss}
`
const baseColor = getBaseColor()
const accentColor = baseColor || blue[900]

const PlanTripButton = styled.button`
align-items: center;
display: flex;
justify-content: center;
gap: 0.5em;
background-color: var(--main-base-color, ${blue[900]});
border: 0;
width: 47%;
height: 51px;
color: white;
font-weight: 700;
`

const ReturnToTripPlanButton = styled(PlanTripButton)`
border: 2px solid var(--main-base-color, ${blue[900]});
background-color: white;
color: var(--main-base-color, ${blue[900]});
`
const ButtonContainer = styled.div`
display: flex;
justify-content: space-between;
margin-top: 2em;
`

const AdvancedSettingsPanel = ({
closeAdvancedSettings,
currentQuery,
enabledModeButtons,
innerRef,
modeButtonOptions,
modeSettingDefinitions,
modeSettingValues,
onPlanTripClick,
routingQuery,
setQueryParam
}: {
closeAdvancedSettings: () => void
currentQuery: any
enabledModeButtons: string[]
innerRef: RefObject<HTMLDivElement>
modeButtonOptions: ModeButtonDefinition[]
modeSettingDefinitions: ModeSetting[]
modeSettingValues: ModeSettingValues
onPlanTripClick: () => void
routingQuery: () => void
setQueryParam: (evt: any) => void
}): JSX.Element => {
const baseColor = getBaseColor()
const accentColor = baseColor || blue[900]

const intl = useIntl()
const closeButtonText = intl.formatMessage({
id: 'components.BatchSearchScreen.closeAdvancedPreferences'
Expand All @@ -110,6 +136,16 @@ const AdvancedSettingsPanel = ({
// @ts-expect-error Context not typed
const { ModeIcon } = useContext(ComponentContext)

const planTrip = () => {
alertUserTripPlan(intl, currentQuery, onPlanTripClick, routingQuery)
closeAdvancedSettings()
}

const closeAndAnnounce = () => {
closeAdvancedSettings()
toast.success(intl.formatMessage({ id: 'actions.user.preferencesSaved' }))
}

const processSettings = (settings: ModeSetting[]) =>
settings.map(
pipe(
Expand Down Expand Up @@ -148,7 +184,7 @@ const AdvancedSettingsPanel = ({
<h1 className="header-text">{headerText}</h1>
<CloseButton
aria-label={closeButtonText}
onClick={closeAdvancedSettings}
onClick={closeAndAnnounce}
title={closeButtonText}
>
<Close size={22} />
Expand Down Expand Up @@ -181,6 +217,15 @@ const AdvancedSettingsPanel = ({
onSettingsUpdate(setQueryParam)
)}
/>
<ButtonContainer>
<ReturnToTripPlanButton onClick={closeAndAnnounce}>
Back to Trip Plan
</ReturnToTripPlanButton>
<PlanTripButton onClick={planTrip}>
<Search size={18} />
<FormattedMessage id="components.BatchSettings.planTripTooltip" />
</PlanTripButton>
</ButtonContainer>
</PanelOverlay>
)
}
Expand Down
51 changes: 4 additions & 47 deletions lib/components/form/batch-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import {
populateSettingWithValue
} from '@opentripplanner/trip-form'
import { connect } from 'react-redux'
import {
decodeQueryParams,
DelimitedArrayParam,
encodeQueryParams
} from 'use-query-params'
import { decodeQueryParams } from 'use-query-params'
import {
ModeButtonDefinition,
ModeSetting,
Expand All @@ -25,12 +21,12 @@ import { ComponentContext } from '../../util/contexts'
import { generateModeSettingValues } from '../../util/api'
import { getActiveSearch, hasValidLocation } from '../../util/state'
import { getBaseColor, getDarkenedBaseColor } from '../util/colors'
import { RoutingQueryCallResult } from '../../actions/api-constants'
import { StyledIconWrapper } from '../util/styledIcon'

import {
addCustomSettingLabels,
addModeButtonIcon,
alertUserTripPlan,
modesQueryParamConfig,
onSettingsUpdate,
pipe,
Expand Down Expand Up @@ -117,47 +113,8 @@ function BatchSettings({
)

const _planTrip = useCallback(() => {
// Check for any validation issues in query.
const issues = []
if (!hasValidLocation(currentQuery, 'from')) {
issues.push(intl.formatMessage({ id: 'components.BatchSettings.origin' }))
}
if (!hasValidLocation(currentQuery, 'to')) {
issues.push(
intl.formatMessage({ id: 'components.BatchSettings.destination' })
)
}
onPlanTripClick && onPlanTripClick()
if (issues.length > 0) {
// TODO: replace with less obtrusive validation.
window.alert(
intl.formatMessage(
{ id: 'components.BatchSettings.validationMessage' },
{ issues: intl.formatList(issues, { type: 'conjunction' }) }
)
)
return
}

// Plan trip.
updateQueryTimeIfLeavingNow()
const routingQueryResult = routingQuery()

// If mode combination is not valid (i.e. produced no query), alert the user.
if (routingQueryResult === RoutingQueryCallResult.INVALID_MODE_SELECTION) {
window.alert(
intl.formatMessage({
id: 'components.BatchSettings.invalidModeSelection'
})
)
}
}, [
currentQuery,
intl,
onPlanTripClick,
routingQuery,
updateQueryTimeIfLeavingNow
])
alertUserTripPlan(intl, currentQuery, onPlanTripClick, routingQuery)
}, [currentQuery, intl, onPlanTripClick, routingQuery])

/**
* Check whether the mode selector is showing a popup.
Expand Down
5 changes: 2 additions & 3 deletions lib/components/form/styled.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { blue, getBaseColor, grey } from '../util/colors'
import { blue, grey } from '../util/colors'
import {
DateTimeSelector,
SettingsSelectorPanel,
Expand Down Expand Up @@ -235,7 +235,6 @@ export const StyledLocationField = styled(LocationField)`
export const advancedPanelClassName = 'advanced-panel'
export const mainPanelClassName = 'main-panel'
export const transitionDuration = prefersReducedMotion ? 0 : 175
const baseColor = getBaseColor()

const wipeOffset = 7

Expand Down Expand Up @@ -339,7 +338,7 @@ export const styledCheckboxCss = css`

&:checked + label {
&::after {
background-color: ${baseColor || blue[700]};
background-color: var(--main-base-color, ${blue[700]});
${toggleTransition};
}

Expand Down
45 changes: 45 additions & 0 deletions lib/components/form/util.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import { ModeButtonDefinition, ModeSetting } from '@opentripplanner/types'
import React from 'react'

import { getFormattedMode } from '../../util/i18n'
import { hasValidLocation } from '../../util/state'
import { RoutingQueryCallResult } from '../../actions/api-constants'
import { updateQueryTimeIfLeavingNow } from '../../actions/form'

// This method is used to daisy-chain a series of functions together on a given value
export function pipe<T>(...fns: Array<(arg: T) => T>) {
Expand Down Expand Up @@ -69,3 +72,45 @@ export const setModeButton =
encodeQueryParams(modesQueryParamConfig, { modeButtons: newButtons })
)
}

export const alertUserTripPlan = (
intl: IntlShape,
currentQuery: any,
onPlanTripClick: () => void,
routingQuery: () => any
): void => {
// Check for any validation issues in query.
const issues: string[] = []
if (!hasValidLocation(currentQuery, 'from')) {
issues.push(intl.formatMessage({ id: 'components.BatchSettings.origin' }))
}
if (!hasValidLocation(currentQuery, 'to')) {
issues.push(
intl.formatMessage({ id: 'components.BatchSettings.destination' })
)
}
onPlanTripClick()
if (issues.length > 0) {
// TODO: replace with less obtrusive validation.
window.alert(
intl.formatMessage(
{ id: 'components.BatchSettings.validationMessage' },
{ issues: intl.formatList(issues, { type: 'conjunction' }) }
)
)
return
}

// Plan trip.
updateQueryTimeIfLeavingNow()
const routingQueryResult = routingQuery()

// If mode combination is not valid (i.e. produced no query), alert the user.
if (routingQueryResult === RoutingQueryCallResult.INVALID_MODE_SELECTION) {
window.alert(
intl.formatMessage({
id: 'components.BatchSettings.invalidModeSelection'
})
)
}
}
5 changes: 3 additions & 2 deletions lib/components/mobile/batch-search-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { connect } from 'react-redux'
import { CSSTransition, TransitionGroup } from 'react-transition-group'
import { injectIntl, IntlShape } from 'react-intl'
import React, { Component } from 'react'
import toast from 'react-hot-toast'

import * as uiActions from '../../actions/ui'
import {
Expand All @@ -9,8 +11,6 @@ import {
transitionDuration,
TransitionStyles
} from '../form/styled'
import { CSSTransition, TransitionGroup } from 'react-transition-group'

import { MobileScreens } from '../../actions/ui-constants'
import AdvancedSettingsPanel from '../form/advanced-settings-panel'
import BatchSettings from '../form/batch-settings'
Expand Down Expand Up @@ -117,6 +117,7 @@ class BatchSearchScreen extends Component<Props> {
<AdvancedSettingsPanel
closeAdvancedSettings={this.handleCloseAdvanceSettings}
innerRef={this._advancedSettingRef}
onPlanTripClick={this.handlePlanTripClick}
/>
</CSSTransition>
)}
Expand Down
Loading