Skip to content

Commit 47e2af0

Browse files
committed
fix: show loader on map until route draw mode is ready
Prevent route creation clicks before draw mode is fully initialised.
1 parent 6183919 commit 47e2af0

3 files changed

Lines changed: 63 additions & 5 deletions

File tree

cypress/e2e/map/createRoute.cy.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,12 @@ describe('Route creation', rootOpts, () => {
149149
});
150150

151151
MapPage.editRouteModal.save();
152+
MapPage.map.getLoader().should('exist');
152153

153154
// Create a geometry for route that includes dataset stops E2E001,
154155
// (exclude E2E002) E2E003, E2E004 and E2E005
156+
// Wait until loading has finished before starting to click on the map
157+
MapPage.map.getLoader().should('not.exist');
155158
MapPage.map.clickAtCoordinates(
156159
stopCoordinatesByLabel.E2E001[0],
157160
stopCoordinatesByLabel.E2E001[1],
@@ -287,8 +290,11 @@ describe('Route creation', rootOpts, () => {
287290
});
288291

289292
MapPage.editRouteModal.save();
293+
MapPage.map.getLoader().should('exist');
290294

291295
// Create a geometry for route that includes dataset stops E2E001 - E2E004
296+
// Wait until loading has finished before starting to click on the map
297+
MapPage.map.getLoader().should('not.exist');
292298
MapPage.map.clickAtCoordinates(
293299
stopCoordinatesByLabel.E2E001[0],
294300
stopCoordinatesByLabel.E2E001[1],
@@ -389,8 +395,11 @@ describe('Route creation', rootOpts, () => {
389395
});
390396

391397
MapPage.editRouteModal.save();
398+
MapPage.map.getLoader().should('exist');
392399

393400
// Create a geometry for route that includes dataset stops E2E001 and E2E002
401+
// Wait until loading has finished before starting to click on the map
402+
MapPage.map.getLoader().should('not.exist');
394403
MapPage.map.clickAtCoordinates(
395404
stopCoordinatesByLabel.E2E001[0],
396405
stopCoordinatesByLabel.E2E001[1],
@@ -461,9 +470,12 @@ describe('Route creation', rootOpts, () => {
461470
});
462471

463472
MapPage.editRouteModal.save();
473+
MapPage.map.getLoader().should('exist');
464474

465475
// Create a geometry for route that includes dataset stops E2E001
466476
// and E2E002
477+
// Wait until loading has finished before starting to click on the map
478+
MapPage.map.getLoader().should('not.exist');
467479
MapPage.map.clickAtCoordinates(
468480
stopCoordinatesByLabel.E2E001[0],
469481
stopCoordinatesByLabel.E2E001[1],

ui/src/components/map/routes/DrawRouteLayer.tsx

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ import { useGetRouteDetailsByIdQuery } from '../../../generated/graphql';
55
import { mapRouteToInfraLinksAlongRoute } from '../../../graphql';
66
import { useAppDispatch, useAppSelector } from '../../../hooks';
77
import {
8+
LoadingState,
89
Mode,
10+
Operation,
911
selectEditedRouteData,
1012
selectMapRouteEditor,
1113
stopRouteEditingAction,
1214
} from '../../../redux';
1315
import { removeRoute } from '../../../utils/map';
16+
import { useLoader } from '../../common/hooks/useLoader';
1417
import { DrawControl } from '../DrawControl';
1518
import { ACTIVE_LINE_STROKE_ID } from './editorStyles';
1619
import {
@@ -42,16 +45,19 @@ const setCursor = (map: MapRef | undefined, drawingMode: Mode | undefined) => {
4245

4346
export const DrawRouteLayer: FC = () => {
4447
const drawRef = useRef<MapboxDraw | null>(null);
45-
const { current: mapboxDraw } = drawRef;
4648
const { current: map } = useMap();
4749
const dispatch = useAppDispatch();
50+
const { setLoadingState: setRouteDrawLoadingState } = useLoader(
51+
Operation.PrepareRouteDraw,
52+
);
4853

4954
const editedRouteData = useAppSelector(selectEditedRouteData);
5055
const { drawingMode } = useAppSelector(selectMapRouteEditor);
5156
const { creatingNewRoute } = useAppSelector(selectMapRouteEditor);
52-
const shouldUseDrawingCursor =
53-
drawingMode === Mode.Edit && creatingNewRoute && !editedRouteData.geometry;
54-
setCursor(map, shouldUseDrawingCursor ? Mode.Draw : drawingMode);
57+
const isNewRouteDrawPhase =
58+
creatingNewRoute && !editedRouteData.geometry && drawingMode !== undefined;
59+
60+
setCursor(map, isNewRouteDrawPhase ? Mode.Draw : drawingMode);
5561

5662
const { templateRouteId } = editedRouteData;
5763
// Fetch existing route's stops and geometry in case editing existing route
@@ -159,6 +165,44 @@ export const DrawRouteLayer: FC = () => {
159165
};
160166
}, [keyDown]);
161167

168+
// Check that draw is ready before removing loader in new route draw phase and allowing user to start drawing
169+
useEffect(() => {
170+
const mapInstance = map?.getMap();
171+
const handleDrawLoadingState = () => {
172+
const hasDrawRef = !!drawRef.current;
173+
const hasDrawHotSource = !!mapInstance?.getSource('mapbox-gl-draw-hot');
174+
const hasDrawColdSource = !!mapInstance?.getSource('mapbox-gl-draw-cold');
175+
176+
const isDrawReady = hasDrawRef && hasDrawHotSource && hasDrawColdSource;
177+
178+
setRouteDrawLoadingState(
179+
isDrawReady ? LoadingState.NotLoading : LoadingState.HighPriority,
180+
);
181+
};
182+
183+
if (isNewRouteDrawPhase) {
184+
setRouteDrawLoadingState(LoadingState.HighPriority);
185+
if (mapInstance) {
186+
// Check if drawing is ready
187+
handleDrawLoadingState();
188+
189+
// Re-check readiness when the map receives new data.
190+
mapInstance.on('sourcedata', handleDrawLoadingState);
191+
192+
// Re-check readiness after the map has finished updating.
193+
mapInstance.on('idle', handleDrawLoadingState);
194+
}
195+
}
196+
197+
return () => {
198+
if (mapInstance) {
199+
mapInstance.off('sourcedata', handleDrawLoadingState);
200+
mapInstance.off('idle', handleDrawLoadingState);
201+
}
202+
setRouteDrawLoadingState(LoadingState.NotLoading);
203+
};
204+
}, [isNewRouteDrawPhase, map, setRouteDrawLoadingState]);
205+
162206
// If we don't have metadata, we should not render <DrawControl>
163207
// useControl hook inside <DrawControl> do not rerender correctly and have an incorrect state
164208
if (!editedRouteData.metaData) {
@@ -184,7 +228,7 @@ export const DrawRouteLayer: FC = () => {
184228
const onModeChange = () => {
185229
// Disables all other modes when editing
186230
if (drawingMode === Mode.Edit) {
187-
mapboxDraw?.changeMode('direct_select', {
231+
drawRef.current?.changeMode('direct_select', {
188232
featureId: SNAPPING_LINE_LAYER_ID,
189233
});
190234
}

ui/src/redux/slices/loader.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export enum Operation {
1616
SaveStop = 'saveStop',
1717
DeleteStop = 'deleteStop',
1818
SaveRoute = 'saveRoute',
19+
PrepareRouteDraw = 'prepareRouteDraw',
1920
MatchRoute = 'matchRoute',
2021
ModifyStopArea = 'modifyStopArea',
2122
ModifyTerminal = 'modifyTerminal',
@@ -89,6 +90,7 @@ export const mapOperations = [
8990
Operation.DeleteStop,
9091
Operation.ModifyStopArea,
9192
Operation.SaveRoute,
93+
Operation.PrepareRouteDraw,
9294
Operation.MatchRoute,
9395
Operation.CheckBrokenRoutes,
9496
Operation.SaveTimingPlace,

0 commit comments

Comments
 (0)