From 0b9b183e563ab5e424b8ddf08d514c7f550f8bac Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Wed, 12 Jan 2022 14:44:18 +0100 Subject: [PATCH 1/7] feat(itinerary-body): show itinerary walking leg imagery button --- example-config.yml | 4 +++ .../line-itin/connected-itinerary-body.js | 28 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/example-config.yml b/example-config.yml index 123383bcd..7115a99ae 100644 --- a/example-config.yml +++ b/example-config.yml @@ -409,3 +409,7 @@ dateTime: # # Whether to render routes within flex zones of a route's patterns. If set to true, # # routes will not be rendered within flex zones. # hideRouteShapesWithinFlexZones: true + +# API key to make Mapillary API calls. These are used to show street imagery. +# mapillary: +# key: diff --git a/lib/components/narrative/line-itin/connected-itinerary-body.js b/lib/components/narrative/line-itin/connected-itinerary-body.js index 79b8f167b..3b33267af 100644 --- a/lib/components/narrative/line-itin/connected-itinerary-body.js +++ b/lib/components/narrative/line-itin/connected-itinerary-body.js @@ -1,23 +1,29 @@ +/* eslint-disable react/prop-types */ +// TODO: Typescript (otp-rr config object) +import { connect } from 'react-redux' +import { + PlaceName as PlaceNameWrapper, + PlaceRowWrapper +} from '@opentripplanner/itinerary-body/lib/styled' import isEqual from 'lodash.isequal' -import TransitLegSummary from '@opentripplanner/itinerary-body/lib/defaults/transit-leg-summary' import ItineraryBody from '@opentripplanner/itinerary-body/lib/otp-react-redux/itinerary-body' import LineColumnContent from '@opentripplanner/itinerary-body/lib/otp-react-redux/line-column-content' import PlaceName from '@opentripplanner/itinerary-body/lib/otp-react-redux/place-name' -import { PlaceName as PlaceNameWrapper, PlaceRowWrapper } from '@opentripplanner/itinerary-body/lib/styled' -import RouteDescription from '@opentripplanner/itinerary-body/lib/otp-react-redux/route-description' import React, { Component } from 'react' -import { connect } from 'react-redux' +import RouteDescription from '@opentripplanner/itinerary-body/lib/otp-react-redux/route-description' import styled from 'styled-components' +import TransitLegSummary from '@opentripplanner/itinerary-body/lib/defaults/transit-leg-summary' +import { ComponentContext } from '../../../util/contexts' import { setLegDiagram } from '../../../actions/map' import { setViewedTrip } from '../../../actions/ui' import TripDetails from '../connected-trip-details' import TripTools from '../trip-tools' -import { ComponentContext } from '../../../util/contexts' import RealtimeTimeColumn from './realtime-time-column' import TransitLegSubheader from './connected-transit-leg-subheader' +// eslint-disable-next-line @typescript-eslint/no-empty-function const noop = () => {} const ItineraryBodyContainer = styled.div` @@ -37,11 +43,11 @@ class ConnectedItineraryBody extends Component { static contextType = ComponentContext /** avoid rerendering if the itinerary to display hasn't changed */ - shouldComponentUpdate (nextProps, nextState) { + shouldComponentUpdate(nextProps, nextState) { return !isEqual(this.props.itinerary, nextProps.itinerary) } - render () { + render() { const { accessibilityScoreGradationMap, config, @@ -63,6 +69,7 @@ class ConnectedItineraryBody extends Component { itinerary={itinerary} LegIcon={LegIcon} LineColumnContent={LineColumnContent} + mapillaryKey={config?.mapillary?.key} PlaceName={PlaceName} RouteDescription={RouteDescription} setActiveLeg={setActiveLeg} @@ -99,6 +106,7 @@ const mapDispatchToProps = { setViewedTrip } -export default connect(mapStateToProps, mapDispatchToProps)( - ConnectedItineraryBody -) +export default connect( + mapStateToProps, + mapDispatchToProps +)(ConnectedItineraryBody) From a3c0a0af02e89187a9a2965cda4309e74fd0291b Mon Sep 17 00:00:00 2001 From: miles-grant-ibigroup Date: Wed, 12 Jan 2022 16:32:09 +0100 Subject: [PATCH 2/7] improvement: show mapillary iframe in elevation popup --- lib/actions/map.js | 1 + lib/components/map/map.css | 21 +- lib/components/map/map.js | 67 +++- lib/components/map/mapillary-frame.tsx | 29 ++ .../narrative/default/access-leg.js | 61 ++-- .../line-itin/connected-itinerary-body.js | 5 +- lib/reducers/create-otp-reducer.js | 334 +++++++++++------- 7 files changed, 337 insertions(+), 181 deletions(-) create mode 100644 lib/components/map/mapillary-frame.tsx diff --git a/lib/actions/map.js b/lib/actions/map.js index 5db88e68f..310d66233 100644 --- a/lib/actions/map.js +++ b/lib/actions/map.js @@ -131,6 +131,7 @@ export function switchLocations() { } export const setLegDiagram = createAction('SET_LEG_DIAGRAM') +export const setMapillaryId = createAction('SET_MAPILLARY_ID') export const setElevationPoint = createAction('SET_ELEVATION_POINT') diff --git a/lib/components/map/map.css b/lib/components/map/map.css index 77652d126..04dca4aea 100644 --- a/lib/components/map/map.css +++ b/lib/components/map/map.css @@ -15,7 +15,7 @@ } .otp .link-button:focus { - outline:0; + outline: 0; } /* leg diagram */ @@ -29,8 +29,8 @@ z-index: 1000; background-color: white; background-clip: padding-box; - border: 2px solid rgba(127, 127, 127, .5); - border-Radius: 4px; + border: 2px solid rgba(127, 127, 127, 0.5); + border-radius: 4px; cursor: crosshair; } @@ -64,6 +64,21 @@ background: none; } +.otp .leg-diagram .mapillary-close-button { + background: rgba(255, 255, 255, 0.85); + border-radius: 0 0 1em; + display: block; + left: 0; + padding: 0.5em; + position: absolute; + top: 0; + z-index: 10000; +} +.otp .leg-diagram .mapillary-close-button:hover { + background: rgba(200, 200, 200, 0.85); + color: #333; +} + /*** Car Rental Map Icons ***/ .otp .car-rental-icon { diff --git a/lib/components/map/map.js b/lib/components/map/map.js index 12e01609e..4b8ca41e2 100644 --- a/lib/components/map/map.js +++ b/lib/components/map/map.js @@ -1,43 +1,56 @@ -import React, { Component } from 'react' +/* eslint-disable react/prop-types */ +// TODO: Typescript (config object) +import { Button, ButtonGroup } from 'react-bootstrap' import { connect } from 'react-redux' -import { ButtonGroup, Button } from 'react-bootstrap' +import React, { Component } from 'react' + +import { setMapillaryId } from '../../actions/map' import DefaultMap from './default-map' import LegDiagram from './leg-diagram' +import MapillaryFrame from './mapillary-frame' import StylizedMap from './stylized-map' class Map extends Component { - constructor () { + constructor() { super() this.state = { activeViewIndex: 0 } } - getComponentForView (view) { + getComponentForView(view) { // TODO: allow a 'CUSTOM' type switch (view.type) { - case 'DEFAULT': return - case 'STYLIZED': return + case 'DEFAULT': + return + case 'STYLIZED': + return } } - render () { - const { diagramLeg, mapConfig } = this.props + render() { + const { activeMapillaryImage, diagramLeg, mapConfig, setMapillaryId } = + this.props const showDiagram = diagramLeg + const showMapillary = activeMapillaryImage // Use the views defined in the config; if none defined, just show the default map const views = mapConfig.views || [{ type: 'DEFAULT' }] return ( -
+
{/* The map views -- only one is visible at a time */} {views.map((view, i) => { return ( -
{this.getComponentForView(view)}
@@ -46,15 +59,26 @@ class Map extends Component { {/* The toggle buttons -- only show if multiple views */} {views.length > 1 && ( -
+
{views.map((view, i) => { return (
) } @@ -76,9 +106,14 @@ class Map extends Component { const mapStateToProps = (state, ownProps) => { return { + activeMapillaryImage: state.otp.ui.mapillaryId, diagramLeg: state.otp.ui.diagramLeg, mapConfig: state.otp.config.map } } -export default connect(mapStateToProps)(Map) +const mapDispatchToProps = { + setMapillaryId +} + +export default connect(mapStateToProps, mapDispatchToProps)(Map) diff --git a/lib/components/map/mapillary-frame.tsx b/lib/components/map/mapillary-frame.tsx new file mode 100644 index 000000000..f4225abde --- /dev/null +++ b/lib/components/map/mapillary-frame.tsx @@ -0,0 +1,29 @@ +import { Button } from 'react-bootstrap' +import React from 'react' + +const MapillaryFrame = ({ + id, + onClose +}: { + id: string + onClose?: () => void +}): React.ReactElement => { + return ( +
+