Spaces:
Running
Running
File size: 5,840 Bytes
8457d97 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | "use client";
import React, { useState, useEffect } from "react";
import { db, auth } from "@/lib/firebase";
import { collection, onSnapshot, query, orderBy, limit } from "firebase/firestore";
import Link from "next/link";
export default function Dashboard() {
const [stats, setStats] = useState({
products: 0,
clients: 0,
salesCount: 0,
revenue: 0,
});
useEffect(() => {
// Real-time stats from Firestore
const unsubProducts = onSnapshot(collection(db, "products"), (snap) => {
setStats((prev) => ({ ...prev, products: snap.size }));
});
const unsubClients = onSnapshot(collection(db, "clients"), (snap) => {
setStats((prev) => ({ ...prev, clients: snap.size }));
});
const unsubSales = onSnapshot(collection(db, "sales"), (snap) => {
let rev = 0;
snap.forEach((doc) => {
rev += doc.data().total || 0;
});
setStats((prev) => ({ ...prev, salesCount: snap.size, revenue: rev }));
});
return () => {
unsubProducts();
unsubClients();
unsubSales();
};
}, []);
return (
<div className="min-h-screen bg-[#0f172a] text-white p-6 font-sans">
<header className="flex justify-between items-center mb-10">
<div>
<h1 className="text-4xl font-extrabold bg-gradient-to-r from-blue-400 to-indigo-500 bg-clip-text text-transparent">
ERP Premium Dashboard
</h1>
<p className="text-gray-400 mt-1">Bienvenido al centro de control de tu negocio</p>
</div>
<div className="flex gap-4">
<button
onClick={() => auth.signOut()}
className="px-6 py-2 bg-white/10 hover:bg-white/20 rounded-full border border-white/10 transition-all text-sm font-medium backdrop-blur-md"
>
Cerrar Sesión
</button>
</div>
</header>
{/* Stats Grid */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-10">
<StatCard title="Productos" value={stats.products} icon="📦" color="from-blue-500 to-cyan-400" />
<StatCard title="Clientes" value={stats.clients} icon="👥" color="from-purple-500 to-pink-500" />
<StatCard title="Ventas Totales" value={stats.salesCount} icon="🛒" color="from-orange-500 to-yellow-400" />
<StatCard title="Ingresos" value={`$${stats.revenue.toLocaleString()}`} icon="💰" color="from-green-500 to-emerald-400" />
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Quick Actions */}
<div className="lg:col-span-1 bg-white/5 border border-white/10 rounded-3xl p-8 backdrop-blur-xl">
<h2 className="text-xl font-bold mb-6">Acciones Rápidas</h2>
<div className="space-y-4">
<QuickAction href="/inventory" label="Nueva Existencia" icon="➕" />
<QuickAction href="/sales" label="Registrar Venta" icon="🏷️" />
<QuickAction href="/clients" label="Añadir Cliente" icon="👤" />
<QuickAction href="/hr" label="Gestionar Personal" icon="👔" />
</div>
</div>
{/* Charts Mockup / Future Widget */}
<div className="lg:col-span-2 bg-white/5 border border-white/10 rounded-3xl p-8 backdrop-blur-xl relative overflow-hidden group">
<div className="absolute inset-0 bg-gradient-to-br from-blue-600/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-700"></div>
<div className="relative z-10">
<h2 className="text-xl font-bold mb-6">Rendimiento Semanal</h2>
<div className="h-64 flex items-end justify-between gap-2">
{[60, 45, 80, 55, 95, 70, 85].map((h, i) => (
<div key={i} className="flex-1 flex flex-col items-center">
<div
className="w-full bg-gradient-to-t from-blue-600 to-cyan-400 rounded-t-lg transition-all duration-1000 delay-150"
style={{ height: `${h}%` }}
></div>
<span className="text-[10px] text-gray-500 mt-2">{['L', 'M', 'X', 'J', 'V', 'S', 'D'][i]}</span>
</div>
))}
</div>
<p className="mt-8 text-sm text-gray-400 items-center flex gap-2">
<span className="w-2 h-2 rounded-full bg-green-400 animate-pulse"></span>
Actualizado en tiempo real con Firestore
</p>
</div>
</div>
</div>
</div>
);
}
function StatCard({ title, value, icon, color }: { title: string, value: string | number, icon: string, color: string }) {
return (
<div className="bg-white/5 border border-white/10 rounded-3xl p-6 backdrop-blur-md relative overflow-hidden group hover:scale-[1.02] transition-all">
<div className={`absolute -right-4 -top-4 w-24 h-24 bg-gradient-to-br ${color} opacity-20 blur-2xl rounded-full group-hover:opacity-40 transition-opacity`}></div>
<div className="flex items-center gap-4 relative z-10">
<div className="text-3xl">{icon}</div>
<div>
<p className="text-sm text-gray-400 uppercase tracking-wider font-semibold">{title}</p>
<p className="text-2xl font-bold">{value}</p>
</div>
</div>
</div>
);
}
function QuickAction({ href, label, icon }: { href: string, label: string, icon: string }) {
return (
<Link href={href} className="flex items-center gap-4 p-4 rounded-2xl bg-white/5 border border-white/5 hover:bg-white/10 hover:border-white/20 transition-all group">
<span className="text-xl group-hover:scale-125 transition-transform">{icon}</span>
<span className="font-medium text-gray-200">{label}</span>
<span className="ml-auto opacity-0 group-hover:opacity-100 transition-opacity">→</span>
</Link>
);
}
|