import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import { AlertContext, type AlertContextProps, type AlertParams, LanguageContext, type LanguageContextProps } from '@ifrc-go/ui/contexts';
import { useCallback, useMemo, useState, lazy, Suspense, useEffect, Component } from 'react';
import type { ReactNode } from 'react';
import { unique } from '@togglecorp/fujs';
import RootLayout from './layouts/RootLayout';
import UploadPage from './pages/UploadPage';
import HelpPage from './pages/HelpPage';
// Lazy load heavy pages with prefetching
const AnalyticsPage = lazy(() => import('./pages/AnalyticsPage'));
const ExplorePage = lazy(() => import('./pages/ExplorePage'));
const AdminPage = lazy(() => import('./pages/AdminPage/AdminPage'));
const MapDetailPage = lazy(() => import('./pages/MapDetailsPage'));
import { FilterProvider } from './contexts/FilterContext';
import { AdminProvider } from './contexts/AdminContext';
// Simple Error Boundary Component
class ErrorBoundary extends Component<{ children: ReactNode }, { hasError: boolean }> {
constructor(props: { children: ReactNode }) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error: Error, errorInfo: any) {
console.error('Error caught by boundary:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return (
Something went wrong
Please refresh the page to try again.
);
}
return this.props.children;
}
}
// Prefetch function for better performance
const prefetchPage = (importFn: () => Promise) => {
// Start prefetching immediately
const prefetchPromise = importFn();
// Store the promise so we can reuse it
prefetchPromise.catch(() => {
// Silently handle prefetch errors
});
return prefetchPromise;
};
// Prefetch all pages on idle
const prefetchAllPages = () => {
if ('requestIdleCallback' in window) {
requestIdleCallback(() => {
prefetchPage(() => import('./pages/AnalyticsPage'));
prefetchPage(() => import('./pages/ExplorePage'));
prefetchPage(() => import('./pages/AdminPage/AdminPage'));
prefetchPage(() => import('./pages/MapDetailsPage'));
});
} else {
// Fallback for browsers without requestIdleCallback
setTimeout(() => {
prefetchPage(() => import('./pages/AnalyticsPage'));
prefetchPage(() => import('./pages/ExplorePage'));
prefetchPage(() => import('./pages/AdminPage/AdminPage'));
prefetchPage(() => import('./pages/MapDetailsPage'));
}, 1000);
}
};
const router = createBrowserRouter([
{
element: ,
children: [
{ path: '/', element: },
{ path: '/upload', element: },
{
path: '/analytics',
element: (
Loading Analytics...}>
)
},
{
path: '/explore',
element: (
Loading Explore...}>
)
},
{ path: '/help', element: },
{
path: '/admin',
element: (
Loading Admin...}>
)
},
{
path: '/map/:mapId',
element: (
Loading Map Details...}>
)
},
],
},
], {
basename: import.meta.env.BASE_URL, // This will be '/' from Vite
});
function Application() {
const [alerts, setAlerts] = useState([]);
// Prefetch pages on mount
useEffect(() => {
prefetchAllPages();
}, []);
const addAlert = useCallback((alert: AlertParams) => {
setAlerts((prevAlerts) => unique(
[...prevAlerts, alert],
(a) => a.name,
) ?? prevAlerts);
}, [setAlerts]);
const removeAlert = useCallback((name: AlertParams['name']) => {
setAlerts((prevAlerts) => {
const i = prevAlerts.findIndex((a) => a.name === name);
if (i === -1) {
return prevAlerts;
}
const newAlerts = [...prevAlerts];
newAlerts.splice(i, 1);
return newAlerts;
});
}, [setAlerts]);
const updateAlert = useCallback((name: AlertParams['name'], paramsWithoutName: Omit) => {
setAlerts((prevAlerts) => {
const i = prevAlerts.findIndex((a) => a.name === name);
if (i === -1) {
return prevAlerts;
}
const newAlerts = [...prevAlerts];
newAlerts[i] = {
...newAlerts[i],
...paramsWithoutName,
};
return newAlerts;
});
}, [setAlerts]);
const alertContextValue = useMemo(
() => ({
alerts,
addAlert,
removeAlert,
updateAlert,
}),
[alerts, addAlert, removeAlert, updateAlert],
);
const languageContextValue = useMemo(
() => ({
languageNamespaceStatus: {},
setLanguageNamespaceStatus: () => {},
currentLanguage: 'en',
setCurrentLanguage: () => {},
strings: {},
setStrings: () => {},
registerNamespace: () => {},
}),
[],
);
return (
);
}
export default function App() {
return ;
}