DashboardStats.tsx 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import { useQuery } from 'react-query';
  2. import {
  3. Users,
  4. Code,
  5. Activity,
  6. Key,
  7. } from 'lucide-react';
  8. import apiService from '@/services/api';
  9. import type { DashboardStats } from '@/types';
  10. const StatCard = ({ title, value, icon: Icon, change, changeType }: any) => (
  11. <div className="bg-white dark:bg-gray-800 rounded-xl shadow-sm border dark:border-gray-700 p-6">
  12. <div className="flex items-center">
  13. <div className="flex-shrink-0">
  14. <Icon className="h-8 w-8 text-primary-600 dark:text-primary-400" />
  15. </div>
  16. <div className="ml-5 w-0 flex-1">
  17. <dl>
  18. <dt className="text-sm font-medium text-gray-500 dark:text-gray-400 truncate">{title}</dt>
  19. <dd className="flex items-baseline">
  20. <div className="text-2xl font-semibold text-gray-900 dark:text-gray-100">{value}</div>
  21. {change && (
  22. <div
  23. className={`ml-2 flex items-baseline text-sm font-medium ${
  24. changeType === 'increase' ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400'
  25. }`}
  26. >
  27. {changeType === 'increase' ? '↑' : '↓'} {change}
  28. </div>
  29. )}
  30. </dd>
  31. </dl>
  32. </div>
  33. </div>
  34. </div>
  35. );
  36. export default function DashboardStatsComponent() {
  37. const { data: stats, isLoading } = useQuery<DashboardStats>(
  38. 'dashboard-stats',
  39. () => apiService.getDashboardStats(),
  40. {
  41. refetchInterval: 30000, // Refetch every 30 seconds
  42. }
  43. );
  44. if (isLoading) {
  45. return (
  46. <div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
  47. {[...Array(4)].map((_, i) => (
  48. <div key={i} className="animate-pulse">
  49. <div className="bg-gray-200 dark:bg-gray-700 rounded-xl h-32"></div>
  50. </div>
  51. ))}
  52. </div>
  53. );
  54. }
  55. return (
  56. <div className="grid grid-cols-1 gap-5 sm:grid-cols-2 lg:grid-cols-4">
  57. <StatCard
  58. title="Total Users"
  59. value={stats?.total_users || 0}
  60. icon={Users}
  61. />
  62. <StatCard
  63. title="Applications"
  64. value={stats?.total_applications || 0}
  65. icon={Code}
  66. />
  67. <StatCard
  68. title="Deployments"
  69. value={stats?.total_deployments || 0}
  70. icon={Activity}
  71. />
  72. <StatCard
  73. title="API Keys"
  74. value={stats?.total_api_keys || 0}
  75. icon={Key}
  76. />
  77. </div>
  78. );
  79. }