Skip to content

Commit

Permalink
Merge branch 'dev' into fix-zoom-itin-click
Browse files Browse the repository at this point in the history
  • Loading branch information
josh-willis-arcadis authored Nov 5, 2024
2 parents f469584 + 17eee37 commit 29cf298
Show file tree
Hide file tree
Showing 30 changed files with 613 additions and 264 deletions.
2 changes: 1 addition & 1 deletion a11y/a11y.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ beforeAll(async () => {
})
// Web security is disabled to allow requests to the mock OTP server
browser = await puppeteer.launch({
args: ['--disable-web-security']
args: ['--disable-web-security', '--no-sandbox']
})
})

Expand Down
6 changes: 5 additions & 1 deletion example-config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,11 @@ modes:
iconName: wheelchair
type: CHECKBOX # Possible options: CHECKBOX, SUBMODE, SLIDER, DROPDOWN
transitModes:
- mode: BUS
# Mode can be a string or an array of strings.
- mode: ["TROLLEYBUS", "BUS"]
# When mode is an array an overrideMode must be provided.
# This specifies the displayed mode used for icon and URL param.
overrideMode: BUS
label: Bus
# A mode color can be added, used throughout the application,
# most notably in the enhanced stop viewer bubble
Expand Down
2 changes: 2 additions & 0 deletions i18n/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,8 @@ components:
oneHour: 1 hour
realtimeAlertFlagged: There is a realtime alert flagged on my journey
timeBefore: "{time} before"
TripPreviewLayout:
previewTrip: Preview Trip
TripStatus:
alerts: "{alerts, plural, one {# alert!} other {# alerts!}}"
deleteTrip: Delete Trip
Expand Down
2 changes: 2 additions & 0 deletions i18n/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -661,6 +661,8 @@ components:
oneHour: 1 heure
realtimeAlertFlagged: Une alerte en temps réel affecte mon trajet
timeBefore: "{time} avant"
TripPreviewLayout:
previewTrip: Aperçu du trajet
TripStatus:
alerts: "{alerts, plural, =0 {# alerte !} one {# alerte !} other {# alertes !}}"
deleteTrip: Supprimer le trajet
Expand Down
27 changes: 19 additions & 8 deletions lib/actions/apiV2.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import {
getRouteColorBasedOnSettings,
getRouteIdForPattern,
getRouteTextColorBasedOnSettings,
routeIsValid
} from '../util/viewer'
import { isLastStop } from '../util/stop-times'
Expand Down Expand Up @@ -1130,20 +1131,30 @@ export function routingQuery(searchId = null, updateSearchInReducer) {
...itin,
legs: itin.legs
?.map((leg) => {
const routeOperator = getRouteOperator(
{
agencyId: leg?.agency?.id,
id: leg?.route?.id
},
config.transitOperators
)
const routeProperties = {
color: leg?.route?.color,
mode: leg.mode
}

return {
...leg,
origColor: leg?.route?.color,
route: {
...leg.route,
color: getRouteColorBasedOnSettings(
getRouteOperator(
{
agencyId: leg?.agency?.id,
id: leg?.route?.id
},
config.transitOperators
),
{ color: leg?.route?.color, mode: leg.mode }
routeOperator,
routeProperties
).split('#')?.[1],
textColor: getRouteTextColorBasedOnSettings(
routeOperator,
routeProperties
).split('#')?.[1]
}
}
Expand Down
2 changes: 1 addition & 1 deletion lib/actions/form.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export function resetForm(full = false) {
const options = getTripOptionsFromQuery(defaultQuery)
// Default mode is currently WALK,TRANSIT. We need to update this value
// here to match the list of modes, otherwise the form will break.
options.mode = ['WALK', ...transitModes.map((m) => m.mode)].join(',')
options.mode = ['WALK', ...transitModes.flatMap((m) => m.mode)].join(',')
dispatch(settingQueryParam(options))
}
if (full) {
Expand Down
24 changes: 22 additions & 2 deletions lib/components/app/batch-routing-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group'
import { FormattedMessage, injectIntl, IntlShape } from 'react-intl'
import React, { Component, FormEvent } from 'react'

import * as apiActions from '../../actions/api'
import {
advancedPanelClassName,
mainPanelClassName,
transitionDuration,
TransitionStyles
} from '../form/styled'
import { alertUserTripPlan } from '../form/util'
import { getActiveSearch, getShowUserSettings } from '../../util/state'
import { getPersistenceMode } from '../../util/user'
import AdvancedSettingsPanel from '../form/advanced-settings-panel'
Expand All @@ -22,9 +24,11 @@ import ViewerContainer from '../viewers/viewer-container'

interface Props {
activeSearch: any
currentQuery: any
intl: IntlShape
mainPanelContent: number
mobile?: boolean
routingQuery: () => void
showUserSettings: boolean
}

Expand Down Expand Up @@ -75,7 +79,13 @@ class BatchRoutingPanel extends Component<Props> {
handleSubmit = (e: FormEvent) => e.preventDefault()

handlePlanTripClick = () => {
this.setState({ planTripClicked: true })
const { currentQuery, intl, routingQuery } = this.props
alertUserTripPlan(
intl,
currentQuery,
() => this.setState({ planTripClicked: true }),
routingQuery
)
}

render() {
Expand Down Expand Up @@ -128,6 +138,7 @@ class BatchRoutingPanel extends Component<Props> {
>
<AdvancedSettingsPanel
closeAdvancedSettings={this.closeAdvancedSettings}
handlePlanTrip={this.handlePlanTripClick}
innerRef={this._advancedSettingRef}
setCloseAdvancedSettingsWithDelay={
this.setCloseAdvancedSettingsWithDelay
Expand Down Expand Up @@ -223,12 +234,21 @@ const mapStateToProps = (state: any) => {
(state.user.loggedInUser?.hasConsentedToTerms ||
getPersistenceMode(state.otp.config.persistence).isLocalStorage)
const { mainPanelContent } = state.otp.ui
const currentQuery = state.otp.currentQuery

return {
activeSearch: getActiveSearch(state),
currentQuery,
mainPanelContent,
showUserSettings
}
}

export default connect(mapStateToProps)(injectIntl(BatchRoutingPanel))
const mapDispatchToProps = {
routingQuery: apiActions.routingQuery
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(injectIntl(BatchRoutingPanel))
129 changes: 20 additions & 109 deletions lib/components/app/print-layout.tsx
Original file line number Diff line number Diff line change
@@ -1,164 +1,75 @@
import { Button } from 'react-bootstrap'
import { connect } from 'react-redux'
import { FormattedMessage, injectIntl, IntlShape } from 'react-intl'
import { Itinerary } from '@opentripplanner/types'
import { Map } from '@styled-icons/fa-solid/Map'
import { Print } from '@styled-icons/fa-solid/Print'
import { Times } from '@styled-icons/fa-solid/Times'
// @ts-expect-error not typescripted yet
import PrintableItinerary from '@opentripplanner/printable-itinerary'
import React, { Component } from 'react'

import * as apiActions from '../../actions/api'
import * as formActions from '../../actions/form'
import {
addPrintViewClassToRootHtml,
clearClassFromRootHtml
} from '../../util/print'
import { ComponentContext } from '../../util/contexts'
import { AppReduxState } from '../../util/state-types'
import { getActiveItinerary, getActiveSearch } from '../../util/state'
import { IconWithText } from '../util/styledIcon'
import { summarizeQuery } from '../form/user-settings-i18n'
import { User } from '../user/types'
import DefaultMap from '../map/default-map'
import PageTitle from '../util/page-title'
import SpanWithSpace from '../util/span-with-space'
import TripDetails from '../narrative/connected-trip-details'

import TripPreviewLayoutBase from './trip-preview-layout-base'

type Props = {
// TODO: Typescript activeSearch type
activeSearch: any
// TODO: Typescript config type
config: any
currentQuery: any
intl: IntlShape
itinerary: Itinerary
location?: { search?: string }
parseUrlQueryString: (params?: any, source?: string) => any
// TODO: Typescript user type
user: any
}

type State = {
mapVisible?: boolean
user: User
}

class PrintLayout extends Component<Props, State> {
static contextType = ComponentContext

constructor(props: Props) {
super(props)
this.state = {
mapVisible: true
}
}

_toggleMap = () => {
this.setState({ mapVisible: !this.state.mapVisible })
}

_print = () => {
window.print()
}

class PrintLayout extends Component<Props> {
_close = () => {
window.location.replace(String(window.location).replace('print/', ''))
}

componentDidMount() {
const { itinerary, location, parseUrlQueryString } = this.props

// Add print-view class to html tag to ensure that iOS scroll fix only applies
// to non-print views.
addPrintViewClassToRootHtml()
// Parse the URL query parameters, if present
if (!itinerary && location && location.search) {
parseUrlQueryString()
}

// TODO: use currentQuery to pan/zoom to the correct part of the map
}

componentWillUnmount() {
clearClassFromRootHtml()
}

render() {
const { activeSearch, config, intl, itinerary, user } = this.props
const { LegIcon } = this.context
const { activeSearch, intl, itinerary, user } = this.props
const printVerb = intl.formatMessage({ id: 'common.forms.print' })

return (
<div className="otp print-layout">
<PageTitle
title={[
printVerb,
activeSearch &&
summarizeQuery(activeSearch.query, intl, user.savedLocations)
]}
/>
{/* The header bar, including the Toggle Map and Print buttons */}
<div className="header">
<div style={{ float: 'right' }}>
<SpanWithSpace margin={0.25}>
<Button
aria-expanded={this.state.mapVisible}
bsSize="small"
onClick={this._toggleMap}
>
<IconWithText Icon={Map}>
<FormattedMessage id="components.PrintLayout.toggleMap" />
</IconWithText>
</Button>
</SpanWithSpace>
<SpanWithSpace margin={0.25}>
<Button bsSize="small" onClick={this._print}>
<IconWithText Icon={Print}>{printVerb}</IconWithText>
</Button>
</SpanWithSpace>
<Button bsSize="small" onClick={this._close} role="link">
<IconWithText Icon={Times}>
<FormattedMessage id="common.forms.close" />
</IconWithText>
</Button>
</div>
<FormattedMessage id="components.PrintLayout.itinerary" />
</div>

{/* The map, if visible */}
{this.state.mapVisible && (
<TripPreviewLayoutBase
header={<FormattedMessage id="components.PrintLayout.itinerary" />}
itinerary={itinerary}
mapElement={
<div className="map-container">
{/* FIXME: Improve reframing/setting map bounds when itinerary is received. */}
<DefaultMap />
</div>
)}

{/* The main itinerary body */}
{itinerary && (
<>
<PrintableItinerary
config={config}
itinerary={itinerary}
LegIcon={LegIcon}
/>
<TripDetails className="percy-hide" itinerary={itinerary} />
</>
)}
</div>
}
onClose={this._close}
subTitle={
activeSearch &&
summarizeQuery(activeSearch.query, intl, user.savedLocations)
}
title={printVerb}
/>
)
}
}

// connect to the redux store

// TODO: Typescript state
const mapStateToProps = (state: any) => {
const mapStateToProps = (state: AppReduxState) => {
const activeSearch = getActiveSearch(state)
const { localUser, loggedInUser } = state.user
const user = loggedInUser || localUser
return {
activeSearch,
config: state.otp.config,
currentQuery: state.otp.currentQuery,
itinerary: getActiveItinerary(state) as Itinerary,
user
}
Expand Down
3 changes: 2 additions & 1 deletion lib/components/app/responsive-webapp.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import BeforeSignInScreen from '../user/before-signin-screen'
import Map from '../map/map'
import MobileMain from '../mobile/main'
import printRoutes from '../../util/webapp-print-routes'
import tripPreviewRoutes from '../../util/webapp-trip-preview-routes'
import webAppRoutes from '../../util/webapp-routes'
import withLoggedInUserSupport from '../user/with-logged-in-user-support'
import withMap from '../map/with-map'
Expand All @@ -43,7 +44,7 @@ import SessionTimeout from './session-timeout'

const { isMobile } = coreUtils.ui

const routes = [...webAppRoutes, ...printRoutes]
const routes = [...webAppRoutes, ...printRoutes, ...tripPreviewRoutes]

class ResponsiveWebapp extends Component {
static propTypes = {
Expand Down
Loading

0 comments on commit 29cf298

Please sign in to comment.