Spaces:
Running
Running
File size: 6,329 Bytes
952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8457d97 8e723d7 952569a 8e723d7 8457d97 8e723d7 8457d97 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8457d97 952569a 8457d97 952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a 8e723d7 952569a | 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 132 133 134 135 136 137 138 139 140 141 142 143 | "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";
import {
AreaChart,
Area,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
BarChart,
Bar,
Cell
} from 'recharts';
import {
Package,
Users,
ShoppingCart,
LayoutDashboard
} from 'lucide-react';
import { motion } from 'framer-motion';
const dummyData = [
{ name: 'Lun', sales: 4000, products: 2400 },
{ name: 'Mar', sales: 3000, products: 1398 },
{ name: 'Mie', sales: 2000, products: 9800 },
{ name: 'Jue', sales: 2780, products: 3908 },
{ name: 'Vie', sales: 1890, products: 4800 },
{ name: 'Sab', sales: 2390, products: 3800 },
{ name: 'Dom', sales: 3490, products: 4300 },
];
export default function Dashboard() {
const [stats, setStats] = useState({ products: 0, clients: 0, salesCount: 0, revenue: 0 });
useEffect(() => {
const unsubProducts = onSnapshot(collection(db, "products"), (snap) => setStats((p) => ({ ...p, products: snap.size })));
const unsubClients = onSnapshot(collection(db, "clients"), (snap) => setStats((p) => ({ ...p, clients: snap.size })));
const unsubSales = onSnapshot(collection(db, "sales"), (snap) => {
let rev = 0;
snap.forEach((doc) => rev += doc.data().total || 0);
setStats((p) => ({ ...p, salesCount: snap.size, revenue: rev }));
});
return () => { unsubProducts(); unsubClients(); unsubSales(); };
}, []);
return (
<div className="min-h-screen bg-[#0f172a] text-white p-10">
<header className="flex justify-between items-center mb-16">
<div>
<h1 className="text-6xl font-black tracking-tighter italic bg-gradient-to-br from-white to-gray-500 bg-clip-text text-transparent">
ERP / NEXUS
</h1>
<p className="text-gray-500 font-bold mt-2 uppercase text-xs tracking-widest">Plataforma de Control Empresarial Inteligente</p>
</div>
<div className="flex border border-white/10 rounded-2xl p-2 backdrop-blur-md bg-white/5">
<div className="px-4 py-2 bg-blue-600 rounded-xl text-xs font-black uppercase">En Vivo</div>
<div className="px-4 py-2 text-xs font-bold text-gray-500">Global</div>
</div>
</header>
{/* Stats Table */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-8 mb-16">
<StatCard title="Inventario" value={stats.products} icon={<Package />} color="from-blue-600" />
<StatCard title="Staff Activo" value={stats.clients} icon={<Users />} color="from-purple-600" />
<StatCard title="Ventas Mes" value={stats.salesCount} icon={<ShoppingCart />} color="from-orange-600" />
<StatCard title="Ingresos" value={`$${stats.revenue.toLocaleString()}`} icon={<LayoutDashboard />} color="from-emerald-600" />
</div>
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
{/* Advanced Chart */}
<div className="lg:col-span-2 bg-white/5 border border-white/10 rounded-[3rem] p-10 h-[450px]">
<h2 className="text-xl font-black italic uppercase tracking-widest mb-10 text-gray-400">Rendimiento Mensual / <span className="text-white">Revenue</span></h2>
<ResponsiveContainer width="100%" height="70%">
<AreaChart data={dummyData}>
<defs>
<linearGradient id="colorSales" x1="0" y1="0" x2="0" y2="1">
<stop offset="5%" stopColor="#3b82f6" stopOpacity={0.3}/>
<stop offset="95%" stopColor="#3b82f6" stopOpacity={0}/>
</linearGradient>
</defs>
<Tooltip
contentStyle={{ backgroundColor: '#1e293b', border: 'none', borderRadius: '16px', fontSize: '12px' }}
itemStyle={{ color: '#fff' }}
/>
<Area type="monotone" dataKey="sales" stroke="#3b82f6" strokeWidth={4} fillOpacity={1} fill="url(#colorSales)" />
</AreaChart>
</ResponsiveContainer>
</div>
{/* Inventory Widget */}
<div className="bg-white/5 border border-white/10 rounded-[3rem] p-10 relative overflow-hidden group">
<div className="absolute top-0 right-0 p-8 text-6xl opacity-5 group-hover:opacity-10 transition-opacity font-black italic">DATA</div>
<h2 className="text-xl font-black italic uppercase tracking-widest mb-10 text-gray-400">Distribución / <span className="text-white">Stock</span></h2>
<div className="space-y-6">
<ProgressWidget label="Electrónicos" value={78} color="bg-blue-500" />
<ProgressWidget label="Mobiliario" value={45} color="bg-purple-500" />
<ProgressWidget label="Insumos" value={92} color="bg-emerald-500" />
<ProgressWidget label="Servicios" value={23} color="bg-orange-500" />
</div>
</div>
</div>
</div>
);
}
function StatCard({ title, value, icon, color }: any) {
return (
<div className="bg-white/5 border border-white/10 rounded-[2.5rem] p-8 backdrop-blur-xl relative group cursor-pointer hover:bg-white/10 transition-all">
<div className={`absolute top-0 left-0 w-full h-1 bg-gradient-to-r ${color} to-transparent opacity-0 group-hover:opacity-100 transition-opacity`}></div>
<div className="flex flex-col gap-4">
<div className="w-12 h-12 bg-white/10 rounded-2xl flex items-center justify-center text-blue-400">{icon}</div>
<p className="text-[10px] font-black uppercase tracking-[0.2em] text-gray-500">{title}</p>
<p className="text-4xl font-black italic tracking-tighter">{value}</p>
</div>
</div>
);
}
function ProgressWidget({ label, value, color }: any) {
return (
<div className="space-y-2">
<div className="flex justify-between text-[10px] font-black uppercase tracking-widest">
<span>{label}</span>
<span className="text-gray-500">{value}%</span>
</div>
<div className="w-full h-1.5 bg-white/5 rounded-full overflow-hidden">
<motion.div
initial={{ width: 0 }}
animate={{ width: `${value}%` }}
className={`h-full ${color}`}
/>
</div>
</div>
);
}
|