mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 14:38:12 +00:00
126 lines
4.1 KiB
TypeScript
126 lines
4.1 KiB
TypeScript
import { Card, CardContent } from "@/shared/common/ui/card";
|
|
import {
|
|
Activity,
|
|
CheckCircle,
|
|
XCircle,
|
|
Clock,
|
|
TrendingUp,
|
|
} from "lucide-react";
|
|
import { cn } from "@/shared/lib/utils";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
interface ActivityStatsProps {
|
|
totalActivities: number;
|
|
successRate: number;
|
|
avgDailyActivities: number;
|
|
uniqueUsers: number;
|
|
topActions: { action: string; count: number }[];
|
|
}
|
|
|
|
export function ActivityStats({
|
|
totalActivities,
|
|
successRate,
|
|
avgDailyActivities,
|
|
uniqueUsers,
|
|
topActions,
|
|
}: ActivityStatsProps) {
|
|
const border = "border-gray-200 dark:border-gray-800";
|
|
const surface = "bg-white dark:bg-gray-900";
|
|
const textStrong = "text-gray-900 dark:text-gray-100";
|
|
const textMuted = "text-gray-600 dark:text-gray-300";
|
|
const textSubtle = "text-gray-500 dark:text-gray-400";
|
|
const textSubtler = "text-gray-400 dark:text-gray-500";
|
|
const iconBgLight = "bg-gray-100 dark:bg-gray-800";
|
|
const { t } = useTranslation();
|
|
|
|
const stats = [
|
|
{
|
|
label: t("auditLog.stats.totalActivities"),
|
|
value: totalActivities.toLocaleString(),
|
|
icon: Activity,
|
|
color: "text-blue-600 dark:text-blue-400",
|
|
bgColor: "bg-blue-50 dark:bg-blue-950",
|
|
},
|
|
{
|
|
label: t("auditLog.stats.successRate"),
|
|
value: `${successRate}%`,
|
|
icon: CheckCircle,
|
|
color: "text-green-600 dark:text-green-400",
|
|
bgColor: "bg-green-50 dark:bg-green-950",
|
|
},
|
|
{
|
|
label: t("auditLog.stats.dailyAverage"),
|
|
value: avgDailyActivities.toLocaleString(),
|
|
icon: TrendingUp,
|
|
color: "text-purple-600 dark:text-purple-400",
|
|
bgColor: "bg-purple-50 dark:bg-purple-950",
|
|
},
|
|
{
|
|
label: t("auditLog.stats.uniqueUsers"),
|
|
value: uniqueUsers.toLocaleString(),
|
|
icon: Clock,
|
|
color: "text-orange-600 dark:text-orange-400",
|
|
bgColor: "bg-orange-50 dark:bg-orange-950",
|
|
},
|
|
];
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
{stats.map((stat, index) => (
|
|
<Card key={index} className={cn(border, surface)}>
|
|
<CardContent className="p-6">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<p className={cn("text-sm font-medium", textMuted)}>
|
|
{stat.label}
|
|
</p>
|
|
<p className={cn("text-2xl font-bold mt-1", textStrong)}>
|
|
{stat.value}
|
|
</p>
|
|
</div>
|
|
<div className={cn("p-3 rounded-full", stat.bgColor)}>
|
|
<stat.icon className={cn("h-6 w-6", stat.color)} />
|
|
</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
|
|
<Card className={cn(border, surface)}>
|
|
<CardContent className="p-6">
|
|
<h3 className={cn("text-lg font-semibold mb-4", textStrong)}>
|
|
{t("auditLog.stats.topActions")}
|
|
</h3>
|
|
<div className="space-y-3">
|
|
{topActions.map((action, index) => (
|
|
<div key={index} className="flex items-center justify-between">
|
|
<div className="flex items-center gap-3">
|
|
<div
|
|
className={cn(
|
|
"w-8 h-8 rounded-md flex items-center justify-center",
|
|
iconBgLight,
|
|
)}>
|
|
<span className={cn("text-sm font-medium", textSubtle)}>
|
|
{action.action.charAt(0)}
|
|
</span>
|
|
</div>
|
|
<span className={cn("text-sm font-medium", textStrong)}>
|
|
{t(`activityLogPage.actions.${action.action}`, {
|
|
defaultValue: action.action,
|
|
})}
|
|
</span>
|
|
</div>
|
|
<span className={cn("text-sm font-semibold", textMuted)}>
|
|
{action.count} {t("auditLog.stats.times")}
|
|
</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</div>
|
|
);
|
|
}
|