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.
This commit is contained in:
parent
2c896eede8
commit
398d9edcbb
3 changed files with 41 additions and 7 deletions
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="h-full flex flex-col items-center justify-center bg-gray-100 p-4">
|
||||
<div className="w-16 h-16 bg-red-50 rounded-2xl flex items-center justify-center mb-4">
|
||||
<AlertCircle size={32} className="text-red-400" />
|
||||
</div>
|
||||
<p className="text-gray-600 text-sm mb-4 text-center">Map failed to load.</p>
|
||||
<button onClick={() => this.setState({ hasError: false })} className="px-5 py-2.5 bg-orange-500 text-white rounded-xl text-sm font-medium active:bg-orange-600">
|
||||
Try Again
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
|
||||
export default function MapPage() {
|
||||
const router = useRouter();
|
||||
const { isLoggedIn, isLoading: authLoading } = useAuth();
|
||||
|
|
@ -131,7 +157,9 @@ export default function MapPage() {
|
|||
<div className="w-8 h-8 border-[3px] border-orange-500 border-t-transparent rounded-full animate-spin" />
|
||||
</div>
|
||||
}>
|
||||
<CollectionMap items={items} onNavigate={handleNavigate} />
|
||||
<MapErrorBoundary>
|
||||
<CollectionMap items={items} onNavigate={handleNavigate} />
|
||||
</MapErrorBoundary>
|
||||
</Suspense>
|
||||
)}
|
||||
</main>
|
||||
|
|
|
|||
|
|
@ -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 (
|
||||
<div className="h-full w-full relative">
|
||||
<MapContainer center={center} zoom={12} className="h-full w-full" zoomControl={false}>
|
||||
<div className="absolute inset-0">
|
||||
<MapContainer
|
||||
center={center}
|
||||
zoom={12}
|
||||
className="absolute inset-0 z-0"
|
||||
zoomControl={false}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
>
|
||||
<TileLayer
|
||||
attribution='© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
|
|
|
|||
Loading…
Reference in a new issue