Skip to content

ERA-10349: Support EFB schemas in ER > Location Field [2] #1263

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 30 additions & 25 deletions src/LocationPicker/MenuPopover/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const MenuPopover = ({
}, ref) => {
const { t } = useTranslation('components', { keyPrefix: 'locationPicker.menuPopover' });

const isPickingLocation = useSelector((state) => state.view.mapLocationSelection.isPickingLocation);
const showUserLocation = useSelector((state) => state.view.showUserLocation);

const gpsFormatToggleRef = useRef();
Expand Down Expand Up @@ -105,34 +106,38 @@ const MenuPopover = ({
}, []);

useEffect(() => {
const onMouseDown = (event) => {
if (!wrapperRef.current.contains(event.target) && !setLocationButtonRef.current.contains(event.target)) {
onClose(event);

if (!target.current.contains(event.target)) {
// Clicking away from our picker when the menu is open doesn't trigger the wrapper's blur event, so we need
// to trigger the onBlur callback manually.
const blurEvent = new FocusEvent('blur', {
bubbles: true,
cancelable: false,
relatedTarget: event.target,
});

Object.defineProperties(blurEvent, {
target: {
value: target.current,
},
});

onBlur(blurEvent);
// Add a mouse down event to close the menu if the user clicks outside only if the user is not picking a location
// from the map.
if (!isPickingLocation) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the issue when chosing a location and clicking something that is not the map. We just remove the listener while user picks a location so its logic doesn't un-focuses the location picker getting the app into a broken state.

const onMouseDown = (event) => {
if (!wrapperRef.current.contains(event.target) && !setLocationButtonRef.current.contains(event.target)) {
onClose(event);

if (onBlur && !target.current.contains(event.target)) {
// Clicking away from our picker when the menu is open doesn't trigger the wrapper's blur event, so we need
// to trigger the onBlur callback manually.
const blurEvent = new FocusEvent('blur', {
bubbles: true,
cancelable: false,
relatedTarget: event.target,
});

Object.defineProperties(blurEvent, {
target: {
value: target.current,
},
});

onBlur(blurEvent);
}
}
}
};
};

document.addEventListener('mousedown', onMouseDown);
document.addEventListener('mousedown', onMouseDown);

return () => document.removeEventListener('mousedown', onMouseDown);
}, [onBlur, onClose, setLocationButtonRef, target]);
return () => document.removeEventListener('mousedown', onMouseDown);
}
}, [isPickingLocation, onBlur, onClose, setLocationButtonRef, target]);

return <Popover
className={`${className} ${styles.menuPopover}`}
Expand Down
42 changes: 42 additions & 0 deletions src/LocationPicker/MenuPopover/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ describe('LocationPicker - MenuPopover', () => {
beforeEach(() => {
store = {
view: {
mapLocationSelection: {
isPickingLocation: false,
},
showUserLocation: false,
userLocation: null,
userPreferences: {
Expand Down Expand Up @@ -247,4 +250,43 @@ describe('LocationPicker - MenuPopover', () => {
expect(onClose).toHaveBeenCalledTimes(1);
expect(onBlur).not.toHaveBeenCalled();
});

test('does not close the menu if the user clicks outside while picking a location', () => {
store.view.mapLocationSelection.isPickingLocation = true;

render(<>
<div data-testid="outside" />

<Provider store={mockStore(store)}>
<MapContext.Provider value={map}>
<MenuPopover
className="className"
id="locationPicker"
onBlur={onBlur}
onChange={onChange}
onClose={onClose}
setLocationButtonRef={{
current: {
contains: () => false,
focus: setLocationButtonRefFocus,
},
}}
style={{}}
target={{
current: {
contains: () => false,
offsetWidth: 100,
},
}}
value={null}
/>
</MapContext.Provider>
</Provider>
</>);

userEvent.click(screen.getByTestId('outside'));

expect(onClose).not.toHaveBeenCalled();
expect(onBlur).not.toHaveBeenCalled();
});
});
3 changes: 3 additions & 0 deletions src/LocationPicker/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ describe('LocationPicker', () => {

store = {
view: {
mapLocationSelection: {
isPickingLocation: false,
},
showUserLocation: false,
userLocation: null,
userPreferences: {
Expand Down
2 changes: 0 additions & 2 deletions src/MapDrawingTools/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,6 @@ describe('MapDrawingTools', () => {
});

test('adding a layer if the source exists', () => {
map.getSource.mockReturnValue({ whatever: 'yes' });

render(
<MapContext.Provider value={map}>
<MapDrawingToolsContextProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ describe('ReportManager - DetailsSection - SchemaForm - fields - Location', () =

store = {
view: {
mapLocationSelection: {
isPickingLocation: false,
},
showUserLocation: false,
userLocation: null,
userPreferences: {
Expand Down
12 changes: 7 additions & 5 deletions src/ReportManager/DetailsSection/SchemaForm/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import { FORM_ELEMENT_TYPES, ROOT_CANVAS_ID } from './constants';
import makeFieldsFromSchema from './utils/makeFieldsFromSchema';
import useLocationMarkersLayer from './utils/useLocationMarkersLayer';
import useMapLocationMarkers from './utils/useMapLocationMarkers';
import useSchemaValidations from './utils/useSchemaValidations';

import Collection from './fields/Collection';
Expand All @@ -23,7 +23,9 @@ export const FIELDS = {

const SchemaForm = ({
autofillDefaultInputs,
eventId,
eventLocation,
hideMapLocationMarkers,
initialFormData,
onFormDataChange,
onFormSubmit,
Expand All @@ -48,8 +50,8 @@ const SchemaForm = ({
const {
blurLocationMarker,
focusLocationMarker,
updateLocationMarkers
} = useLocationMarkersLayer(eventLocation, onLocationMarkerClick);
setLocationMarkers,
} = useMapLocationMarkers(eventId, eventLocation, onLocationMarkerClick, hideMapLocationMarkers);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The useMapLocationMarkers hook now receives the eventId and a flag to hideMapLocationMarkers. Previously, the source and layer ids where constants, meaning that several instances of the hook couldn't be mounted at the same time. Now the eventId makes each source and layer id even if the hook mounts multiple times. The hideMapLocationMarkers is used for the scenario where one event is added over another (clicking the Event button in the footer of a Report Detail View), so the event that is now behind doesn't show its markers.


// This ref works as a flag to trigger a useEffect and call onFormDataChange asynchronously when there are changes in
// the form data, so we can keep the onSectionFieldChange dependency array empty.
Expand Down Expand Up @@ -160,8 +162,8 @@ const SchemaForm = ({
};
addLocationMarkersFromFormDataRecursively(formData);

updateLocationMarkers(locationMarkers);
}, [fields, formData, updateLocationMarkers]);
setLocationMarkers(locationMarkers);
}, [fields, formData, setLocationMarkers]);

return <form onSubmit={onSubmit}>
{fields[ROOT_CANVAS_ID]?.details.fields.map((sectionId) => <Section
Expand Down
Loading