Spaces:
Running
Running
| "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> | |
| ); | |
| } | |