MIF_E31221222/sigap-website/app/_components/admin/users/user-stats.tsx

93 lines
2.6 KiB
TypeScript

"use client";
import { useQuery } from "@tanstack/react-query";
import { Card, CardContent } from "@/app/_components/ui/card";
import { Users, UserCheck, UserX } from "lucide-react";
import { fetchUsers } from "@/app/(protected)/(admin)/dashboard/user-management/action";
import { User } from "@/src/models/users/users.model";
function calculateUserStats(users: User[]) {
const totalUsers = users.length;
const activeUsers = users.filter(
(user) => !user.banned_until && user.email_confirmed_at
).length;
const inactiveUsers = totalUsers - activeUsers;
return {
totalUsers,
activeUsers,
inactiveUsers,
activePercentage:
totalUsers > 0 ? ((activeUsers / totalUsers) * 100).toFixed(1) : "0.0",
inactivePercentage:
totalUsers > 0 ? ((inactiveUsers / totalUsers) * 100).toFixed(1) : "0.0",
};
}
export function UserStats() {
const { data: users = [], isLoading } = useQuery({
queryKey: ["users"],
queryFn: fetchUsers,
});
const stats = calculateUserStats(users);
if (isLoading) {
return (
<>
{[...Array(3)].map((_, i) => (
<Card key={i} className="bg-background border-border">
<CardContent className="p-6">
<div className="space-y-4 animate-pulse">
<div className="h-5 w-24 bg-muted rounded" />
<div className="h-8 w-16 bg-muted rounded" />
<div className="h-4 w-32 bg-muted rounded" />
</div>
</CardContent>
</Card>
))}
</>
);
}
const cards = [
{
title: "Total Users",
value: stats.totalUsers,
subtitle: "Updated just now",
icon: Users,
},
{
title: "Active Users",
value: stats.activeUsers,
subtitle: `${stats.activePercentage}% of total users`,
icon: UserCheck,
},
{
title: "Inactive Users",
value: stats.inactiveUsers,
subtitle: `${stats.inactivePercentage}% of total users`,
icon: UserX,
},
];
return (
<>
{cards.map((card, index) => (
<Card key={index} className="bg-background border-border">
<CardContent className="p-6">
<div className="flex items-center justify-between mb-4">
<div className="font-medium text-sm text-muted-foreground">
{card.title}
</div>
<card.icon className="h-4 w-4 text-muted-foreground" />
</div>
<div className="text-3xl font-bold mb-2">{card.value}</div>
<div className="text-sm text-muted-foreground">{card.subtitle}</div>
</CardContent>
</Card>
))}
</>
);
}