127 lines
3.8 KiB
TypeScript
127 lines
3.8 KiB
TypeScript
import { useState, useEffect } from "react";
|
|
import {
|
|
Building2,
|
|
CheckCircle2,
|
|
// Users,
|
|
// TrendingUp,
|
|
Package,
|
|
Heart,
|
|
} from "lucide-react";
|
|
import { StatCard } from "./StatCard";
|
|
import type { StatCardData } from "@/types/dashboard";
|
|
import { dashboardService } from "@/services/dashboard-service";
|
|
|
|
export const StatsGrid = () => {
|
|
const [statsData, setStatsData] = useState<StatCardData[]>([]);
|
|
const [isLoading, setIsLoading] = useState<boolean>(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
const fetchStatistics = async () => {
|
|
try {
|
|
setIsLoading(true);
|
|
setError(null);
|
|
const response = await dashboardService.getStatistics();
|
|
const { data } = response;
|
|
|
|
const mappedStats: StatCardData[] = [
|
|
{
|
|
icon: Building2,
|
|
value: data.totalTenants,
|
|
label: "Total Tenants",
|
|
badge: { text: `${data.activeTenants} active`, variant: "green" },
|
|
},
|
|
{
|
|
icon: CheckCircle2,
|
|
value: data.activeTenants,
|
|
label: "Active Tenants",
|
|
badge: {
|
|
text:
|
|
data.totalTenants > 0
|
|
? `${Math.round((data.activeTenants / data.totalTenants) * 100)}% Rate`
|
|
: "0% Rate",
|
|
variant: "green",
|
|
},
|
|
},
|
|
// {
|
|
// icon: Users,
|
|
// value: data.totalUsers,
|
|
// label: "Total Users",
|
|
// badge: { text: "All users", variant: "gray" },
|
|
// },
|
|
// {
|
|
// icon: TrendingUp,
|
|
// value: data.activeSessions,
|
|
// label: "Active Sessions",
|
|
// badge: { text: "Live now", variant: "gray" },
|
|
// },
|
|
{
|
|
icon: Package,
|
|
value: data.registeredModules,
|
|
label: "Registered Modules",
|
|
badge: { text: "Total", variant: "gray" },
|
|
},
|
|
{
|
|
icon: Heart,
|
|
value: data.healthyModules,
|
|
label: "Healthy Modules",
|
|
badge: {
|
|
text:
|
|
data.registeredModules > 0
|
|
? `${Math.round((data.healthyModules / data.registeredModules) * 100)}% Uptime`
|
|
: "0% Uptime",
|
|
variant:
|
|
data.healthyModules === data.registeredModules &&
|
|
data.registeredModules > 0
|
|
? "green"
|
|
: "gray",
|
|
},
|
|
},
|
|
];
|
|
|
|
setStatsData(mappedStats);
|
|
} catch (err) {
|
|
console.error("Failed to fetch dashboard statistics:", err);
|
|
setError("Failed to load statistics. Please try again.");
|
|
} finally {
|
|
setIsLoading(false);
|
|
}
|
|
};
|
|
|
|
fetchStatistics();
|
|
}, []);
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 mb-4 md:mb-6 auto-rows-fr">
|
|
{Array.from({ length: 6 }).map((_, index) => (
|
|
<div
|
|
key={index}
|
|
className="bg-white border border-[rgba(0,0,0,0.08)] rounded-lg p-[17px] flex flex-col gap-3 h-[107px] animate-pulse"
|
|
>
|
|
<div className="h-4 bg-gray-200 rounded w-1/4"></div>
|
|
<div className="h-8 bg-gray-200 rounded w-1/2"></div>
|
|
<div className="h-3 bg-gray-200 rounded w-1/3"></div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error) {
|
|
return (
|
|
<div className="bg-red-50 border border-red-200 rounded-lg p-4 mb-4 md:mb-6">
|
|
<p className="text-red-800 text-sm">{error}</p>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 mb-4 md:mb-6 auto-rows-fr">
|
|
{statsData.map((stat, index) => (
|
|
<StatCard key={index} data={stat} />
|
|
))}
|
|
</div>
|
|
);
|
|
};
|