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

[Platform] Enhancements on JSON and Map errors #2548

Merged
merged 4 commits into from
Mar 8, 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
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,39 @@ const OrganizationDropdown = () => {

// Initialize active group if missing
useEffect(() => {
// If we're still fetching, do nothing yet
if (isFetchingActiveGroup) return;

const storedGroup = localStorage.getItem('activeGroup');
if (storedGroup) {
const defaultGroup = JSON.parse(storedGroup);
dispatch(setOrganizationName(defaultGroup.grp_title));
try {
// Attempt to parse the stored group
const defaultGroup = JSON.parse(storedGroup);

// Check if defaultGroup and its properties exist
if (defaultGroup && defaultGroup.grp_title) {
dispatch(setOrganizationName(defaultGroup.grp_title));
} else {
// If the stored data is missing expected fields, remove it
localStorage.removeItem('activeGroup');
console.warn(
'activeGroup in localStorage is missing grp_title, removing it...',
);
}
} catch (error) {
// If JSON parsing fails, remove the invalid item
console.error('Error parsing activeGroup from localStorage:', error);
localStorage.removeItem('activeGroup');
}
} else if (!activeGroupId && activeGroups.length > 0) {
// No activeGroup in localStorage, so pick the first available group
const defaultGroup = activeGroups[0];
localStorage.setItem('activeGroup', JSON.stringify(defaultGroup));
dispatch(setOrganizationName(defaultGroup.grp_title));
if (defaultGroup && defaultGroup.grp_title) {
dispatch(setOrganizationName(defaultGroup.grp_title));
}
}
}, [activeGroupId, activeGroups, dispatch]);
}, [isFetchingActiveGroup, activeGroupId, activeGroups, dispatch]);

const handleUpdatePreferences = useCallback(
async (group) => {
Expand Down
107 changes: 59 additions & 48 deletions src/platform/src/common/components/Map/AirQoMap.jsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// AirQoMap.jsx
import React, { useEffect, useRef, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import mapboxgl from 'mapbox-gl';
Expand Down Expand Up @@ -47,16 +48,20 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
'mapbox://styles/mapbox/streets-v11',
);

// Parse and Validate URL Parameters
// Parse and validate URL parameters
let latParam, lngParam, zmParam;
let hasValidParams = false;

if (typeof window !== 'undefined') {
const urlParams = new URLSearchParams(window.location.search);
latParam = parseFloat(urlParams.get('lat'));
lngParam = parseFloat(urlParams.get('lng'));
zmParam = parseFloat(urlParams.get('zm'));
hasValidParams = !isNaN(latParam) && !isNaN(lngParam) && !isNaN(zmParam);
try {
const urlParams = new URLSearchParams(window.location.search);
latParam = parseFloat(urlParams.get('lat'));
lngParam = parseFloat(urlParams.get('lng'));
zmParam = parseFloat(urlParams.get('zm'));
hasValidParams = !isNaN(latParam) && !isNaN(lngParam) && !isNaN(zmParam);
} catch (error) {
console.error('Error parsing URL parameters:', error);
hasValidParams = false;
}
}

// Redux Selectors
Expand All @@ -79,14 +84,14 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
);
const shareLocation = useShareLocation(setToastMessage, mapRef);

// Clear Data on Unmount
// Clear data on unmount
useEffect(() => {
return () => {
dispatch(clearData());
};
}, [dispatch]);

// Set Center and Zoom Based on URL Params or Reset Map
// Set center and zoom based on URL parameters or reset map
useEffect(() => {
if (hasValidParams) {
dispatch(setCenter({ latitude: latParam, longitude: lngParam }));
Expand All @@ -96,18 +101,17 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
}
}, [hasValidParams, latParam, lngParam, zmParam, dispatch]);

// Initialize Map
// Initialize the map
useEffect(() => {
const initializeMap = async () => {
try {
mapboxgl.accessToken = mapboxApiAccessToken;

const initialCenter = hasValidParams
? [lngParam, latParam]
: [mapData.center.longitude, mapData.center.latitude];
const initialZoom = hasValidParams ? zmParam : mapData.zoom;

if (!mapContainerRef.current) return; // Ensure container exists
if (!mapContainerRef.current) return;

const map = new mapboxgl.Map({
container: mapContainerRef.current,
Expand All @@ -119,21 +123,25 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
mapRef.current = map;

map.on('load', () => {
map.resize();

// Add controls conditionally
if (!(width < 1024 && selectedNode)) {
map.addControl(new CustomZoomControl(dispatch), 'bottom-right');
map.addControl(
new CustomGeolocateControl(setToastMessage),
'bottom-right',
);
try {
map.resize();

// Conditionally add controls
if (!(width < 1024 && selectedNode)) {
map.addControl(new CustomZoomControl(), 'bottom-right');
map.addControl(
new CustomGeolocateControl(setToastMessage),
'bottom-right',
);
}

// Fetch data after the map is loaded
fetchAndProcessData();
setLoading(false);
dispatch(setMapLoading(false));
} catch (err) {
console.error('Error during map load event:', err);
}

// Fetch data once map is loaded
fetchAndProcessData();
setLoading(false);
dispatch(setMapLoading(false));
});

map.on('error', (e) => {
Expand All @@ -153,15 +161,18 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
if (!mapRef.current) {
initializeMap();
} else {
// Update the map's style, center, and zoom
mapRef.current.setStyle(mapStyle);
mapRef.current.flyTo({
center: hasValidParams
? [lngParam, latParam]
: [mapData.center.longitude, mapData.center.latitude],
zoom: hasValidParams ? zmParam : mapData.zoom,
essential: true,
});
try {
mapRef.current.setStyle(mapStyle);
mapRef.current.flyTo({
center: hasValidParams
? [lngParam, latParam]
: [mapData.center.longitude, mapData.center.latitude],
zoom: hasValidParams ? zmParam : mapData.zoom,
essential: true,
});
} catch (error) {
console.error('Error updating map style:', error);
}
}

return () => {
Expand All @@ -172,39 +183,37 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
};
}, [mapStyle, NodeType, mapboxApiAccessToken, width]);

// Manage Loading State Timeout
// Manage loading state timeout
useEffect(() => {
if (loading) {
const loaderTimer = setTimeout(() => {
if (!mapRef.current || mapRef.current.isStyleLoaded()) {
setLoading(false);
}
}, 10000);

return () => clearTimeout(loaderTimer);
}
}, [loading]);

// Handle Node Selection Loading
// Handle node selection loading
useEffect(() => {
if (selectedNode) {
const skeletonTimer = setTimeout(() => {
dispatch(setMapLoading(false));
setLoading(false);
}, 2000);

return () => clearTimeout(skeletonTimer);
}
}, [dispatch, selectedNode]);

// Handle Location Boundaries
// Handle location boundaries with improved error handling in the hook
useLocationBoundaries({
mapRef,
mapData,
setLoading,
});

// Fly to New Center and Zoom When Map Data Changes
// Fly to new center and zoom when map data changes
useEffect(() => {
if (mapRef.current && mapData.center && mapData.zoom) {
const { latitude, longitude } = mapData.center;
Expand All @@ -225,7 +234,7 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
zmParam,
]);

// Update Clusters When Data Changes
// Update clusters when data changes
useEffect(() => {
if (mapRef.current) {
try {
Expand All @@ -236,20 +245,22 @@ const AirQoMap = ({ customStyle, mapboxApiAccessToken, pollutant }) => {
}
}, [clusterUpdate]);

// Handle Window Resize
// Handle window resize events
useEffect(() => {
const handleResize = () => {
if (mapRef.current && mapRef.current.isStyleLoaded()) {
mapRef.current.resize();
try {
if (mapRef.current && mapRef.current.isStyleLoaded()) {
mapRef.current.resize();
}
} catch (error) {
console.error('Error handling window resize:', error);
}
};

window.addEventListener('resize', handleResize);
handleResize();

return () => {
window.removeEventListener('resize', handleResize);
};
return () => window.removeEventListener('resize', handleResize);
}, [selectedNode]);

return (
Expand Down
Loading
Loading