NEXUS / app /inventory /page.tsx
dimensionalpulsar's picture
Upload 26 files
952569a verified
"use client";
import React, { useState, useEffect } from "react";
import { db } from "@/lib/firebase";
import { collection, onSnapshot, addDoc, deleteDoc, doc, updateDoc } from "firebase/firestore";
import Link from "next/link";
interface Product {
id: string;
name: string;
category: string;
price: number;
stock: number;
}
export default function InventoryPage() {
const [products, setProducts] = useState<Product[]>([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [newProduct, setNewProduct] = useState({ name: "", category: "", price: 0, stock: 0 });
useEffect(() => {
const unsub = onSnapshot(collection(db, "products"), (snap) => {
const data = snap.docs.map(doc => ({ id: doc.id, ...doc.data() } as Product));
setProducts(data);
});
return () => unsub();
}, []);
const handleAdd = async (e: React.FormEvent) => {
e.preventDefault();
await addDoc(collection(db, "products"), newProduct);
setIsModalOpen(false);
setNewProduct({ name: "", category: "", price: 0, stock: 0 });
};
const handleDelete = async (id: string) => {
if(confirm("¿Seguro que quieres eliminar este producto?")) {
await deleteDoc(doc(db, "products", id));
}
};
return (
<div className="min-h-screen bg-[#0f172a] text-white p-6">
<header className="flex justify-between items-center mb-8">
<div>
<Link href="/" className="text-blue-400 hover:text-blue-300 transition-colors flex items-center gap-2 mb-2">
← Volver al Dashboard
</Link>
<h1 className="text-3xl font-bold">Gestión de Inventario</h1>
</div>
<button
onClick={() => setIsModalOpen(true)}
className="px-6 py-3 bg-blue-600 hover:bg-blue-500 rounded-2xl font-bold transition-all shadow-lg shadow-blue-900/20"
>
➕ Añadir Producto
</button>
</header>
{/* Inventory Table */}
<div className="bg-white/5 border border-white/10 rounded-3xl overflow-hidden backdrop-blur-xl">
<table className="w-full text-left">
<thead className="bg-white/5 border-b border-white/10">
<tr>
<th className="px-6 py-4 font-semibold text-gray-400 uppercase text-xs tracking-wider">Nombre</th>
<th className="px-6 py-4 font-semibold text-gray-400 uppercase text-xs tracking-wider">Categoría</th>
<th className="px-6 py-4 font-semibold text-gray-400 uppercase text-xs tracking-wider">Precio</th>
<th className="px-6 py-4 font-semibold text-gray-400 uppercase text-xs tracking-wider">Stock</th>
<th className="px-6 py-4 font-semibold text-gray-400 uppercase text-xs tracking-wider">Acciones</th>
</tr>
</thead>
<tbody className="divide-y divide-white/5">
{products.map((p) => (
<tr key={p.id} className="hover:bg-white/5 transition-colors group">
<td className="px-6 py-4 font-medium text-gray-200">{p.name}</td>
<td className="px-6 py-4 text-gray-400">
<span className="px-3 py-1 bg-white/5 rounded-full text-xs border border-white/10">{p.category}</span>
</td>
<td className="px-6 py-4 font-bold text-blue-400">${Number(p.price).toLocaleString()}</td>
<td className="px-6 py-4">
<div className="flex items-center gap-2">
<span className={`w-2 h-2 rounded-full ${p.stock > 10 ? 'bg-green-400' : 'bg-red-400'}`}></span>
{p.stock} uds.
</div>
</td>
<td className="px-6 py-4">
<button onClick={() => handleDelete(p.id)} className="text-gray-600 hover:text-red-400 transition-colors">🗑️</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
{/* Modal Mockup */}
{isModalOpen && (
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm flex items-center justify-center p-6 z-50">
<div className="bg-[#1e293b] border border-white/10 p-8 rounded-[40px] w-full max-w-lg shadow-2xl animate-in fade-in zoom-in-95">
<h2 className="text-2xl font-bold mb-6">Nuevo Producto</h2>
<form onSubmit={handleAdd} className="space-y-4">
<input
type="text" placeholder="Nombre" required
value={newProduct.name} onChange={e => setNewProduct({...newProduct, name: e.target.value})}
className="w-full bg-white/5 border border-white/10 rounded-2xl px-6 py-4 outline-none focus:border-blue-500/50"
/>
<input
type="text" placeholder="Categoría" required
value={newProduct.category} onChange={e => setNewProduct({...newProduct, category: e.target.value})}
className="w-full bg-white/5 border border-white/10 rounded-2xl px-6 py-4 outline-none focus:border-blue-500/50"
/>
<div className="grid grid-cols-2 gap-4">
<input
type="number" placeholder="Precio" required
value={newProduct.price} onChange={e => setNewProduct({...newProduct, price: Number(e.target.value)})}
className="w-full bg-white/5 border border-white/10 rounded-2xl px-6 py-4 outline-none focus:border-blue-500/50"
/>
<input
type="number" placeholder="Stock" required
value={newProduct.stock} onChange={e => setNewProduct({...newProduct, stock: Number(e.target.value)})}
className="w-full bg-white/5 border border-white/10 rounded-2xl px-6 py-4 outline-none focus:border-blue-500/50"
/>
</div>
<div className="flex gap-4 mt-8">
<button type="button" onClick={() => setIsModalOpen(false)} className="flex-1 py-4 text-gray-400 hover:text-white transition-colors">Cancelar</button>
<button type="submit" className="flex-1 bg-blue-600 hover:bg-blue-500 py-4 rounded-2xl font-bold transition-all shadow-lg shadow-blue-900/20">Guardar</button>
</div>
</form>
</div>
</div>
)}
</div>
);
}