tahamajs/IE / Projects /front /src /components /admin /AdminOverview.tsx
tahamajs's picture
download
raw
6.56 kB
// src/components/admin/AdminOverview.tsx
import { useState, useEffect } from "react";
import { Activity, Users, FileText, MessageSquare, Shield, Clock, Cpu, Server, Layers } from "lucide-react";
import api from "@/lib/api";
interface AdminOverviewProps {
stats: any;
activities: any[];
loading: boolean;
}
export function AdminOverview({ activities, loading }: AdminOverviewProps) {
const [sysInfo, setSysInfo] = useState<any>(null);
const [sysLoading, setSysLoading] = useState(true);
useEffect(() => {
const fetchSysInfo = async () => {
try {
const res = await api.get("/admin/system/info");
setSysInfo(res.data);
} catch (err) {
console.error("Failed to fetch system info", err);
} finally {
setSysLoading(false);
}
};
fetchSysInfo();
const interval = setInterval(fetchSysInfo, 20000);
return () => clearInterval(interval);
}, []);
if (loading) {
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div className="h-80 bg-white/40 dark:bg-gray-900/40 border dark:border-gray-800 rounded-2xl animate-pulse" />
<div className="h-80 bg-white/40 dark:bg-gray-900/40 border dark:border-gray-800 rounded-2xl animate-pulse" />
</div>
);
}
const getEntityIcon = (type?: string) => {
const norm = type?.toLowerCase() || "";
if (norm === "user" || norm.includes("register")) {
return <Users className="w-4 h-4 text-blue-500" />;
}
if (norm === "article" || norm.includes("publish")) {
return <FileText className="w-4 h-4 text-emerald-500" />;
}
return <MessageSquare className="w-4 h-4 text-indigo-500" />;
};
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
{/* Recent Activity Timeline */}
<div className="bg-white/60 dark:bg-gray-900/60 backdrop-blur-md border border-gray-200/50 dark:border-gray-800/50 rounded-2xl p-6 shadow-xl relative overflow-hidden">
<div className="absolute top-0 right-0 w-24 h-24 bg-primary/5 rounded-full blur-2xl" />
<h2 className="text-lg font-semibold flex items-center gap-2 mb-4">
<Activity className="w-5 h-5 text-primary" />
Audit / Recent Activity
</h2>
<div className="relative border-l border-gray-200 dark:border-gray-800 ml-3.5 space-y-5">
{activities &&
activities.slice(0, 5).map((activity: any, i: number) => {
const entityType = activity.entityType || activity.type || "";
return (
<div key={i} className="relative pl-6">
{/* Timeline node */}
<div className="absolute -left-3.5 top-0.5 w-7 h-7 rounded-full bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-850 flex items-center justify-center shadow-md">
{getEntityIcon(entityType)}
</div>
<div>
<p className="text-sm font-medium text-gray-800 dark:text-gray-200">
{activity.description}
</p>
<span className="text-[10px] text-gray-400 font-semibold flex items-center gap-1 mt-0.5">
<Clock className="w-3 h-3" />
{new Date(activity.timestamp).toLocaleString()}
</span>
</div>
</div>
);
})}
{(!activities || activities.length === 0) && (
<div className="text-center text-gray-500 py-8 border-l border-transparent ml-[-14px]">
No recent administrative actions
</div>
)}
</div>
</div>
{/* Live System & JVM Info */}
<div className="bg-white/60 dark:bg-gray-900/60 backdrop-blur-md border border-gray-200/50 dark:border-gray-800/50 rounded-2xl p-6 shadow-xl relative overflow-hidden flex flex-col justify-between">
<div className="absolute bottom-0 right-0 w-24 h-24 bg-indigo-500/5 rounded-full blur-2xl" />
<div>
<h2 className="text-lg font-semibold flex items-center gap-2 mb-1">
<Cpu className="w-5 h-5 text-violet-500" />
System Properties
</h2>
<p className="text-xs text-gray-500 dark:text-gray-400 mb-4">JVM environment & OS statistics</p>
</div>
{sysLoading ? (
<div className="flex-1 flex items-center justify-center py-8">
<div className="w-6 h-6 border-2 border-primary border-t-transparent rounded-full animate-spin" />
</div>
) : sysInfo ? (
<div className="space-y-2.5 flex-1 justify-center flex flex-col">
<div className="flex justify-between items-center py-2 border-b border-gray-100 dark:border-gray-800/60 text-sm">
<span className="text-gray-500 font-medium flex items-center gap-1.5"><Layers className="w-4 h-4" /> Java Version</span>
<span className="font-semibold text-gray-700 dark:text-gray-300">{sysInfo.javaVersion || "17"}</span>
</div>
<div className="flex justify-between items-center py-2 border-b border-gray-100 dark:border-gray-800/60 text-sm">
<span className="text-gray-500 font-medium flex items-center gap-1.5"><Server className="w-4 h-4" /> OS Platform</span>
<span className="font-semibold text-gray-700 dark:text-gray-300 truncate max-w-[200px]" title={sysInfo.osName}>{sysInfo.osName || "Linux"}</span>
</div>
<div className="flex justify-between items-center py-2 border-b border-gray-100 dark:border-gray-800/60 text-sm">
<span className="text-gray-500 font-medium flex items-center gap-1.5"><Cpu className="w-4 h-4" /> CPU Cores</span>
<span className="font-semibold text-gray-700 dark:text-gray-300">{sysInfo.availableProcessors || "8"}</span>
</div>
<div className="flex justify-between items-center py-2 text-sm">
<span className="text-gray-500 font-medium flex items-center gap-1.5"><Shield className="w-4 h-4" /> Engine Uptime</span>
<span className="font-semibold text-gray-750 dark:text-gray-250 bg-gray-100 dark:bg-gray-800/70 px-2 py-0.5 rounded text-xs">{sysInfo.uptime || "N/A"}</span>
</div>
</div>
) : (
<div className="flex-1 flex items-center justify-center text-gray-400 text-sm">
Failed to load server environment details
</div>
)}
</div>
</div>
);
}

Xet Storage Details

Size:
6.56 kB
·
Xet hash:
f77a9c60a8f749a6b36a45ed29e73e6d78a2ce207e59cd76bd40563d855ccc0d

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.