turash/bugulma/frontend/src/AppRouter.tsx
Damir Mukimov 673e8d4361
Some checks failed
CI/CD Pipeline / backend-lint (push) Failing after 31s
CI/CD Pipeline / backend-build (push) Has been skipped
CI/CD Pipeline / frontend-lint (push) Failing after 1m37s
CI/CD Pipeline / frontend-build (push) Has been skipped
CI/CD Pipeline / e2e-test (push) Has been skipped
fix: resolve all frontend lint errors (85 issues fixed)
- Replace all 'any' types with proper TypeScript interfaces
- Fix React hooks setState in useEffect issues with lazy initialization
- Remove unused variables and imports across all files
- Fix React Compiler memoization dependency issues
- Add comprehensive i18n translation keys for admin interfaces
- Apply consistent prettier formatting throughout codebase
- Clean up unused bulk editing functionality
- Improve type safety and code quality across frontend

Files changed: 39
- ImpactMetrics.tsx: Fixed any types and interfaces
- AdminVerificationQueuePage.tsx: Added i18n keys, removed unused vars
- LocalizationUIPage.tsx: Fixed memoization, added translations
- LocalizationDataPage.tsx: Added type safety and translations
- And 35+ other files with various lint fixes
2025-12-25 14:14:58 +01:00

516 lines
20 KiB
TypeScript

import AddOrganizationWizard from '@/components/add-organization/AddOrganizationWizard.tsx';
import { AdminLayout } from '@/components/admin/layout/AdminLayout.tsx';
import ProtectedRoute from '@/components/auth/ProtectedRoute.tsx';
import Chatbot from '@/components/chatbot/Chatbot.tsx';
import Spinner from '@/components/ui/Spinner.tsx';
import { useUI } from '@/hooks/useUI.ts';
import { NavigationProvider } from '@/providers/NavigationProvider.tsx';
import { AnimatePresence, motion } from 'framer-motion';
import React, { Suspense } from 'react';
import { Route, BrowserRouter as Router, Routes, useLocation } from 'react-router-dom';
// Performance: Lazily load page components to improve initial load time.
const LandingPage = React.lazy(() => import('../pages/LandingPage.tsx'));
const MapView = React.lazy(() => import('../pages/MapView.tsx'));
const OrganizationPage = React.lazy(() => import('@/pages/OrganizationPage.tsx'));
const OrganizationDashboardPage = React.lazy(() => import('@/pages/OrganizationDashboardPage.tsx'));
const AboutPage = React.lazy(() => import('../pages/AboutPage.tsx'));
const ContactPage = React.lazy(() => import('../pages/ContactPage.tsx'));
const PrivacyPage = React.lazy(() => import('../pages/PrivacyPage.tsx'));
const AdminDashboard = React.lazy(() => import('../pages/admin/AdminDashboard.tsx'));
const AdminOrganizationsPage = React.lazy(
() => import('../pages/admin/AdminOrganizationsPage.tsx')
);
const AdminOrganizationEditPage = React.lazy(
() => import('../pages/admin/AdminOrganizationEditPage.tsx')
);
const AdminVerificationQueuePage = React.lazy(
() => import('../pages/admin/AdminVerificationQueuePage.tsx')
);
const AdminOrganizationsAnalyticsPage = React.lazy(
() => import('../pages/admin/AdminOrganizationsAnalyticsPage.tsx')
);
const AdminSettingsMaintenancePage = React.lazy(
() => import('../pages/admin/AdminSettingsMaintenancePage.tsx')
);
// Existing admin pages (migrating to new structure)
const UsersListPage = React.lazy(() => import('../pages/admin/UsersListPage.tsx'));
const UserEditPage = React.lazy(() => import('../pages/admin/UserEditPage.tsx'));
const ContentPagesPage = React.lazy(() => import('../pages/admin/ContentPagesPage.tsx'));
const ContentPageEditPage = React.lazy(() => import('../pages/admin/ContentPageEditPage.tsx'));
const AnnouncementsPage = React.lazy(() => import('../pages/admin/AnnouncementsPage.tsx'));
const MediaLibraryPage = React.lazy(() => import('../pages/admin/MediaLibraryPage.tsx'));
const LocalizationUIPage = React.lazy(() => import('../pages/admin/LocalizationUIPage.tsx'));
const LocalizationDataPage = React.lazy(() => import('../pages/admin/LocalizationDataPage.tsx'));
const DashboardPage = React.lazy(() => import('../pages/DashboardPage.tsx'));
const AnalyticsDashboard = React.lazy(() => import('../pages/AnalyticsDashboard.tsx'));
const ImpactMetrics = React.lazy(() => import('../pages/ImpactMetrics.tsx'));
const SupplyDemandAnalysis = React.lazy(() => import('../pages/SupplyDemandAnalysis.tsx'));
const OrganizationsListPage = React.lazy(() => import('../pages/OrganizationsListPage.tsx'));
const OrganizationEditPage = React.lazy(() => import('../pages/OrganizationEditPage.tsx'));
const HeritagePage = React.lazy(() => import('../pages/HeritagePage.tsx'));
const HeritageBuildingPage = React.lazy(() => import('../pages/HeritageBuildingPage.tsx'));
const LoginPage = React.lazy(() => import('../pages/LoginPage.tsx'));
const SignupPage = React.lazy(() => import('../pages/SignupPage.tsx'));
const ResourceFlowsPage = React.lazy(() => import('../pages/ResourceFlowsPage.tsx'));
const ResourceFlowDetailPage = React.lazy(() => import('../pages/ResourceFlowDetailPage.tsx'));
const MatchingDashboard = React.lazy(() => import('../pages/MatchingDashboard.tsx'));
const MatchDetailPage = React.lazy(() => import('../pages/MatchDetailPage.tsx'));
const MatchNegotiationPage = React.lazy(() => import('../pages/MatchNegotiationPage.tsx'));
const MatchesMapView = React.lazy(() => import('../pages/MatchesMapView.tsx'));
const DiscoveryPage = React.lazy(() => import('../pages/DiscoveryPage.tsx'));
const CommunityNewsPage = React.lazy(() => import('../pages/CommunityNewsPage.tsx'));
const CommunityImpactPage = React.lazy(() => import('../pages/CommunityImpactPage.tsx'));
const CommunityStoriesPage = React.lazy(() => import('../pages/CommunityStoriesPage.tsx'));
const CommunityEventsPage = React.lazy(() => import('../pages/CommunityEventsPage.tsx'));
/**
* Wrapper component for admin pages that provides AdminLayout
*/
const AdminPageWrapper = ({
children,
title,
breadcrumbs,
}: {
children: React.ReactNode;
title?: string;
breadcrumbs?: Array<{ label: string; href?: string }>;
}) => (
<AdminLayout title={title} breadcrumbs={breadcrumbs}>
{children}
</AdminLayout>
);
const AppRoutes = () => {
const location = useLocation();
const { isAddOrgWizardOpen, closeAddOrgWizard } = useUI();
const pagesWithoutChatbot = [
'/organization',
'/about',
'/contact',
'/privacy',
'/admin',
'/dashboard',
'/heritage',
'/resources',
'/matching',
'/login',
'/signup',
];
return (
<div className="relative min-h-screen">
<AnimatePresence mode="wait">
<motion.div
key={location.pathname}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.25 }}
>
<Suspense
fallback={
<div className="flex h-screen w-full items-center justify-center bg-background">
<Spinner className="h-8 w-8 text-primary" />
</div>
}
>
<Routes>
<Route path="/" element={<LandingPage />} />
<Route path="/map" element={<MapView />} />
<Route path="/discovery" element={<DiscoveryPage />} />
<Route path="/organization/:id" element={<OrganizationPage />} />
<Route
path="/organization/:id/dashboard"
element={
<ProtectedRoute requiredRole="user">
<OrganizationDashboardPage />
</ProtectedRoute>
}
/>
<Route path="/about" element={<AboutPage />} />
<Route path="/contact" element={<ContactPage />} />
<Route path="/privacy" element={<PrivacyPage />} />
{/* Admin Routes */}
<Route
path="/admin"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper title="Dashboard">
<AdminDashboard />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/organizations"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Organizations"
breadcrumbs={[{ label: 'Admin', href: '/admin' }, { label: 'Organizations' }]}
>
<AdminOrganizationsPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/organizations/new"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Create Organization"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Organizations', href: '/admin/organizations' },
{ label: 'Create' },
]}
>
<AdminOrganizationEditPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/organizations/:id/edit"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Edit Organization"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Organizations', href: '/admin/organizations' },
{ label: 'Edit' },
]}
>
<AdminOrganizationEditPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/organizations/verification"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Verification Queue"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Organizations', href: '/admin/organizations' },
{ label: 'Verification Queue' },
]}
>
<AdminVerificationQueuePage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/analytics/organizations"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Organization Analytics"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Analytics', href: '/admin/analytics' },
{ label: 'Organizations' },
]}
>
<AdminOrganizationsAnalyticsPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/settings/maintenance"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Maintenance"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Settings', href: '/admin/settings' },
{ label: 'Maintenance' },
]}
>
<AdminSettingsMaintenancePage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/users"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Users"
breadcrumbs={[{ label: 'Admin', href: '/admin' }, { label: 'Users' }]}
>
<UsersListPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/users/:id"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Edit User"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Users', href: '/admin/users' },
{ label: 'Edit User' },
]}
>
<UserEditPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/content/pages"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Static Pages"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Content', href: '/admin/content' },
{ label: 'Static Pages' },
]}
>
<ContentPagesPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/content/pages/:id"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Edit Page"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Content', href: '/admin/content' },
{ label: 'Pages', href: '/admin/content/pages' },
{ label: 'Edit Page' },
]}
>
<ContentPageEditPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/content/announcements"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Announcements"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Content', href: '/admin/content' },
{ label: 'Announcements' },
]}
>
<AnnouncementsPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/content/media"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Media Library"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Content', href: '/admin/content' },
{ label: 'Media Library' },
]}
>
<MediaLibraryPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/localization/ui"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="UI Translations"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Localization', href: '/admin/localization' },
{ label: 'UI Translations' },
]}
>
<LocalizationUIPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/admin/localization/data"
element={
<ProtectedRoute requiredRole="admin">
<AdminPageWrapper
title="Data Translations"
breadcrumbs={[
{ label: 'Admin', href: '/admin' },
{ label: 'Localization', href: '/admin/localization' },
{ label: 'Data Translations' },
]}
>
<LocalizationDataPage />
</AdminPageWrapper>
</ProtectedRoute>
}
/>
<Route
path="/dashboard"
element={
<ProtectedRoute requiredRole="user">
<DashboardPage />
</ProtectedRoute>
}
/>
<Route
path="/analytics"
element={
<ProtectedRoute requiredRole="user">
<AnalyticsDashboard />
</ProtectedRoute>
}
/>
<Route
path="/analytics/impact"
element={
<ProtectedRoute requiredRole="user">
<ImpactMetrics />
</ProtectedRoute>
}
/>
<Route
path="/analytics/supply-demand"
element={
<ProtectedRoute requiredRole="user">
<SupplyDemandAnalysis />
</ProtectedRoute>
}
/>
<Route
path="/organizations"
element={
<ProtectedRoute requiredRole="user">
<OrganizationsListPage />
</ProtectedRoute>
}
/>
<Route
path="/organizations/new"
element={
<ProtectedRoute requiredRole="user">
<OrganizationEditPage />
</ProtectedRoute>
}
/>
<Route
path="/organizations/:id/edit"
element={
<ProtectedRoute requiredRole="user">
<OrganizationEditPage />
</ProtectedRoute>
}
/>
<Route path="/heritage" element={<HeritagePage />} />
<Route path="/heritage/buildings/:id" element={<HeritageBuildingPage />} />
<Route
path="/resources"
element={
<ProtectedRoute requiredRole="user">
<ResourceFlowsPage />
</ProtectedRoute>
}
/>
<Route
path="/resources/:id"
element={
<ProtectedRoute requiredRole="user">
<ResourceFlowDetailPage />
</ProtectedRoute>
}
/>
<Route
path="/matching"
element={
<ProtectedRoute requiredRole="user">
<MatchingDashboard />
</ProtectedRoute>
}
/>
<Route
path="/matching/:id"
element={
<ProtectedRoute requiredRole="user">
<MatchDetailPage />
</ProtectedRoute>
}
/>
<Route
path="/matching/:id/negotiate"
element={
<ProtectedRoute requiredRole="user">
<MatchNegotiationPage />
</ProtectedRoute>
}
/>
<Route
path="/matching/map"
element={
<ProtectedRoute requiredRole="user">
<MatchesMapView />
</ProtectedRoute>
}
/>
<Route path="/community/news" element={<CommunityNewsPage />} />
<Route path="/community/impact" element={<CommunityImpactPage />} />
<Route path="/community/stories" element={<CommunityStoriesPage />} />
<Route path="/community/events" element={<CommunityEventsPage />} />
<Route path="/login" element={<LoginPage />} />
<Route path="/signup" element={<SignupPage />} />
</Routes>
</Suspense>
</motion.div>
</AnimatePresence>
{!pagesWithoutChatbot.some((page) => location.pathname.startsWith(page)) && (
<div className="fixed bottom-4 right-4 z-40 md:bottom-6 md:right-6">
<Chatbot />
</div>
)}
<AddOrganizationWizard isOpen={isAddOrgWizardOpen} onClose={closeAddOrgWizard} />
</div>
);
};
const AppRouter = () => (
<Router>
<NavigationProvider>
<AppRoutes />
</NavigationProvider>
</Router>
);
export default AppRouter;