Files
digicraft-fe/pages/AnalyticsPage.tsx
Fahri Can Seçer 6e3bee17ef
Some checks failed
Deploy Frontend / deploy (push) Has been cancelled
main
2026-02-05 01:34:13 +03:00

280 lines
16 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import axios from 'axios';
import { useTranslation } from 'react-i18next';
import {
Activity, Users, DollarSign, Server, Cpu,
ArrowUpRight, ArrowDownRight, RefreshCw, Layers
} from 'lucide-react';
import Layout from '../components/Layout';
import { useAuth } from '../AuthContext';
// Simple simulated chart component
const MicroChart = ({ color, data }: { color: string, data: number[] }) => (
<div className="flex items-end gap-1 h-12 w-full mt-2 opacity-50">
{data.map((val, i) => (
<div
key={i}
style={{
height: `${val}%`,
backgroundColor: color
}}
className="flex-1 rounded-sm transition-all duration-500"
/>
))}
</div>
);
export default function AnalyticsPage() {
const { t } = useTranslation();
const { user } = useAuth();
const [stats, setStats] = useState<any>(null);
const [loading, setLoading] = useState(true);
const [refreshKey, setRefreshKey] = useState(0);
// Mock Chart Data
const [chartData] = useState(() => Array.from({ length: 12 }, () => Math.floor(Math.random() * 60) + 20));
useEffect(() => {
const fetchStats = async () => {
try {
const res = await axios.get('/api/admin/analytics');
setStats(res.data);
} catch (err) {
console.error("Failed to load analytics", err);
} finally {
setLoading(false);
}
};
fetchStats();
// Auto-refresh every 30s
const interval = setInterval(fetchStats, 30000);
return () => clearInterval(interval);
}, [refreshKey]);
const formatCurrency = (val: number) => {
return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD' }).format(val);
};
const formatTime = (seconds: number) => {
const h = Math.floor(seconds / 3600);
const m = Math.floor((seconds % 3600) / 60);
return `${h}h ${m}m`;
};
if (loading && !stats) return (
<Layout>
<div className="flex h-[80vh] items-center justify-center">
<RefreshCw className="w-8 h-8 text-stone-300 animate-spin" />
</div>
</Layout>
);
return (
<Layout>
<div className="max-w-7xl mx-auto p-8 relative overflow-hidden min-h-screen">
{/* Background Ambient Glow */}
<div className="absolute top-0 right-0 w-[500px] h-[500px] bg-purple-500/5 rounded-full blur-[120px] -z-10" />
<div className="absolute bottom-0 left-0 w-[500px] h-[500px] bg-blue-500/5 rounded-full blur-[120px] -z-10" />
{/* Header Section */}
<div className="flex justify-between items-end mb-10">
<div>
<div className="flex items-center gap-3 mb-2">
<div className="bg-stone-900 text-white px-2 py-0.5 rounded text-[10px] font-black uppercase tracking-widest">
v{stats.system.version}
</div>
<span className="flex items-center gap-1.5 text-green-600 text-[10px] font-bold uppercase tracking-widest">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-green-500"></span>
</span>
System Operational
</span>
</div>
<h1 className="text-4xl font-black text-stone-900 tracking-tighter">Engine Analytics</h1>
<p className="text-stone-500 font-medium">Mission Control & System Health</p>
</div>
<button
onClick={() => setRefreshKey(p => p + 1)}
className="flex items-center gap-2 px-4 py-2 bg-white/50 hover:bg-white border border-stone-200/50 rounded-xl transition-all shadow-sm backdrop-blur-sm text-sm font-bold text-stone-600 hover:text-stone-900"
>
<RefreshCw className="w-4 h-4" />
Refresh Data
</button>
</div>
{/* KPI Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-10">
{/* KPI 1: Users */}
<div className="bg-white/60 backdrop-blur-xl border border-white/40 shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-3xl p-6 relative overflow-hidden group">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-indigo-50 rounded-2xl text-indigo-600 group-hover:scale-110 transition-transform">
<Users className="w-6 h-6" />
</div>
<span className="flex items-center text-xs font-bold text-green-600 bg-green-50 px-2 py-1 rounded-lg">
+{stats.users.new24h} <ArrowUpRight className="w-3 h-3 ml-1" />
</span>
</div>
<div>
<p className="text-sm font-bold text-stone-400 uppercase tracking-widest mb-1">Total Users</p>
<h3 className="text-3xl font-black text-stone-900 tracking-tight">{stats.users.total}</h3>
</div>
<MicroChart color="#6366f1" data={chartData} />
</div>
{/* KPI 2: Projects */}
<div className="bg-white/60 backdrop-blur-xl border border-white/40 shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-3xl p-6 relative overflow-hidden group">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-purple-50 rounded-2xl text-purple-600 group-hover:scale-110 transition-transform">
<Layers className="w-6 h-6" />
</div>
<span className="flex items-center text-xs font-bold text-purple-600 bg-purple-50 px-2 py-1 rounded-lg">
{stats.projects.completionRate}% Done
</span>
</div>
<div>
<p className="text-sm font-bold text-stone-400 uppercase tracking-widest mb-1">Total Projects</p>
<h3 className="text-3xl font-black text-stone-900 tracking-tight">{stats.projects.total}</h3>
</div>
<MicroChart color="#a855f7" data={[...chartData].reverse()} />
</div>
{/* KPI 3: Liability */}
<div className="bg-white/60 backdrop-blur-xl border border-white/40 shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-3xl p-6 relative overflow-hidden group">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-amber-50 rounded-2xl text-amber-600 group-hover:scale-110 transition-transform">
<DollarSign className="w-6 h-6" />
</div>
</div>
<div>
<p className="text-sm font-bold text-stone-400 uppercase tracking-widest mb-1">Credit Liability</p>
<h3 className="text-3xl font-black text-stone-900 tracking-tight">{stats.financials.creditsLiability.toLocaleString()}</h3>
<p className="text-xs text-stone-400 mt-1 font-mono">Value: {formatCurrency(stats.financials.estimatedValue)}</p>
</div>
<div className="absolute -right-6 -bottom-6 opacity-5">
<DollarSign className="w-40 h-40" />
</div>
</div>
{/* KPI 4: System Health */}
<div className="bg-stone-900 backdrop-blur-xl border border-stone-800 shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-3xl p-6 relative overflow-hidden text-white group">
<div className="flex justify-between items-start mb-4">
<div className="p-3 bg-white/10 rounded-2xl text-white group-hover:scale-110 transition-transform">
<Server className="w-6 h-6" />
</div>
<span className="flex items-center text-xs font-bold text-green-400 bg-green-900/30 px-2 py-1 rounded-lg border border-green-800">
{stats.system.cpuLoad}% Load
</span>
</div>
<div>
<p className="text-sm font-bold text-stone-400 uppercase tracking-widest mb-1">Uptime</p>
<h3 className="text-3xl font-black tracking-tight">{formatTime(stats.system.uptime)}</h3>
<p className="text-xs text-stone-500 mt-1 font-mono">Mem: {stats.system.memory}MB</p>
</div>
<div className="absolute top-0 right-0 w-full h-full bg-[url('https://grainy-gradients.vercel.app/noise.svg')] opacity-10 mix-blend-overlay"></div>
</div>
</div>
{/* Detailed Sections */}
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Live Feed */}
<div className="lg:col-span-2 bg-white border border-stone-100 shadow-sm rounded-3xl p-8">
<div className="flex items-center gap-3 mb-6">
<Activity className="w-5 h-5 text-stone-400" />
<h3 className="text-lg font-black text-stone-900 tracking-tight">Live Activity Feed</h3>
</div>
<div className="space-y-4">
{stats.activityLog.map((log: any) => (
<div key={log.id} className="flex items-center justify-between p-4 rounded-2xl bg-stone-50 border border-stone-100 hover:bg-white hover:shadow-md transition-all group">
<div className="flex items-center gap-4">
<div className="w-10 h-10 rounded-full bg-blue-100 flex items-center justify-center text-blue-600 font-bold text-xs">
{log.user.substring(0, 2).toUpperCase()}
</div>
<div>
<p className="text-sm font-bold text-stone-900">{log.action.replace('_', ' ')}</p>
<p className="text-xs text-stone-500">{log.user}</p>
</div>
</div>
<div className="text-right">
<p className="text-xs font-mono font-bold text-stone-400">{new Date(log.timestamp).toLocaleTimeString()}</p>
<p className="text-[10px] font-bold text-stone-300 uppercase tracking-widest">{log.details}</p>
</div>
</div>
))}
{stats.activityLog.length === 0 && (
<div className="text-center py-10 text-stone-400 text-sm">No recent activity found.</div>
)}
</div>
</div>
{/* System Resources */}
<div className="bg-white border border-stone-100 shadow-sm rounded-3xl p-8">
<div className="flex items-center gap-3 mb-6">
<Cpu className="w-5 h-5 text-stone-400" />
<h3 className="text-lg font-black text-stone-900 tracking-tight">Resource Monitor</h3>
</div>
<div className="space-y-6">
<div>
<div className="flex justify-between text-xs font-bold text-stone-500 mb-2 uppercase tracking-widest">
<span>CPU Usage</span>
<span>{stats.system.cpuLoad}%</span>
</div>
<div className="h-2 w-full bg-stone-100 rounded-full overflow-hidden">
<div
className="h-full bg-stone-900 rounded-full transition-all duration-1000 ease-out"
style={{ width: `${stats.system.cpuLoad}%` }}
/>
</div>
</div>
<div>
<div className="flex justify-between text-xs font-bold text-stone-500 mb-2 uppercase tracking-widest">
<span>Memory Allocation</span>
<span>{stats.system.memory} MB</span>
</div>
<div className="h-2 w-full bg-stone-100 rounded-full overflow-hidden">
<div
className="h-full bg-purple-500 rounded-full transition-all duration-1000 ease-out"
style={{ width: `${Math.min((stats.system.memory / 512) * 100, 100)}%` }}
/>
</div>
</div>
<div>
<div className="flex justify-between text-xs font-bold text-stone-500 mb-2 uppercase tracking-widest">
<span>Storage (Projects)</span>
<span>{stats.projects.total} Items</span>
</div>
<div className="h-2 w-full bg-stone-100 rounded-full overflow-hidden">
<div
className="h-full bg-blue-500 rounded-full transition-all duration-1000 ease-out"
style={{ width: '45%' }}
/>
</div>
</div>
<div className="mt-8 p-4 bg-amber-50 rounded-2xl border border-amber-100">
<h4 className="flex items-center gap-2 text-xs font-black text-amber-700 uppercase tracking-widest mb-1">
<Activity className="w-3 h-3" /> System Status
</h4>
<p className="text-xs text-amber-600/80 leading-relaxed">
All services operate within nominal parameters. No critical warnings detected in the last 24 hours.
</p>
</div>
</div>
</div>
</div>
</div>
</Layout>
);
}