fix: Add coordinate validation to prevent Invalid LngLat errors

- Add isValidCoordinate() helper to validate lat/lng ranges
- Validate viewport center on map initialization
- Skip participants and waypoints with invalid coordinates
- Add validation to auto-center and fitToParticipants

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-12-25 21:28:34 -05:00
parent eeab19ceac
commit 39f8c83ba9
1 changed files with 47 additions and 9 deletions

View File

@ -24,6 +24,20 @@ const DEFAULT_VIEWPORT: MapViewport = {
zoom: 15, zoom: 15,
}; };
// Validate coordinates are within valid ranges
function isValidCoordinate(lat: number, lng: number): boolean {
return (
typeof lat === 'number' &&
typeof lng === 'number' &&
!isNaN(lat) &&
!isNaN(lng) &&
lat >= -90 &&
lat <= 90 &&
lng >= -180 &&
lng <= 180
);
}
export default function MapView({ export default function MapView({
participants, participants,
waypoints = [], waypoints = [],
@ -45,6 +59,12 @@ export default function MapView({
useEffect(() => { useEffect(() => {
if (!mapContainer.current || map.current) return; if (!mapContainer.current || map.current) return;
// Validate viewport center coordinates, fall back to default if invalid
const [lng, lat] = initialViewport.center;
const validCenter = isValidCoordinate(lat, lng)
? initialViewport.center
: DEFAULT_VIEWPORT.center;
map.current = new maplibregl.Map({ map.current = new maplibregl.Map({
container: mapContainer.current, container: mapContainer.current,
style: { style: {
@ -73,8 +93,8 @@ export default function MapView({
}, },
], ],
}, },
center: initialViewport.center, center: validCenter,
zoom: initialViewport.zoom, zoom: initialViewport.zoom || DEFAULT_VIEWPORT.zoom,
bearing: initialViewport.bearing ?? 0, bearing: initialViewport.bearing ?? 0,
pitch: initialViewport.pitch ?? 0, pitch: initialViewport.pitch ?? 0,
}); });
@ -133,6 +153,12 @@ export default function MapView({
if (!participant.location) return; if (!participant.location) return;
const { latitude, longitude } = participant.location; const { latitude, longitude } = participant.location;
// Skip invalid coordinates
if (!isValidCoordinate(latitude, longitude)) {
console.warn('Invalid coordinates for participant:', participant.id, latitude, longitude);
return;
}
let marker = currentMarkers.get(participant.id); let marker = currentMarkers.get(participant.id);
if (marker) { if (marker) {
@ -169,12 +195,15 @@ export default function MapView({
if (autoCenterOnUser && !hasCenteredOnUserRef.current && currentUserId) { if (autoCenterOnUser && !hasCenteredOnUserRef.current && currentUserId) {
const currentUser = participants.find(p => p.id === currentUserId); const currentUser = participants.find(p => p.id === currentUserId);
if (currentUser?.location && map.current) { if (currentUser?.location && map.current) {
console.log('Auto-centering on user location:', currentUser.location.latitude, currentUser.location.longitude); const { latitude, longitude } = currentUser.location;
map.current.flyTo({ if (isValidCoordinate(latitude, longitude)) {
center: [currentUser.location.longitude, currentUser.location.latitude], console.log('Auto-centering on user location:', latitude, longitude);
zoom: 16, map.current.flyTo({
}); center: [longitude, latitude],
hasCenteredOnUserRef.current = true; zoom: 16,
});
hasCenteredOnUserRef.current = true;
}
} }
} }
}, [participants, mapLoaded, currentUserId, onParticipantClick, autoCenterOnUser]); }, [participants, mapLoaded, currentUserId, onParticipantClick, autoCenterOnUser]);
@ -197,6 +226,13 @@ export default function MapView({
// Add/update waypoint markers // Add/update waypoint markers
waypoints.forEach((waypoint) => { waypoints.forEach((waypoint) => {
const { latitude, longitude } = waypoint.location; const { latitude, longitude } = waypoint.location;
// Skip invalid coordinates
if (!isValidCoordinate(latitude, longitude)) {
console.warn('Invalid coordinates for waypoint:', waypoint.id, latitude, longitude);
return;
}
let marker = currentWaypointMarkers.get(waypoint.id); let marker = currentWaypointMarkers.get(waypoint.id);
if (marker) { if (marker) {
@ -271,7 +307,9 @@ export default function MapView({
const fitToParticipants = () => { const fitToParticipants = () => {
if (!map.current || participants.length === 0) return; if (!map.current || participants.length === 0) return;
const locatedParticipants = participants.filter((p) => p.location); const locatedParticipants = participants.filter(
(p) => p.location && isValidCoordinate(p.location.latitude, p.location.longitude)
);
if (locatedParticipants.length === 0) return; if (locatedParticipants.length === 0) return;
if (locatedParticipants.length === 1) { if (locatedParticipants.length === 1) {