fedi-feed-router/resources/js/pages/Dashboard.tsx

191 lines
No EOL
7.1 KiB
TypeScript

import React from 'react';
import { useQuery } from '@tanstack/react-query';
import { FileText, Rss, Users, Route, TrendingUp, Clock, CheckCircle } from 'lucide-react';
import { apiClient } from '../lib/api';
const Dashboard: React.FC = () => {
const { data: stats, isLoading, error } = useQuery({
queryKey: ['dashboard-stats'],
queryFn: () => apiClient.getDashboardStats(),
});
if (isLoading) {
return (
<div className="p-6">
<div className="animate-pulse">
<div className="h-8 bg-gray-200 rounded w-1/4 mb-6"></div>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
{[...Array(4)].map((_, i) => (
<div key={i} className="bg-white p-6 rounded-lg shadow">
<div className="h-4 bg-gray-200 rounded w-3/4 mb-2"></div>
<div className="h-8 bg-gray-200 rounded w-1/2"></div>
</div>
))}
</div>
</div>
</div>
);
}
if (error) {
return (
<div className="p-6">
<div className="bg-red-50 border border-red-200 rounded-md p-4">
<p className="text-red-600">Failed to load dashboard data</p>
</div>
</div>
);
}
const articleStats = stats?.article_stats;
const systemStats = stats?.system_stats;
return (
<div className="p-6">
<div className="mb-8">
<h1 className="text-2xl font-bold text-gray-900">Dashboard</h1>
<p className="mt-1 text-sm text-gray-500">
Overview of your feed management system
</p>
</div>
{/* Article Statistics */}
<div className="mb-8">
<h2 className="text-lg font-semibold text-gray-900 mb-4">Article Statistics</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<FileText className="h-8 w-8 text-blue-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Articles Today</p>
<p className="text-2xl font-semibold text-gray-900">
{articleStats?.total_today || 0}
</p>
</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<Clock className="h-8 w-8 text-yellow-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Articles This Week</p>
<p className="text-2xl font-semibold text-gray-900">
{articleStats?.total_week || 0}
</p>
</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<CheckCircle className="h-8 w-8 text-green-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Approved Today</p>
<p className="text-2xl font-semibold text-gray-900">
{articleStats?.approved_today || 0}
</p>
</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<TrendingUp className="h-8 w-8 text-purple-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Approval Rate</p>
<p className="text-2xl font-semibold text-gray-900">
{articleStats?.approval_percentage_today?.toFixed(1) || 0}%
</p>
</div>
</div>
</div>
</div>
</div>
{/* System Statistics */}
<div>
<h2 className="text-lg font-semibold text-gray-900 mb-4">System Overview</h2>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<Rss className="h-8 w-8 text-orange-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Active Feeds</p>
<p className="text-2xl font-semibold text-gray-900">
{systemStats?.active_feeds || 0}
<span className="text-sm font-normal text-gray-500">
/{systemStats?.total_feeds || 0}
</span>
</p>
</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<Users className="h-8 w-8 text-indigo-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Platform Accounts</p>
<p className="text-2xl font-semibold text-gray-900">
{systemStats?.active_platform_accounts || 0}
<span className="text-sm font-normal text-gray-500">
/{systemStats?.total_platform_accounts || 0}
</span>
</p>
</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<FileText className="h-8 w-8 text-cyan-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Platform Channels</p>
<p className="text-2xl font-semibold text-gray-900">
{systemStats?.active_platform_channels || 0}
<span className="text-sm font-normal text-gray-500">
/{systemStats?.total_platform_channels || 0}
</span>
</p>
</div>
</div>
</div>
<div className="bg-white p-6 rounded-lg shadow">
<div className="flex items-center">
<div className="flex-shrink-0">
<Route className="h-8 w-8 text-pink-500" />
</div>
<div className="ml-4">
<p className="text-sm font-medium text-gray-500">Active Routes</p>
<p className="text-2xl font-semibold text-gray-900">
{systemStats?.active_routes || 0}
<span className="text-sm font-normal text-gray-500">
/{systemStats?.total_routes || 0}
</span>
</p>
</div>
</div>
</div>
</div>
</div>
</div>
);
};
export default Dashboard;