Magnus Smari Smarason 7c3d65dadf
Some checks failed
Build, Lint, and Deploy Arctic Species Portal / test-and-build (push) Failing after 1m0s
Build, Lint, and Deploy Arctic Species Portal / deploy (push) Has been skipped
Fixed CRUD operations for CITES listings, common names, and IUCN assessments. Added admin routes and authentication context. Updated UI components and added new pages for admin functionalities.
2025-05-17 20:58:29 +00:00

127 lines
4.9 KiB
TypeScript

import { useState, useEffect } from 'react';
import { AdminLayout } from '@/components/layout/AdminLayout';
import {
Card,
CardContent,
// CardDescription, // Not used in StatsCard, can be removed if not used elsewhere
CardHeader,
CardTitle,
} from '@/components/ui/card';
import { BarChart, Layers, FileCheck, GitBranch } from 'lucide-react';
import { supabase } from '@/lib/supabase'; // Import Supabase client
import { speciesApi } from '@/services/adminApi'; // Import speciesApi
interface StatsCardProps {
title: string;
value: number | string;
description: string;
icon: React.ReactNode;
}
export default function AdminDashboard() {
const [stats, setStats] = useState({
totalSpecies: 0,
totalTradeRecords: 0,
totalIucnAssessments: 0,
totalCitesListings: 0,
});
const [loadingStats, setLoadingStats] = useState(true);
useEffect(() => {
const fetchStats = async () => {
console.log('[Dashboard] Fetching stats...');
setLoadingStats(true);
try {
// Using Promise.all to fetch all counts concurrently
const [
speciesRes,
tradeRecordsRes,
iucnAssessmentsRes,
citesListingsRes,
] = await Promise.all([
speciesApi.getAll(1, 1), // Fetches total count for species from speciesApi
supabase.from('cites_trade_records').select('*', { count: 'exact', head: true }), // Corrected table name
supabase.from('iucn_assessments').select('*', { count: 'exact', head: true }),
supabase.from('cites_listings').select('*', { count: 'exact', head: true }),
]);
// Log errors if any, but still try to set counts for successful fetches
// speciesApi.getAll() throws on error, so speciesRes won't have an .error property here if successful.
// Errors from speciesApi.getAll() will be caught by the main try...catch block.
if (tradeRecordsRes.error) console.error('[Dashboard] Error fetching CITES trade records count:', tradeRecordsRes.error);
if (iucnAssessmentsRes.error) console.error('[Dashboard] Error fetching IUCN assessments count:', iucnAssessmentsRes.error);
if (citesListingsRes.error) console.error('[Dashboard] Error fetching CITES listings count:', citesListingsRes.error);
setStats({
totalSpecies: speciesRes.count || 0, // speciesRes.count is available if speciesApi.getAll() succeeded
totalTradeRecords: tradeRecordsRes.count || 0,
totalIucnAssessments: iucnAssessmentsRes.count || 0,
totalCitesListings: citesListingsRes.count || 0,
});
} catch (error) {
console.error('[Dashboard] Error in fetchStats Promise.all:', error);
// In case of a major error in Promise.all itself, stats will remain 0
} finally {
setLoadingStats(false);
console.log('[Dashboard] Finished fetching stats. Current stats:', stats); // Log current stats after fetch
}
};
fetchStats();
}, []); // Empty dependency array ensures this runs once on mount
return (
<AdminLayout>
<div className="mb-6">
<h1 className="text-3xl font-bold">Admin Dashboard</h1>
<p className="text-muted-foreground">Manage your Arctic species database</p>
</div>
<div className="grid gap-6 md:grid-cols-2 lg:grid-cols-4">
<StatsCard
title="Total Species"
value={loadingStats ? 'Loading...' : stats.totalSpecies}
description="Species in database"
icon={<Layers className="h-6 w-6 text-blue-500" />}
/>
<StatsCard
title="CITES Trade Records"
value={loadingStats ? 'Loading...' : stats.totalTradeRecords}
description="Trade records tracked"
icon={<BarChart className="h-6 w-6 text-green-500" />}
/>
<StatsCard
title="IUCN Assessments"
value={loadingStats ? 'Loading...' : stats.totalIucnAssessments}
description="Conservation status assessments"
icon={<FileCheck className="h-6 w-6 text-red-500" />}
/>
<StatsCard
title="CITES Listings"
value={loadingStats ? 'Loading...' : stats.totalCitesListings}
description="CITES appendix listings"
icon={<GitBranch className="h-6 w-6 text-purple-500" />}
/>
</div>
{/* TODO: Add loading indicator for the whole stats section if loadingStats is true */}
{/* Recent activity, quick links or other dashboard elements */}
</AdminLayout>
);
}
function StatsCard({ title, value, description, icon }: StatsCardProps) {
return (
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">{title}</CardTitle>
{icon}
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">{value}</div>
<p className="text-xs text-muted-foreground">{description}</p>
</CardContent>
</Card>
);
}