From c02106b5863195b0a75b7709a24d53c99c2f7afe Mon Sep 17 00:00:00 2001 From: yusuftomilola Date: Wed, 4 Mar 2026 18:14:01 +0100 Subject: [PATCH] feat: custom 404 page and global loading system --- .../common/GlobalLoadingWrapper.jsx | 32 ++++++++++ src/pages/NotFound.jsx | 39 +++++++++-- src/routes/AppRouter.jsx | 64 +++++++++++-------- 3 files changed, 104 insertions(+), 31 deletions(-) create mode 100644 src/components/common/GlobalLoadingWrapper.jsx diff --git a/src/components/common/GlobalLoadingWrapper.jsx b/src/components/common/GlobalLoadingWrapper.jsx new file mode 100644 index 0000000..9c843a7 --- /dev/null +++ b/src/components/common/GlobalLoadingWrapper.jsx @@ -0,0 +1,32 @@ +import { useNavigation } from 'react-router-dom'; +import { useSelector } from 'react-redux'; +import Spinner from './Spinner'; + +const selectIsAnyLoading = (state) => + state.auth.isLoading || + state.campaigns.loading || + state.donations.loading || + state.dashboard.loading; + +const GlobalLoadingWrapper = ({ children }) => { + const navigation = useNavigation(); + const isReduxLoading = useSelector(selectIsAnyLoading); + + const isLoading = navigation.state !== 'idle' || isReduxLoading; + + return ( + <> + {children} + {isLoading && ( +
+ +
+ )} + + ); +}; + +export default GlobalLoadingWrapper; diff --git a/src/pages/NotFound.jsx b/src/pages/NotFound.jsx index 3e0d3fb..153b9ff 100644 --- a/src/pages/NotFound.jsx +++ b/src/pages/NotFound.jsx @@ -1,11 +1,40 @@ -import { Link } from 'react-router-dom'; +import { Link, useNavigate } from 'react-router-dom'; const NotFound = () => { + const navigate = useNavigate(); + return ( -
-

404 - Page Not Found

-

The page you are looking for does not exist.

- Go back to Home +
+
+

+ 404 +

+ +

+ Page Not Found +

+ +

+ The page you're looking for doesn't exist or may have been moved. + Check the URL or head back home. +

+ +
+ + Go Back Home + + + +
+
); }; diff --git a/src/routes/AppRouter.jsx b/src/routes/AppRouter.jsx index a41a5e1..027afad 100644 --- a/src/routes/AppRouter.jsx +++ b/src/routes/AppRouter.jsx @@ -1,41 +1,53 @@ +import { lazy, Suspense } from 'react'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; -// Layout import MainLayout from '../components/layout/MainLayout'; +import GlobalLoadingWrapper from '../components/common/GlobalLoadingWrapper'; +import Spinner from '../components/common/Spinner'; +import NotFound from '../pages/NotFound'; +import ErrorTest from '../components/common/ErrorTest'; -// Pages -import Home from '../pages/Home'; -import Explore from '../pages/Explore'; +// Auth pages — small, kept as static imports import Login from '../pages/Login'; import Register from '../pages/Register'; import ForgotPasswordPage from '../pages/auth/ForgotPasswordPage'; -import Dashboard from '../pages/Dashboard'; -import CampaignDetails from '../pages/CampaignDetails'; -import CreateCampaign from '../pages/CreateCampaign'; -import Admin from '../pages/Admin'; -import NotFound from '../pages/NotFound'; -// Test Component -import ErrorTest from '../components/common/ErrorTest'; +// Main pages — lazy-loaded for code splitting +const Home = lazy(() => import('../pages/Home')); +const Explore = lazy(() => import('../pages/Explore')); +const CampaignDetails = lazy(() => import('../pages/CampaignDetails')); +const CreateCampaign = lazy(() => import('../pages/CreateCampaign')); +const Dashboard = lazy(() => import('../pages/Dashboard')); +const Admin = lazy(() => import('../pages/Admin')); + +const SuspenseFallback = () => ( +
+ +
+); const AppRouter = () => { return ( - - } /> - } /> - } /> - } /> - } /> - } /> - }> - } /> - } /> - } /> - } /> - } /> - - + + }> + + } /> + } /> + } /> + } /> + } /> + } /> + }> + } /> + } /> + } /> + } /> + } /> + + + + ); };