mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
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
- 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
182 lines
6.5 KiB
TypeScript
182 lines
6.5 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 apiError = error as {
|
|
status?: number;
|
|
data?: { user_role?: string; required_role?: string };
|
|
};
|
|
const isForbidden = apiError?.status === 403;
|
|
const errorData = apiError?.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">
|
|
{t('common.accessDenied')}: {t('common.administratorPrivileges')}
|
|
</p>
|
|
<div className="mt-3 space-y-2">
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('common.currentRole')}{' '}
|
|
<span className="font-mono font-medium text-foreground">
|
|
{userRole || 'unknown'}
|
|
</span>
|
|
</p>
|
|
<p className="text-sm text-muted-foreground">
|
|
{t('common.requiredRole')}{' '}
|
|
<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">{t('common.fixThis')}</p>
|
|
<ol className="text-sm text-muted-foreground list-decimal list-inside space-y-1">
|
|
<li>{t('common.contactAdmin')}</li>
|
|
<li>{t('common.logoutAndLogin')}</li>
|
|
<li>{t('common.contactAdmin')}</li>
|
|
</ol>
|
|
</div>
|
|
)}
|
|
</div>
|
|
<p className="text-sm text-muted-foreground mt-3">{t('common.contactAdminHelp')}</p>
|
|
</div>
|
|
)}
|
|
{!isForbidden && (
|
|
<div className="rounded-lg border border-destructive bg-destructive/10 p-4">
|
|
<p className="text-sm font-medium text-destructive">
|
|
{t('common.errorLoadingDashboard')}: {(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;
|