turash/bugulma/frontend/pages/admin/AdminDashboard.tsx
2025-12-15 10:06:41 +01:00

180 lines
6.6 KiB
TypeScript

import React from 'react';
import { useTranslation } from '@/hooks/useI18n.tsx';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card.tsx';
import DashboardStats from '@/components/admin/DashboardStats.tsx';
import EconomicGraph from '@/components/admin/EconomicGraph.tsx';
import SupplyChainAnalysis from '@/components/admin/SupplyChainAnalysis.tsx';
import { ActivityFeed } from '@/components/admin/ActivityFeed.tsx';
import { useAdminDashboard } from '@/hooks/features/useAdminDashboard.ts';
import { Grid, Stack } from '@/components/ui/layout';
import { Button } from '@/components/ui';
import { useNavigate } from 'react-router-dom';
import { CheckCircle, AlertCircle, Clock, Users } from 'lucide-react';
import { useAuth } from '@/contexts/AuthContext';
const AdminDashboard = () => {
const { t } = useTranslation();
const { stats, recentActivity, quickActions, isLoading, error } = useAdminDashboard();
const { user } = useAuth();
const navigate = useNavigate();
const quickActionButtons = [
{
label: t('adminPage.quickActions.verifyPending'),
icon: <CheckCircle className="h-4 w-4" />,
count: quickActions.pendingVerifications,
onClick: () => navigate('/admin/organizations/verification'),
variant: 'default' as const,
},
{
label: t('adminPage.quickActions.reviewTranslations'),
icon: <AlertCircle className="h-4 w-4" />,
count: quickActions.pendingTranslations,
onClick: () => navigate('/admin/localization/ui'),
variant: 'secondary' as const,
},
{
label: t('adminPage.quickActions.viewAlerts'),
icon: <Clock className="h-4 w-4" />,
count: quickActions.systemAlerts,
onClick: () => navigate('/admin/settings/maintenance'),
variant: 'outline' as const,
},
{
label: t('adminPage.quickActions.help'),
icon: <Users className="h-4 w-4" />,
onClick: () => navigate('/help'),
variant: 'ghost' as const,
},
];
// Show error message if API call failed (likely 403 - not admin)
if (error && !isLoading) {
const isForbidden = (error as any)?.status === 403;
const errorData = (error as any)?.data;
const userRole = errorData?.user_role || user?.role;
const requiredRole = errorData?.required_role || 'admin';
return (
<div className="space-y-4">
{isForbidden && (
<div className="rounded-lg border border-destructive bg-destructive/10 p-4">
<p className="text-sm font-medium text-destructive">
Access Denied: You do not have administrator privileges to view this dashboard.
</p>
<div className="mt-3 space-y-2">
<p className="text-sm text-muted-foreground">
<span className="font-medium">Your current role:</span>{' '}
<span className="font-mono font-medium text-foreground">
{userRole || 'unknown'}
</span>
</p>
<p className="text-sm text-muted-foreground">
<span className="font-medium">Required role:</span>{' '}
<span className="font-mono font-medium text-foreground">{requiredRole}</span>
</p>
{userRole !== 'admin' && (
<div className="mt-3 p-3 bg-muted rounded-md">
<p className="text-sm font-medium mb-1">To fix this:</p>
<ol className="text-sm text-muted-foreground list-decimal list-inside space-y-1">
<li>Your user account in the database needs to have role = 'admin'</li>
<li>You may need to log out and log back in after your role is updated</li>
<li>Contact your database administrator to update your role</li>
</ol>
</div>
)}
</div>
<p className="text-sm text-muted-foreground mt-3">
Please contact your administrator if you believe you should have access.
</p>
</div>
)}
{!isForbidden && (
<div className="rounded-lg border border-destructive bg-destructive/10 p-4">
<p className="text-sm font-medium text-destructive">
Error loading dashboard: {(error as Error)?.message || 'Unknown error'}
</p>
</div>
)}
</div>
);
}
return (
<Stack spacing="2xl">
{/* Key Metrics */}
<DashboardStats stats={stats} isLoading={isLoading} />
{/* Charts Section */}
<Grid cols={{ lg: 5 }} gap="2xl">
<Card className="lg:col-span-3">
<CardHeader>
<CardTitle>{t('adminPage.economicConnections')}</CardTitle>
<p className="text-sm text-muted-foreground">
{t('adminPage.economicConnectionsDesc')}
</p>
</CardHeader>
<CardContent>
<EconomicGraph />
</CardContent>
</Card>
<Card className="lg:col-span-2">
<CardHeader>
<CardTitle>{t('adminPage.supplyDemand')}</CardTitle>
</CardHeader>
<CardContent>
<SupplyChainAnalysis />
</CardContent>
</Card>
</Grid>
{/* Bottom Row: Recent Activity & Quick Actions */}
<Grid cols={{ lg: 3 }} gap="2xl">
<Card className="lg:col-span-2">
<CardHeader>
<CardTitle>{t('adminPage.recentActivity')}</CardTitle>
</CardHeader>
<CardContent>
<ActivityFeed
activities={recentActivity}
isLoading={isLoading}
emptyMessage="No recent activity"
/>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>{t('adminPage.quickActions.title')}</CardTitle>
</CardHeader>
<CardContent>
<Stack spacing="md">
{quickActionButtons.map((action, index) => (
<Button
key={index}
variant={action.variant}
onClick={action.onClick}
className="justify-start"
>
<div className="flex items-center gap-2">
{action.icon}
<span>{action.label}</span>
{action.count && action.count > 0 && (
<span className="ml-auto rounded-full bg-primary px-2 py-0.5 text-xs text-primary-foreground">
{action.count}
</span>
)}
</div>
</Button>
))}
</Stack>
</CardContent>
</Card>
</Grid>
</Stack>
);
};
export default AdminDashboard;