Files

197 lines
12 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { motion } from 'framer-motion';
import DashboardLayout from '@/components/layout/DashboardLayout';
import { api } from '@/lib/api';
export default function AdminDashboard() {
const [dashboard, setDashboard] = useState<any>(null);
const [users, setUsers] = useState<any[]>([]);
const [partners, setPartners] = useState<any[]>([]);
const [logs, setLogs] = useState<any[]>([]);
const [tab, setTab] = useState('dashboard');
const [loading, setLoading] = useState(true);
useEffect(() => {
const params = new URLSearchParams(window.location.search);
const t = params.get('tab');
if (t) setTab(t);
}, []);
useEffect(() => {
(async () => {
setLoading(true);
try {
if (tab === 'dashboard') {
const d = await api.getDashboard();
setDashboard(d);
} else if (tab === 'users') {
const d = await api.getUsers();
setUsers(d.users || []);
} else if (tab === 'partners') {
const d = await api.getPartners();
setPartners(d.partners || []);
} else if (tab === 'logs') {
const d = await api.getAuditLogs();
setLogs(d.logs || []);
}
} catch (e) { console.error(e); }
setLoading(false);
})();
}, [tab]);
const statCards = dashboard ? [
{ icon: '👥', label: 'Total Usuários', value: dashboard.totalUsers || 0, color: 'from-blue-500 to-cyan-400' },
{ icon: '🏢', label: 'Parceiros', value: dashboard.totalPartners || 0, color: 'from-green-500 to-emerald-400' },
{ icon: '🎁', label: 'Benefícios', value: dashboard.totalBenefits || 0, color: 'from-purple-500 to-pink-400' },
{ icon: '📊', label: 'Transações', value: dashboard.totalTransactions || 0, color: 'from-orange-500 to-red-400' },
] : [];
return (
<DashboardLayout>
<div className="space-y-8">
<div className="flex items-center justify-between">
<div>
<h1 className="text-3xl font-bold">Painel <span className="gradient-text">Administrativo</span></h1>
<p className="text-dark-400 mt-1">Gerencie toda a plataforma em um lugar.</p>
</div>
</div>
{/* Tabs */}
<div className="flex gap-2 overflow-x-auto pb-2">
{[
{ key: 'dashboard', label: '📊 Dashboard' },
{ key: 'users', label: '👥 Usuários' },
{ key: 'partners', label: '🏢 Parceiros' },
{ key: 'benefits', label: '🎁 Benefícios' },
{ key: 'plugins', label: '🔌 Plugins' },
{ key: 'logs', label: '📋 Logs' },
].map(t => (
<button key={t.key} onClick={() => setTab(t.key)}
className={`px-4 py-2 rounded-xl text-sm font-medium whitespace-nowrap transition-all ${tab === t.key ? 'bg-brand-600 text-white' : 'glass text-dark-400 hover:text-white hover:bg-white/5'
}`}>
{t.label}
</button>
))}
</div>
{/* Dashboard Tab */}
{tab === 'dashboard' && (
<div className="space-y-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
{loading ? [1, 2, 3, 4].map(i => <div key={i} className="skeleton h-28 rounded-2xl" />) :
statCards.map((card, i) => (
<motion.div key={i} initial={{ opacity: 0, y: 20 }} animate={{ opacity: 1, y: 0 }}
transition={{ delay: i * 0.1 }}
className="glass rounded-2xl p-5">
<div className="flex items-center gap-3 mb-3">
<div className={`w-10 h-10 rounded-xl bg-gradient-to-br ${card.color} flex items-center justify-center text-lg`}>{card.icon}</div>
<span className="text-dark-400 text-sm">{card.label}</span>
</div>
<div className="text-2xl font-bold">{card.value}</div>
</motion.div>
))}
</div>
</div>
)}
{/* Users Tab */}
{tab === 'users' && (
<div className="glass rounded-2xl overflow-hidden">
<div className="overflow-x-auto">
<table className="w-full">
<thead className="bg-dark-900/50">
<tr>
<th className="text-left px-6 py-4 text-sm text-dark-400 font-medium">Nome</th>
<th className="text-left px-6 py-4 text-sm text-dark-400 font-medium">E-mail</th>
<th className="text-left px-6 py-4 text-sm text-dark-400 font-medium">Função</th>
<th className="text-left px-6 py-4 text-sm text-dark-400 font-medium">Status</th>
<th className="text-left px-6 py-4 text-sm text-dark-400 font-medium">Data</th>
</tr>
</thead>
<tbody className="divide-y divide-dark-800">
{loading ? <tr><td colSpan={5} className="px-6 py-8 text-center text-dark-500">Carregando...</td></tr> :
users.map(u => (
<tr key={u.id} className="hover:bg-dark-800/50 transition-colors">
<td className="px-6 py-4">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-brand-500 to-purple-600 flex items-center justify-center text-xs font-bold">
{u.name?.charAt(0)}
</div>
<span className="text-sm font-medium">{u.name}</span>
</div>
</td>
<td className="px-6 py-4 text-sm text-dark-400">{u.email}</td>
<td className="px-6 py-4">
<span className={`text-xs px-2 py-1 rounded-lg font-medium ${u.role === 'super_admin' ? 'bg-red-500/15 text-red-400' :
u.role === 'partner_admin' ? 'bg-blue-500/15 text-blue-400' :
'bg-gray-500/15 text-gray-400'
}`}>{u.role}</span>
</td>
<td className="px-6 py-4">
<span className={`text-xs px-2 py-1 rounded-lg ${u.status === 'active' ? 'bg-green-500/15 text-green-400' : 'bg-yellow-500/15 text-yellow-400'
}`}>{u.status}</span>
</td>
<td className="px-6 py-4 text-sm text-dark-500">{new Date(u.created_at).toLocaleDateString('pt-BR')}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{/* Partners Tab */}
{tab === 'partners' && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{loading ? [1, 2, 3].map(i => <div key={i} className="skeleton h-40 rounded-2xl" />) :
partners.map(p => (
<motion.div key={p.id} initial={{ opacity: 0, scale: 0.95 }} animate={{ opacity: 1, scale: 1 }}
className="glass rounded-2xl p-6 hover:bg-white/5 transition-all cursor-pointer group">
<div className="flex items-center gap-4 mb-4">
<div className={`w-12 h-12 rounded-xl flex items-center justify-center text-2xl`}
style={{ background: `linear-gradient(135deg, ${p.gradient_from || '#3B82F6'}, ${p.gradient_to || '#8B5CF6'})` }}>
{p.icon || '🏢'}
</div>
<div>
<h3 className="font-bold group-hover:text-brand-400 transition-colors">{p.company_name}</h3>
<p className="text-xs text-dark-500">{p.type} {p.slug}</p>
</div>
</div>
<div className="flex items-center justify-between text-sm">
<span className={`px-2 py-1 rounded-lg text-xs ${p.status === 'active' ? 'bg-green-500/15 text-green-400' : 'bg-red-500/15 text-red-400'
}`}>{p.status === 'active' ? 'Ativo' : 'Inativo'}</span>
<span className="text-dark-500">{p.subscription_plan || 'basic'}</span>
</div>
</motion.div>
))}
</div>
)}
{/* Logs Tab */}
{tab === 'logs' && (
<div className="glass rounded-2xl p-6">
<h2 className="text-lg font-bold mb-4">Logs de Auditoria</h2>
<div className="space-y-2">
{loading ? [1, 2, 3, 4, 5].map(i => <div key={i} className="skeleton h-12 rounded-xl" />) :
logs.length === 0 ? (
<p className="text-dark-500 text-center py-8">Nenhum log registrado.</p>
) : logs.map((l: any) => (
<div key={l.id} className="flex items-center gap-4 p-3 rounded-xl bg-dark-900/50">
<div className="w-9 h-9 rounded-lg bg-brand-500/15 flex items-center justify-center text-brand-400 text-sm">📋</div>
<div className="flex-1 min-w-0">
<p className="text-sm font-medium truncate">{l.action}: {l.description || l.entity_type}</p>
<p className="text-xs text-dark-500">{new Date(l.created_at).toLocaleString('pt-BR')}</p>
</div>
<span className="text-xs text-dark-500 shrink-0">{l.ip_address}</span>
</div>
))}
</div>
</div>
)}
</div>
</DashboardLayout>
);
}