11/* eslint-disable no-underscore-dangle */
22import PropTypes from 'prop-types' ;
3- import React from 'react' ;
3+ import React , { useEffect , useRef , useState } from 'react' ;
44import { createFragmentContainer , graphql } from 'react-relay' ;
5- import { matchShape } from 'found' ;
65import connectToStores from 'fluxible-addons-react/connectToStores' ;
7- import {
8- configShape ,
9- mapLayerOptionsShape ,
10- patternShape ,
11- errorShape ,
12- } from '../../util/shapes' ;
6+ import { configShape , patternShape , errorShape } from '../../util/shapes' ;
137import MapWithTracking from './MapWithTracking' ;
148import RouteLine from './route/RouteLine' ;
159import VehicleMarkerContainer from './VehicleMarkerContainer' ;
1610import { getStartTime } from '../../util/timeUtils' ;
1711import withBreakpoint from '../../util/withBreakpoint' ;
1812import BackButton from '../BackButton' ;
1913import { isActiveDate } from '../../util/patternUtils' ;
20- import { mapLayerShape } from '../../store/MapLayerStore' ;
2114import { boundWithMinimumArea } from '../../util/geo-utils' ;
2215import { getMapLayerOptions } from '../../util/mapLayerUtils' ;
2316import CookieSettingsButton from '../CookieSettingsButton' ;
2417
25- class RoutePageMap extends React . Component {
26- constructor ( props ) {
27- super ( props ) ;
28- this . state = {
29- trackVehicle : ! ! this . props . match . params . tripId , // map follows vehicle
30- } ;
31- }
32-
33- static propTypes = {
34- match : matchShape . isRequired ,
35- pattern : patternShape . isRequired ,
36- lat : PropTypes . number ,
37- lon : PropTypes . number ,
38- breakpoint : PropTypes . string . isRequired ,
39- mapLayers : mapLayerShape . isRequired ,
40- mapLayerOptions : mapLayerOptionsShape . isRequired ,
41- trip : PropTypes . shape ( { gtfsId : PropTypes . string } ) ,
42- error : errorShape ,
43- } ;
18+ function RoutePageMap (
19+ { pattern, lat, lon, breakpoint, trip, error, ...rest } ,
20+ { config } ,
21+ ) {
22+ const tripId = trip ?. gtfsId ;
23+ const [ trackVehicle , setTrackVehicle ] = useState ( ! ! tripId ) ;
24+ const tripIdRef = useRef ( ) ;
25+ const mwtRef = useRef ( ) ;
26+ const latRef = useRef ( ) ;
27+ const lonRef = useRef ( ) ;
28+ const bounds = useRef ( ) ;
29+ const code = useRef ( ) ;
4430
45- static defaultProps = {
46- trip : null ,
47- lat : undefined ,
48- lon : undefined ,
49- error : undefined ,
50- } ;
31+ useEffect ( ( ) => {
32+ // Throw error in client side if relay fails to fetch data
33+ if ( error && ! pattern ) {
34+ throw error . message ;
35+ }
36+ } , [ ] ) ;
5137
52- static contextTypes = {
53- config : configShape . isRequired ,
54- } ;
38+ if ( ! pattern ) {
39+ return null ;
40+ }
5541
56- // eslint-disable-next-line camelcase
57- UNSAFE_componentWillReceiveProps ( nextProps ) {
58- if ( nextProps . match . params . tripId !== this . tripId ) {
59- this . setState ( {
60- trackVehicle : ! ! nextProps . match . params . tripId ,
61- } ) ;
42+ useEffect ( ( ) => {
43+ if ( tripId !== tripIdRef . current ) {
44+ setTrackVehicle ( ! ! tripId ) ;
45+ mwtRef . current ?. disableMapTracking ( ) ;
6246 }
63- if (
64- nextProps . match . params . tripId !== this . tripId ||
65- nextProps . pattern . code !== this . code
66- ) {
67- // clear tracking so that map can focus on desired things
68- this . mwtRef ?. disableMapTracking ( ) ;
47+ } , [ tripId ] ) ;
48+
49+ useEffect ( ( ) => {
50+ if ( pattern . code !== code . current ) {
51+ mwtRef . current ?. disableMapTracking ( ) ;
6952 }
70- }
53+ } , [ pattern . code ] ) ;
7154
72- setMWTRef = ref => {
73- this . mwtRef = ref ;
55+ const setMWTRef = ref => {
56+ mwtRef . current = ref ;
7457 } ;
7558
76- stopTracking = ( ) => {
59+ const stopTracking = ( ) => {
7760 // filter events which occur when map moves by changed props
78- if ( this . tripId === this . props . match . params . tripId ) {
61+ if ( tripIdRef . current === tripId ) {
7962 // user wants to navigate, allow it
80- this . setState ( { trackVehicle : false } ) ;
63+ setTrackVehicle ( false ) ;
8164 }
8265 } ;
8366
84- componentDidMount ( ) {
85- // Throw error in client side if relay fails to fetch data
86- if ( this . props . error && ! this . props . pattern ) {
87- throw this . props . error . message ;
88- }
89- }
90-
91- render ( ) {
92- const { pattern, lat, lon, match, breakpoint, mapLayers, mapLayerOptions } =
93- this . props ;
94- if ( ! pattern ) {
95- return false ;
96- }
97- const { tripId } = match . params ;
98- const mwtProps = { } ;
99- if ( tripId && lat && lon ) {
100- // already getting vehicle pos
101- if ( this . state . trackVehicle ) {
102- mwtProps . lat = lat ;
103- mwtProps . lon = lon ;
104- this . lat = lat ;
105- this . lon = lon ;
106- if ( this . tripId !== tripId ) {
107- setTimeout ( ( ) => {
108- this . tripId = tripId ;
109- } , 500 ) ;
110- }
111- } else {
112- mwtProps . lat = this . lat ;
113- mwtProps . lon = this . lon ;
67+ const mwtProps = { } ;
68+ if ( tripId && lat && lon ) {
69+ // already getting vehicle pos
70+ if ( trackVehicle ) {
71+ mwtProps . lat = lat ;
72+ mwtProps . lon = lon ;
73+ latRef . current = lat ;
74+ lonRef . current = lon ;
75+ if ( tripIdRef . current !== tripId ) {
76+ setTimeout ( ( ) => {
77+ tripIdRef . current = tripId ;
78+ } , 500 ) ;
11479 }
115- mwtProps . zoom = 16 ;
11680 } else {
117- if ( this . code !== pattern . code || ! this . bounds ) {
118- let filteredPoints ;
119- if ( pattern . geometry ) {
120- filteredPoints = pattern . geometry . filter (
121- point => point . lat !== null && point . lon !== null ,
122- ) ;
123- }
124- this . bounds = boundWithMinimumArea (
125- ( filteredPoints || pattern . stops ) . map ( p => [ p . lat , p . lon ] ) ,
81+ mwtProps . lat = latRef . current ;
82+ mwtProps . lon = lonRef . current ;
83+ }
84+ mwtProps . zoom = 16 ;
85+ } else {
86+ if ( code . current !== pattern . code || ! bounds . current ) {
87+ let filteredPoints ;
88+ if ( pattern . geometry ) {
89+ filteredPoints = pattern . geometry . filter (
90+ point => point . lat !== null && point . lon !== null ,
12691 ) ;
127- this . code = pattern . code ;
12892 }
129- if ( this . tripId ) {
130- // changed back to route view, force update
131- this . mwtRef ?. forceRefresh ( ) ;
132- this . tripId = undefined ;
133- }
134- mwtProps . bounds = this . bounds ;
135- }
136- const tripSelected =
137- this . props . trip && this . props . trip . gtfsId && isActiveDate ( pattern ) ;
138- let tripStart ;
139- // BUG ?? tripStar prop is never set
140- const leafletObjs = [
141- < RouteLine
142- key = "line"
143- pattern = { pattern }
144- vehiclePosition = { tripSelected ? { lat, lon } : null }
145- /> ,
146- ] ;
147- if ( isActiveDate ( pattern ) ) {
148- leafletObjs . push (
149- < VehicleMarkerContainer
150- key = "vehicles"
151- direction = { pattern . directionId }
152- pattern = { pattern . code }
153- headsign = { pattern . headsign }
154- topics = { [ pattern . route ] }
155- tripStart = { tripStart }
156- /> ,
93+ bounds . current = boundWithMinimumArea (
94+ ( filteredPoints || pattern . stops ) . map ( p => [ p . lat , p . lon ] ) ,
15795 ) ;
96+ code . current = pattern . code ;
15897 }
159-
160- /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
161- return (
162- < MapWithTracking
163- { ...mwtProps }
164- className = "full"
165- leafletObjs = { leafletObjs }
166- mapLayers = { mapLayers }
167- mapLayerOptions = { mapLayerOptions }
168- onStartNavigation = { this . stopTracking }
169- onMapTracking = { this . stopTracking }
170- setMWTRef = { this . setMWTRef }
171- >
172- { breakpoint !== 'large' && (
173- < BackButton
174- icon = "icon_arrow-collapse--left"
175- iconClassName = "arrow-icon"
176- />
177- ) }
178- { this . context . config . useCookiesPrompt && < CookieSettingsButton /> }
179- </ MapWithTracking >
98+ if ( tripIdRef . current ) {
99+ // changed back to route view, force update
100+ mwtRef . current ?. forceRefresh ( ) ;
101+ tripIdRef . current = undefined ;
102+ }
103+ mwtProps . bounds = bounds . current ;
104+ }
105+ const tripSelected = lat && lon && trip ?. gtfsId && isActiveDate ( pattern ) ;
106+ const leafletObjs = [
107+ < RouteLine
108+ key = "line"
109+ pattern = { pattern }
110+ vehiclePosition = { tripSelected ? { lat, lon } : null }
111+ /> ,
112+ ] ;
113+ if ( isActiveDate ( pattern ) ) {
114+ leafletObjs . push (
115+ < VehicleMarkerContainer
116+ key = "vehicles"
117+ direction = { pattern . directionId }
118+ pattern = { pattern . code }
119+ headsign = { pattern . headsign }
120+ topics = { [ pattern . route ] }
121+ /> ,
180122 ) ;
181123 }
124+ /* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */
125+ return (
126+ < MapWithTracking
127+ { ...mwtProps }
128+ className = "full"
129+ leafletObjs = { leafletObjs }
130+ onStartNavigation = { stopTracking }
131+ onMapTracking = { stopTracking }
132+ setMWTRef = { setMWTRef }
133+ { ...rest }
134+ >
135+ { breakpoint !== 'large' && (
136+ < BackButton
137+ icon = "icon_arrow-collapse--left"
138+ iconClassName = "arrow-icon"
139+ />
140+ ) }
141+ { config . useCookiesPrompt && < CookieSettingsButton /> }
142+ </ MapWithTracking >
143+ ) ;
182144}
183145
146+ RoutePageMap . propTypes = {
147+ pattern : patternShape . isRequired ,
148+ lat : PropTypes . number ,
149+ lon : PropTypes . number ,
150+ breakpoint : PropTypes . string . isRequired ,
151+ trip : PropTypes . shape ( { gtfsId : PropTypes . string } ) ,
152+ error : errorShape ,
153+ } ;
154+
155+ RoutePageMap . defaultProps = {
156+ trip : null ,
157+ lat : undefined ,
158+ lon : undefined ,
159+ error : undefined ,
160+ } ;
161+
162+ RoutePageMap . contextTypes = { config : configShape . isRequired } ;
163+
184164const RoutePageMapWithVehicles = connectToStores (
185165 withBreakpoint ( RoutePageMap ) ,
186166 [ 'RealTimeInformationStore' , 'MapLayerStore' ] ,
@@ -200,22 +180,14 @@ const RoutePageMapWithVehicles = connectToStores(
200180 const matchingVehicles = Object . keys ( vehicles )
201181 . map ( key => vehicles [ key ] )
202182 . filter (
203- vehicle =>
204- vehicle . tripStartTime === undefined ||
205- vehicle . tripStartTime === tripStart ,
206- )
207- . filter (
208- vehicle =>
209- vehicle . tripId === undefined || vehicle . tripId === trip . gtfsId ,
210- )
211- . filter (
212- vehicle =>
213- vehicle . direction === undefined ||
214- vehicle . direction === Number ( trip . directionId ) ,
183+ v =>
184+ ( v . tripStartTime === undefined || v . tripStartTime === tripStart ) &&
185+ ( v . tripId === undefined || v . tripId === trip . gtfsId ) &&
186+ ( v . direction === undefined ||
187+ v . direction === Number ( trip . directionId ) ) ,
215188 ) ;
216189
217- if ( matchingVehicles . length !== 1 ) {
218- // no matching vehicles or cant distinguish between vehicles
190+ if ( ! matchingVehicles . length ) {
219191 return { mapLayers, mapLayerOptions } ;
220192 }
221193 const selectedVehicle = matchingVehicles [ 0 ] ;
0 commit comments