'use client'; import React, { useState, useEffect } from 'react'; import { Building2, Plus, Search, CheckCircle2, XCircle, Phone, MapPin, MessageCircle, Edit2, Power, Package, ShieldCheck, FileText, User, Info, Layers, Sparkles, } from 'lucide-react'; import { Supplier, Product } from '@/types'; import { INITIAL_SUPPLIERS } from '@/lib/data-service'; import { renderClientTemplate, initClientTemplates } from '@/lib/templates-client'; export default function AdminSuppliersPage() { const [suppliers, setSuppliers] = useState(INITIAL_SUPPLIERS); const [products, setProducts] = useState([]); const [search, setSearch] = useState(''); const [statusFilter, setStatusFilter] = useState<'all' | 'active' | 'inactive'>('all'); const [toast, setToast] = useState(null); // Modal State const [isModalOpen, setIsModalOpen] = useState(false); const [editingSupplier, setEditingSupplier] = useState(null); // Form fields const [name, setName] = useState(''); const [phone, setPhone] = useState(''); const [contactPerson, setContactPerson] = useState(''); const [address, setAddress] = useState(''); const [notes, setNotes] = useState(''); const [isActive, setIsActive] = useState(true); const [isSaving, setIsSaving] = useState(false); useEffect(() => { fetchSuppliers(); fetchProducts(); initClientTemplates(); }, []); const fetchSuppliers = async () => { try { const res = await fetch('/api/suppliers?all=true'); const data = await res.json(); if (data.success && data.suppliers) { setSuppliers(data.suppliers); } } catch (e) { console.error('Error fetching suppliers:', e); } }; const fetchProducts = async () => { try { const res = await fetch('/api/products?all=true'); const data = await res.json(); if (data.success && data.products) { setProducts(data.products); } } catch (e) { console.error('Error fetching products:', e); } }; const handleOpenCreateModal = () => { setEditingSupplier(null); setName(''); setPhone('57'); setContactPerson(''); setAddress(''); setNotes(''); setIsActive(true); setIsModalOpen(true); }; const handleOpenEditModal = (supplier: Supplier) => { setEditingSupplier(supplier); setName(supplier.name); setPhone(supplier.phone); setContactPerson(supplier.contactPerson || ''); setAddress(supplier.address || ''); setNotes(supplier.notes || ''); setIsActive(supplier.isActive !== false); setIsModalOpen(true); }; const handleToggleActive = async (supplier: Supplier) => { const nextStatus = !supplier.isActive; // Optimistic update setSuppliers((prev) => prev.map((s) => (s.id === supplier.id ? { ...s, isActive: nextStatus } : s)) ); try { const res = await fetch('/api/suppliers', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: supplier.id, updates: { isActive: nextStatus }, }), }); const data = await res.json(); if (data.success) { setToast( nextStatus ? `🟢 Proveedor "${supplier.name}" ACTIVADO exitosamente.` : `⚪ Proveedor "${supplier.name}" DESACTIVADO. Su información histórica y pedidos continúan 100% seguros.` ); setTimeout(() => setToast(null), 4500); } } catch (e) { console.error('Error toggling supplier active status:', e); fetchSuppliers(); } }; const handleSaveSupplier = async (e: React.FormEvent) => { e.preventDefault(); setIsSaving(true); const cleanPhone = phone.replace(/\D/g, ''); const finalPhone = cleanPhone.startsWith('57') ? cleanPhone : `57${cleanPhone}`; try { if (editingSupplier) { // Edit existing const res = await fetch('/api/suppliers', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ id: editingSupplier.id, name, phone: finalPhone, contactPerson, address, notes, isActive, }), }); const data = await res.json(); if (data.success) { setToast(`✅ Proveedor "${name}" actualizado con éxito.`); setTimeout(() => setToast(null), 4000); setIsModalOpen(false); fetchSuppliers(); } } else { // Create new const res = await fetch('/api/suppliers', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name, phone: finalPhone, contactPerson, address, notes, isActive, }), }); const data = await res.json(); if (data.success) { setToast(`✨ Proveedor "${name}" registrado correctamente.`); setTimeout(() => setToast(null), 4000); setIsModalOpen(false); fetchSuppliers(); } } } catch (err) { console.error(err); } finally { setIsSaving(false); } }; const handleOpenWhatsApp = (supplier: Supplier) => { const cleanPhone = supplier.phone.startsWith('57') ? supplier.phone : `57${supplier.phone}`; const rawText = renderClientTemplate('supplier_general_contact', { proveedor_contacto: supplier.contactPerson || supplier.name, proveedor_nombre: supplier.name, tienda_nombre: 'DripZone', }); const text = encodeURIComponent(rawText); window.open(`https://wa.me/${cleanPhone}?text=${text}`, '_blank'); }; // Metrics const activeSuppliers = suppliers.filter((s) => s.isActive !== false); const inactiveSuppliers = suppliers.filter((s) => s.isActive === false); const filteredSuppliers = suppliers.filter((s) => { const matchesSearch = s.name.toLowerCase().includes(search.toLowerCase()) || s.phone.includes(search) || (s.contactPerson && s.contactPerson.toLowerCase().includes(search.toLowerCase())) || (s.address && s.address.toLowerCase().includes(search.toLowerCase())) || (s.notes && s.notes.toLowerCase().includes(search.toLowerCase())); if (!matchesSearch) return false; if (statusFilter === 'active' && s.isActive === false) return false; if (statusFilter === 'inactive' && s.isActive !== false) return false; return true; }); const getProductCountForSupplier = (supplierId: string, supplierName: string) => { return products.filter( (p) => p.supplierId === supplierId || (p.supplierName && p.supplierName.toLowerCase() === supplierName.toLowerCase()) ).length; }; return (
{/* Page Header */}

Proveedores & Bodegas Aliadas ({suppliers.length})

Activa o desactiva proveedores en 1 clic sin perder el histórico de pedidos, productos ni trazabilidad logística.

{toast && (
{toast}
)} {/* KPI Cards */}
Total Proveedores

{suppliers.length}

Bodegas y mayoristas registrados

Proveedores Activos

{activeSuppliers.length}

Disponibles para nuevas zapatillas y pedidos

Desactivados / Históricos

{inactiveSuppliers.length}

Historial preservado 100% intacto

Zapatillas Vinculadas

{products.length}

Modelos en catálogo

{/* Info Banner About Historical Safety */}

🛡️ Trazabilidad & Protección Histórica Garantizada

Al desactivar un proveedor, ningún pedido pasado se altera ni se pierde. Los manifiestos de despacho, reportes financieros y costos mayoristas de pedidos anteriores conservan su información original. El proveedor simplemente se oculta para nuevas asignaciones de zapatillas.

{/* Filter and Search Bar */}
setSearch(e.target.value)} className="w-full bg-neutral-900 border border-neutral-800 rounded-xl pl-9 pr-3.5 py-2 text-xs text-white outline-hidden focus:border-purple-400" />
{/* Supplier Cards Grid */}
{filteredSuppliers.length === 0 ? (

No se encontraron proveedores

Prueba con otro término de búsqueda o cambia los filtros.

) : ( filteredSuppliers.map((supplier) => { const isSupActive = supplier.isActive !== false; const linkedProductsCount = getProductCountForSupplier(supplier.id, supplier.name); return (
{/* Card Top: Status & Name */}
{isSupActive ? 'Activo para Pedidos' : 'Inactivo (Histórico Seguro)'}

{supplier.name}

{/* Details List */}
{supplier.contactPerson && (

Contacto: {supplier.contactPerson}

)}

{supplier.phone}

{supplier.address && (

{supplier.address}

)} {supplier.notes && (

"{supplier.notes}"

)}
{/* Card Bottom: Metrics & Actions */}
Modelos asignados: {linkedProductsCount} pares
); }) )}
{/* Modal Crear / Editar Proveedor */} {isModalOpen && (

{editingSupplier ? 'Modificar Proveedor' : 'Registrar Nuevo Proveedor'}

setName(e.target.value)} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3.5 py-2.5 text-white outline-hidden focus:border-purple-400 font-semibold" />
setPhone(e.target.value)} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3.5 py-2.5 text-emerald-300 outline-hidden focus:border-emerald-400 font-mono font-bold" />
setContactPerson(e.target.value)} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3.5 py-2.5 text-white outline-hidden focus:border-purple-400" />
setAddress(e.target.value)} className="w-full bg-neutral-950 border border-neutral-800 rounded-xl px-3.5 py-2.5 text-white outline-hidden focus:border-purple-400" />