Skip to content
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

SAFB-249: Group Icon Functionality #305

Open
wants to merge 8 commits into
base: development
Choose a base branch
from
17 changes: 12 additions & 5 deletions src/components/BaseMap/PinLayer.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,18 @@ export class PinLayer extends CompositeLayer {
}

_getPinColor(feature) {
if (
feature.properties.cluster &&
this._getExpansionZoom(feature) <= this.props.maxZoom
)
return [246, 190, 0, 255];
if (feature.properties.cluster) {
const expansionZoom = this._getExpansionZoom(feature);

const isCluster = expansionZoom <= this.props.maxZoom;
const isGroup = expansionZoom >= this.props.maxZoom;

if (isGroup) {
return this.props.getPinColor(feature)
} else if (isCluster) {
return [246, 190, 0, 255];
allynt marked this conversation as resolved.
Show resolved Hide resolved
}
}
if (typeof this.props.getPinColor === 'function')
return this.props.getPinColor(feature);
if (isArray(this.props.pinColor)) return this.props.pinColor;
Expand Down
17 changes: 16 additions & 1 deletion src/helpers/mapHelper.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,27 @@ export const getPolygonLayer = (aoi) => {
}))
}

const selectedItemIsInGroup = (feature, selectedItem) => {
const clusterCoords = feature.geometry.coordinates;
const selectedItemCoords = selectedItem.center.map(coord => coord.toFixed(2));

return clusterCoords.every(
coord => selectedItemCoords.includes(coord.toFixed(2))
);
}
allynt marked this conversation as resolved.
Show resolved Hide resolved

export const getAlertIconColorFromContext = (mapType, feature, selectedItem = {}) => {
let color = DARK_GRAY;
if (!feature.properties.id && !selectedItem.id) {
return color;
}

if (feature.properties.cluster) {
if (selectedItemIsInGroup(feature, selectedItem)) {
return ORANGE;
}
}

if (feature.properties.id === selectedItem.id) {
color = ORANGE;
} else if (ALERT_TYPES.red.includes(feature?.properties?.status)) {
Expand Down Expand Up @@ -100,7 +115,7 @@ export const getIconLayer = (alerts, mapType, markerName='alert', dispatch, setV
dispatch,
setViewState,
getPosition: (feature) => feature.geometry.coordinates,
getPinColor: feature => getAlertIconColorFromContext(mapType, feature, selectedItem),
getPinColor: (feature) => getAlertIconColorFromContext(mapType, feature, selectedItem),
icon: markerName,
iconColor: '#ffffff',
clusterIconSize: 35,
Expand Down
9 changes: 8 additions & 1 deletion src/pages/Chatbot/Comms/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ const Comms = () => {

useEffect(() => {
if (allReports.length > 0) {
setIconLayer(getIconLayer(allReports, MAP_TYPES.COMMUNICATIONS, 'communications', dispatch, setViewState, {id: commID}));

Choose a reason for hiding this comment

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

Empty line as the first bit of the if isn't great, in my opinion, but it is just my opinion, I know some devs like it and others seem to accidentally do it.

const selectedComm = allReports.find(comm => comm.id === commID)

const pinInfo = selectedComm
? { center: selectedComm.location, id: commID }
: {};

setIconLayer(getIconLayer(allReports, MAP_TYPES.COMMUNICATIONS, 'communications', dispatch, setViewState, pinInfo));
}
}, [allReports, commID]);
allynt marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
9 changes: 8 additions & 1 deletion src/pages/Chatbot/Missions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,14 @@ const Missions = () => {

useEffect(() => {
if (allMissions.length > 0) {
setIconLayer(getIconLayer(allMissions, MAP_TYPES.MISSIONS, 'target', dispatch, setViewState, {id: missionId}));

Choose a reason for hiding this comment

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

same again

const selectedMission = allMissions.find(mission => mission.id === missionId)

const pinInfo = selectedMission
? { center: selectedMission.location, id: missionId }
: {}

setIconLayer(getIconLayer(allMissions, MAP_TYPES.MISSIONS, 'target', dispatch, setViewState, pinInfo));

Choose a reason for hiding this comment

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

The code in these 2 useEffects are almost identical, find an item by it's id in an array, then create an object from it and other info, then create an icon layer. I get that the arrays are differnt and the Map_TYPES etc, but the idea is the same, that is ripe for a utility function. Repeating it twice isn't a big deal, but what if you had to do it 10 times, for instance.

}
}, [allMissions, missionId]);

Expand Down
9 changes: 8 additions & 1 deletion src/pages/Chatbot/People/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,14 @@ const People = () => {

useEffect(() => {
if (allPeople.length > 0) {
setIconLayer(getIconLayer(allPeople, MAP_TYPES.PEOPLE, 'people', dispatch, setViewState, {id: peopleId}));

Choose a reason for hiding this comment

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

and again, leading empty line.

const selectedPeople = allPeople.find(people => people.id === peopleId)

const pinInfo = selectedPeople
? { center: selectedPeople.location, id: peopleId }
: {};

setIconLayer(getIconLayer(allPeople, MAP_TYPES.PEOPLE, 'people', dispatch, setViewState, pinInfo));

Choose a reason for hiding this comment

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

Same comment about a utility function here as I made before.

}
}, [allPeople, peopleId]);

Expand Down
10 changes: 8 additions & 2 deletions src/pages/Chatbot/Reports/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,15 @@ const Reports = () => {
const reshapedReports = allReports.map(report => {
const {report_id: id, ...rest} = report;
return { id, ...rest };
})
});

setIconLayer(getIconLayer(reshapedReports, MAP_TYPES.REPORTS, 'report', dispatch, setViewState, { id: reportId }, 'report_id'));
const selectedReport = allReports.find(report => report.report_id === reportId)

const pinInfo = selectedReport
? { center: selectedReport.location, id: reportId }
: {};

setIconLayer(getIconLayer(reshapedReports, MAP_TYPES.REPORTS, 'report', dispatch, setViewState, pinInfo, 'report_id'));

Choose a reason for hiding this comment

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

and again

}
}, [allReports, reportId]);

Expand Down
17 changes: 13 additions & 4 deletions src/pages/FireAlerts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -297,12 +297,21 @@ const FireAlerts = ({ t }) => {
}
};

const getCard = (card, index) => {
const handleSelectAlert = id => {
if (id === alertId) {
setSelectedAlert(undefined);
setHoverInfo(undefined)
} else {
setSelectedAlert(id);
}
}

const getCard = (card) => {
return (
<Alert
key={index}
key={card.id}
card={card}
setSelectedAlert={setSelectedAlert}
setSelectedAlert={handleSelectAlert}
setFavorite={setFavorite}
alertId={alertId}
/>
Expand Down Expand Up @@ -396,7 +405,7 @@ const FireAlerts = ({ t }) => {
<Row>
<Col xl={12} className="p-3">
<Row>
{paginatedAlerts.map((alert, index) => getCard(alert, index))}
{paginatedAlerts.map(getCard)}
</Row>
<Row className="text-center">
<Pagination
Expand Down
41 changes: 16 additions & 25 deletions src/pages/In-situ/Components/AlertList.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ import { setCurrentPage, setInSituFavoriteAlert, setPaginatedAlerts, getCamera }
import { PAGE_SIZE, SET_FAV_INSITU_ALERT_SUCCESS } from '../../../store/insitu/types';
import Alert from './Alert';
import { MAP_TYPES } from '../../../constants/common';
import { getAlertIconColorFromContext } from '../../../helpers/mapHelper';
import { GeoJsonPinLayer } from '../../../components/BaseMap/GeoJsonPinLayer';
import { getIconLayer } from '../../../helpers/mapHelper';

const AlertList = ({
alertId,
Expand All @@ -29,30 +28,11 @@ const AlertList = ({

const dispatch = useDispatch();

const getIconLayer = (alerts) => {
return new GeoJsonPinLayer({
data: alerts,
dispatch,
setViewState,
getPosition: (feature) => feature.geometry.coordinates,
getPinColor: feature => getAlertIconColorFromContext(MAP_TYPES.IN_SITU,feature),
icon: 'camera',
iconColor: '#ffffff',
clusterIconSize: 35,
getPinSize: () => 35,
pixelOffset: [-18,-18],
pinSize: 25,
onGroupClick: true,
onPointClick: true,
});
};

useEffect(() => {
if (selCam) {
!_.isEqual(viewState.midPoint, cameraInfo?.geometry?.coordinates) || isViewStateChanged ?
setViewState(getViewState(cameraInfo?.geometry?.coordinates, currentZoomLevel, cameraInfo, setHoverInfo, setIsViewStateChanged))
: setHoverInfo({ object: { properties: cameraInfo, geometry: cameraInfo?.geometry}, picked: true });
setIconLayer(getIconLayer(cameraList.features, MAP_TYPES.IN_SITU));
}
}, [cameraInfo]);

Expand Down Expand Up @@ -80,7 +60,9 @@ const AlertList = ({
dispatch(getCamera(selectedAlert.camera_id));
} else {
setAlertId(undefined);
setIconLayer(getIconLayer(cameraList.features, MAP_TYPES.IN_SITU));
if (cameraList.features) {
setIconLayer(getIconLayer(cameraList.features, MAP_TYPES.IN_SITU));
}
}
}

Expand All @@ -94,14 +76,23 @@ const AlertList = ({
dispatch(setPaginatedAlerts(_.cloneDeep(filteredAlerts.slice(from, to))));
};

const handleSelectAlert = (id) => {
if (id === alertId) {
setSelectedAlert(undefined);
setHoverInfo(undefined);
} else {
setSelectedAlert(id);
}
}

return (
<>

Choose a reason for hiding this comment

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

Not your code I get it, but is this fragment <></> needed, does the Row not suffice?

<Row>
{
paginatedAlerts.map((alert, index) => <Alert
key={index}
paginatedAlerts.map((alert) => <Alert
key={alert.id}
card={alert}
setSelectedAlert={setSelectedAlert}
setSelectedAlert={handleSelectAlert}
setFavorite={setFavorite}
alertId={alertId} />)
}
Expand Down
34 changes: 11 additions & 23 deletions src/pages/In-situ/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,11 @@ import {
} from '../../store/appAction';
import { getBoundingBox, getViewState } from '../../helpers/mapHelper';
import { PAGE_SIZE } from '../../store/events/types';
import { GeoJsonPinLayer } from '../../components/BaseMap/GeoJsonPinLayer';

//i18n
import { useTranslation } from 'react-i18next'
import { MAP_TYPES } from '../../constants/common';
import { getAlertIconColorFromContext } from '../../helpers/mapHelper';
import { getIconLayer } from '../../helpers/mapHelper';

const InSituAlerts = () => {
const defaultAoi = useSelector(state => state.user.defaultAoi);
Expand All @@ -49,25 +48,6 @@ const InSituAlerts = () => {
const { t } = useTranslation();
const dispatch = useDispatch();

const getIconLayer = (alerts) => {
return new GeoJsonPinLayer({
data: alerts,
dispatch,
setViewState,
getPosition: (feature) => feature.geometry.coordinates,
getPinColor: feature => getAlertIconColorFromContext(MAP_TYPES.IN_SITU,feature),
icon: 'camera',
iconColor: '#ffffff',
clusterIconSize: 35,
getPinSize: () => 35,
pixelOffset: [-18,-18],
pinSize: 25,
onGroupClick: true,
onPointClick: true,
});
};


useEffect(() => {
dispatch(getCameraSources());
}, [])
Expand Down Expand Up @@ -108,8 +88,16 @@ const InSituAlerts = () => {
}, [success, error]);

useEffect(() => {
setIconLayer(getIconLayer(cameraList.features, MAP_TYPES.IN_SITU));
}, [cameraList]);
if (cameraList.features) {
const selectedAlert = alerts.find(alert => alert.id === alertId);

const pinInfo = selectedAlert
? { center: selectedAlert.geometry.coordinates, id: alertId }
: {};

setIconLayer(getIconLayer(cameraList.features, MAP_TYPES.IN_SITU, 'camera', dispatch, setViewState, pinInfo));
}

Choose a reason for hiding this comment

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

Same comment as before about the utility function. That is 4 occurrences of the same idea, just using different params.

}, [cameraList, alertId]);

useEffect(() => {
if (!viewState) {
Expand Down