diff --git a/web/client/plugins/Itinerary/epics/__tests__/itinerary-test.js b/web/client/plugins/Itinerary/epics/__tests__/itinerary-test.js index 9a96bb7a0d..41eccb3704 100644 --- a/web/client/plugins/Itinerary/epics/__tests__/itinerary-test.js +++ b/web/client/plugins/Itinerary/epics/__tests__/itinerary-test.js @@ -45,7 +45,7 @@ import { import { CONTROL_NAME, ITINERARY_ROUTE_LAYER } from '../../constants'; import { ADD_LAYER } from '../../../../actions/layers'; import { REMOVE_ADDITIONAL_LAYER, REMOVE_ALL_ADDITIONAL_LAYERS, UPDATE_ADDITIONAL_LAYER } from '../../../../actions/additionallayers'; -import { CHANGE_MOUSE_POINTER, ZOOM_TO_EXTENT } from '../../../../actions/map'; +import { CHANGE_MOUSE_POINTER, CLICK_ON_MAP, ZOOM_TO_EXTENT } from '../../../../actions/map'; import { CHANGE_MAPINFO_STATE, PURGE_MAPINFO_RESULTS } from '../../../../actions/mapInfo'; import { SHOW_NOTIFICATION } from '../../../../actions/notifications'; @@ -328,6 +328,8 @@ describe('Itinerary Epics', () => { it('should handle map click and update location', (done) => { const action = { type: SELECT_LOCATION_FROM_MAP, index: 1 }; + const point = { latlng: { lat: 44.4949, lng: 11.3426 } }; + const clickAction = { type: CLICK_ON_MAP, point }; const state = { itinerary: { @@ -335,9 +337,16 @@ describe('Itinerary Epics', () => { } }; - testEpic(itinerarySelectLocationFromMapEpic, 1, action, (actions) => { + testEpic(itinerarySelectLocationFromMapEpic, 4, [action, clickAction], (actions) => { expect(actions[0].type).toBe(CHANGE_MOUSE_POINTER); expect(actions[0].pointer).toBe('pointer'); + expect(actions[1].type).toBe(CHANGE_MOUSE_POINTER); + expect(actions[1].pointer).toBe('auto'); + expect(actions[2].type).toBe(UPDATE_LOCATIONS); + expect(actions[2].locations).toEqual([[2.3522, 48.8566], [11.3426, 44.4949]]); + expect(actions[3].type).toBe(UPDATE_ADDITIONAL_LAYER); + expect(actions[3].id).toBe(ITINERARY_ROUTE_LAYER + `_waypoint_marker_${1}`); + expect(actions[3].owner).toBe(CONTROL_NAME + '_waypoint_marker'); }, state, done); }); @@ -355,6 +364,56 @@ describe('Itinerary Epics', () => { expect(actions[0].pointer).toBe('pointer'); }, state, done); }); + + it('should cancel location selection when index is empty', (done) => { + const action = { type: SELECT_LOCATION_FROM_MAP, index: null }; + + testEpic(addTimeoutEpic(itinerarySelectLocationFromMapEpic, 10), 2, action, (actions) => { + expect(actions[0].type).toBe(CHANGE_MOUSE_POINTER); + expect(actions[0].pointer).toBe('auto'); + expect(actions[1].type).toBe(TEST_TIMEOUT); + expect(actions.some(({ type }) => type === UPDATE_LOCATIONS)).toBe(false); + expect(actions.some(({ type }) => type === UPDATE_ADDITIONAL_LAYER)).toBe(false); + }, {}, done); + }); + + it('should cancel pending location selection on itinerary reset', (done) => { + const point = { latlng: { lat: 44.4949, lng: 11.3426 } }; + const actions = [ + { type: SELECT_LOCATION_FROM_MAP, index: 0 }, + { type: RESET_ITINERARY }, + { type: CLICK_ON_MAP, point } + ]; + + testEpic(addTimeoutEpic(itinerarySelectLocationFromMapEpic, 10), 3, actions, (emittedActions) => { + expect(emittedActions[0].type).toBe(CHANGE_MOUSE_POINTER); + expect(emittedActions[0].pointer).toBe('pointer'); + expect(emittedActions[1].type).toBe(CHANGE_MOUSE_POINTER); + expect(emittedActions[1].pointer).toBe('auto'); + expect(emittedActions[2].type).toBe(TEST_TIMEOUT); + expect(emittedActions.some(({ type }) => type === UPDATE_LOCATIONS)).toBe(false); + expect(emittedActions.some(({ type }) => type === UPDATE_ADDITIONAL_LAYER)).toBe(false); + }, {}, done); + }); + + it('should cancel pending location selection when itinerary closes', (done) => { + const point = { latlng: { lat: 44.4949, lng: 11.3426 } }; + const actions = [ + { type: SELECT_LOCATION_FROM_MAP, index: 0 }, + { type: SET_CONTROL_PROPERTY, control: CONTROL_NAME, value: false }, + { type: CLICK_ON_MAP, point } + ]; + + testEpic(addTimeoutEpic(itinerarySelectLocationFromMapEpic, 10), 3, actions, (emittedActions) => { + expect(emittedActions[0].type).toBe(CHANGE_MOUSE_POINTER); + expect(emittedActions[0].pointer).toBe('pointer'); + expect(emittedActions[1].type).toBe(CHANGE_MOUSE_POINTER); + expect(emittedActions[1].pointer).toBe('auto'); + expect(emittedActions[2].type).toBe(TEST_TIMEOUT); + expect(emittedActions.some(({ type }) => type === UPDATE_LOCATIONS)).toBe(false); + expect(emittedActions.some(({ type }) => type === UPDATE_ADDITIONAL_LAYER)).toBe(false); + }, {}, done); + }); }); describe('onItineraryRunEpic', () => { diff --git a/web/client/plugins/Itinerary/epics/itinerary.js b/web/client/plugins/Itinerary/epics/itinerary.js index e104d83bc4..16301ae938 100644 --- a/web/client/plugins/Itinerary/epics/itinerary.js +++ b/web/client/plugins/Itinerary/epics/itinerary.js @@ -43,6 +43,10 @@ import { info, error as errorNotification } from '../../../actions/notifications import { createMarkerSvgDataUrl } from '../../../utils/StyleUtils'; const OFFSET = DEFAULT_PANEL_WIDTH; +const isCancelLocationSelectionAction = ({type, control, value}) => + type === RESET_ITINERARY + || (type === SET_CONTROL_PROPERTY && control === CONTROL_NAME && !value) + || (type === TOGGLE_CONTROL && control === CONTROL_NAME); /** * Handles itinerary map layout updates @@ -188,10 +192,26 @@ export const onOpenItineraryEpic = (action$, {getState}) => */ export const itinerarySelectLocationFromMapEpic = (action$, { getState }) => action$.ofType(SELECT_LOCATION_FROM_MAP) - .switchMap(({ index }) => - action$.ofType(CLICK_ON_MAP) + .switchMap(({ index }) => { + if (isNil(index) || index === '') { + return Observable.of(changeMousePointer('auto')); + } + const cancelSelection$ = action$ + .ofType(RESET_ITINERARY, SET_CONTROL_PROPERTY, TOGGLE_CONTROL) + .filter(isCancelLocationSelectionAction) + .take(1) + .map(() => ({ cancel: true })); + return Observable.merge( + action$.ofType(CLICK_ON_MAP) + .take(1) + .map(({ point }) => ({ point })), + cancelSelection$ + ) .take(1) .switchMap(({ point }) => { + if (!point?.latlng) { + return Observable.of(changeMousePointer('auto')); + } const { latlng } = point; const state = getState(); const locations = locationsSelector(state); @@ -202,8 +222,8 @@ export const itinerarySelectLocationFromMapEpic = (action$, { getState }) => updateLocations(newLocations), addMarkerFeature(latlng, index) ); - }).startWith(changeMousePointer('pointer')) - ); + }).startWith(changeMousePointer('pointer')); + }); /** * Handles itinerary run