Skip to content

Commit 70562cc

Browse files
authored
Merge pull request #5529 from HSLdevcom/AB#295
AB#295 fix route page map bugs
2 parents 265589c + cd7ec82 commit 70562cc

File tree

3 files changed

+136
-173
lines changed

3 files changed

+136
-173
lines changed

app/component/map/RoutePageMap.js

Lines changed: 131 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,186 +1,166 @@
11
/* eslint-disable no-underscore-dangle */
22
import PropTypes from 'prop-types';
3-
import React from 'react';
3+
import React, { useEffect, useRef, useState } from 'react';
44
import { createFragmentContainer, graphql } from 'react-relay';
5-
import { matchShape } from 'found';
65
import 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';
137
import MapWithTracking from './MapWithTracking';
148
import RouteLine from './route/RouteLine';
159
import VehicleMarkerContainer from './VehicleMarkerContainer';
1610
import { getStartTime } from '../../util/timeUtils';
1711
import withBreakpoint from '../../util/withBreakpoint';
1812
import BackButton from '../BackButton';
1913
import { isActiveDate } from '../../util/patternUtils';
20-
import { mapLayerShape } from '../../store/MapLayerStore';
2114
import { boundWithMinimumArea } from '../../util/geo-utils';
2215
import { getMapLayerOptions } from '../../util/mapLayerUtils';
2316
import 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+
184164
const 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];

app/component/map/VehicleMarkerContainer.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ function VehicleMarkerContainer(props, { config }) {
7979
return shouldShowVehicle(
8080
message,
8181
props.direction || desc?.direction,
82-
props.tripStart || desc?.tripStart,
82+
desc?.tripStart,
8383
props.pattern,
8484
ignoreHeadsign ? undefined : props.headsign,
8585
desc?.tripId,
@@ -134,7 +134,6 @@ function VehicleMarkerContainer(props, { config }) {
134134
}
135135

136136
VehicleMarkerContainer.propTypes = {
137-
tripStart: PropTypes.string,
138137
headsign: PropTypes.string,
139138
direction: PropTypes.number,
140139
vehicles: PropTypes.objectOf(
@@ -152,7 +151,6 @@ VehicleMarkerContainer.propTypes = {
152151
};
153152

154153
VehicleMarkerContainer.defaultProps = {
155-
tripStart: undefined,
156154
direction: undefined,
157155
useLargeIcon: true,
158156
};

app/routeRoutes.js

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,9 @@ export default function routeRoutes(config) {
133133
}
134134
}
135135
`}
136-
render={({ Component, props, error, match }) => {
136+
render={({ Component, props, error }) => {
137137
if (Component && (props || error)) {
138-
return <Component {...props} match={match} error={error} />;
138+
return <Component {...props} error={error} />;
139139
}
140140
return null;
141141
}}
@@ -154,16 +154,9 @@ export default function routeRoutes(config) {
154154
}
155155
}
156156
`}
157-
render={({ Component, props, error, match }) => {
157+
render={({ Component, props, error }) => {
158158
if (Component && (props || error)) {
159-
return (
160-
<Component
161-
{...props}
162-
match={match}
163-
error={error}
164-
trip={null}
165-
/>
166-
);
159+
return <Component {...props} error={error} trip={null} />;
167160
}
168161
return null;
169162
}}

0 commit comments

Comments
 (0)