From 398d9edcbba81acba72e9a38fac1bfb5cd503e7c Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Wed, 27 May 2026 01:17:56 +0200 Subject: [PATCH] Add map error boundary and move Leaflet CSS Import global Leaflet CSS in the app layout, create a MapErrorBoundary in the map page to catch map load failures and show a retry UI, and wrap the dynamic CollectionMap with that boundary. Adjust CollectionMap by removing the local Leaflet CSS import, cleaning up unused imports/types, and changing the container to absolute/full-bleed styling so the map fills its parent. These changes improve robustness against map loading errors and ensure Leaflet styles are applied app-wide. --- app/layout.tsx | 1 + app/map/page.tsx | 32 ++++++++++++++++++++++++++++++-- components/CollectionMap.tsx | 15 ++++++++++----- 3 files changed, 41 insertions(+), 7 deletions(-) diff --git a/app/layout.tsx b/app/layout.tsx index 99ff85d..b802701 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,4 +1,5 @@ import type { Metadata, Viewport } from "next"; +import "leaflet/dist/leaflet.css"; import "./globals.css"; import { AuthProvider } from "@/components/AuthProvider"; import OfflineIndicator from "@/components/OfflineIndicator"; diff --git a/app/map/page.tsx b/app/map/page.tsx index 76629a6..ece9c48 100644 --- a/app/map/page.tsx +++ b/app/map/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useState, useEffect, useCallback, Suspense } from 'react'; +import { useState, useEffect, useCallback, Suspense, Component } from 'react'; import { useRouter } from 'next/navigation'; import dynamic from 'next/dynamic'; import { OrderItem } from '@/lib/types'; @@ -23,6 +23,32 @@ const CollectionMap = dynamic(() => import('@/components/CollectionMap'), { ), }); +class MapErrorBoundary extends Component<{ children: React.ReactNode }, { hasError: boolean; error: string }> { + constructor(props: { children: React.ReactNode }) { + super(props); + this.state = { hasError: false, error: '' }; + } + static getDerivedStateFromError(error: Error) { + return { hasError: true, error: error.message }; + } + render() { + if (this.state.hasError) { + return ( +
+
+ +
+

Map failed to load.

+ +
+ ); + } + return this.props.children; + } +} + export default function MapPage() { const router = useRouter(); const { isLoggedIn, isLoading: authLoading } = useAuth(); @@ -131,7 +157,9 @@ export default function MapPage() {
}> - + + + )} diff --git a/components/CollectionMap.tsx b/components/CollectionMap.tsx index 5e01478..c580a60 100644 --- a/components/CollectionMap.tsx +++ b/components/CollectionMap.tsx @@ -2,12 +2,11 @@ import { useEffect, useMemo, useState, useCallback, useRef } from 'react'; import { MapContainer, TileLayer, Marker, Popup, Polyline, useMap } from 'react-leaflet'; -import { OrderItem, Supplier, DriverLocation } from '@/lib/types'; +import { OrderItem, Supplier } from '@/lib/types'; import { formatCurrency, calculateDistance, parseCoordinates } from '@/lib/utils'; import { getDriverTrail, isAuthenticated, getCurrentUser } from '@/lib/pocketbase'; -import { Navigation, AlertTriangle, Route, Crosshair, Layers } from 'lucide-react'; +import { Navigation, AlertTriangle, Route, Crosshair } from 'lucide-react'; import L from 'leaflet'; -import 'leaflet/dist/leaflet.css'; const defaultIcon = L.icon({ iconUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-icon.png', @@ -129,8 +128,14 @@ export default function CollectionMap({ items, onNavigate }: MapViewProps) { }; return ( -
- +
+