603 lines
26 KiB
TypeScript
603 lines
26 KiB
TypeScript
'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<Supplier[]>(INITIAL_SUPPLIERS);
|
||
const [products, setProducts] = useState<Product[]>([]);
|
||
const [search, setSearch] = useState('');
|
||
const [statusFilter, setStatusFilter] = useState<'all' | 'active' | 'inactive'>('all');
|
||
const [toast, setToast] = useState<string | null>(null);
|
||
|
||
// Modal State
|
||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||
const [editingSupplier, setEditingSupplier] = useState<Supplier | null>(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 (
|
||
<div className="space-y-6">
|
||
{/* Page Header */}
|
||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||
<div>
|
||
<h1 className="text-2xl font-black text-white flex items-center gap-2">
|
||
<Building2 className="w-6 h-6 text-purple-400" />
|
||
<span>Proveedores & Bodegas Aliadas ({suppliers.length})</span>
|
||
</h1>
|
||
<p className="text-xs text-neutral-400 mt-1">
|
||
Activa o desactiva proveedores en 1 clic <strong>sin perder el histórico de pedidos, productos ni trazabilidad logística</strong>.
|
||
</p>
|
||
</div>
|
||
|
||
<button
|
||
onClick={handleOpenCreateModal}
|
||
className="bg-gradient-to-r from-purple-600 to-fuchsia-600 hover:from-purple-500 hover:to-fuchsia-500 text-white font-bold text-xs px-4 py-2.5 rounded-2xl flex items-center space-x-2 shadow-lg cursor-pointer transition-all active:scale-95 self-start sm:self-auto"
|
||
>
|
||
<Plus className="w-4 h-4" />
|
||
<span>Nuevo Proveedor</span>
|
||
</button>
|
||
</div>
|
||
|
||
{toast && (
|
||
<div className="bg-purple-950/90 border border-purple-500 text-purple-200 px-4 py-3 rounded-2xl text-xs flex items-center justify-between shadow-xl animate-in fade-in">
|
||
<span>{toast}</span>
|
||
<button onClick={() => setToast(null)} className="font-bold text-white cursor-pointer ml-3">
|
||
✕
|
||
</button>
|
||
</div>
|
||
)}
|
||
|
||
{/* KPI Cards */}
|
||
<div className="grid grid-cols-2 lg:grid-cols-4 gap-3.5">
|
||
<div className="bg-neutral-900 border border-neutral-800 p-4 rounded-3xl space-y-1 shadow-lg">
|
||
<div className="flex items-center justify-between text-neutral-400 text-xs font-bold uppercase tracking-wider">
|
||
<span>Total Proveedores</span>
|
||
<Building2 className="w-4 h-4 text-purple-400" />
|
||
</div>
|
||
<p className="text-2xl font-black text-white">{suppliers.length}</p>
|
||
<p className="text-[10px] text-neutral-400">Bodegas y mayoristas registrados</p>
|
||
</div>
|
||
|
||
<div className="bg-neutral-900 border border-emerald-500/30 p-4 rounded-3xl space-y-1 shadow-lg">
|
||
<div className="flex items-center justify-between text-emerald-400 text-xs font-bold uppercase tracking-wider">
|
||
<span>Proveedores Activos</span>
|
||
<CheckCircle2 className="w-4 h-4 text-emerald-400" />
|
||
</div>
|
||
<p className="text-2xl font-black text-emerald-300">{activeSuppliers.length}</p>
|
||
<p className="text-[10px] text-emerald-400/80">Disponibles para nuevas zapatillas y pedidos</p>
|
||
</div>
|
||
|
||
<div className="bg-neutral-900 border border-amber-500/30 p-4 rounded-3xl space-y-1 shadow-lg">
|
||
<div className="flex items-center justify-between text-amber-400 text-xs font-bold uppercase tracking-wider">
|
||
<span>Desactivados / Históricos</span>
|
||
<XCircle className="w-4 h-4 text-amber-400" />
|
||
</div>
|
||
<p className="text-2xl font-black text-amber-300">{inactiveSuppliers.length}</p>
|
||
<p className="text-[10px] text-neutral-400">Historial preservado 100% intacto</p>
|
||
</div>
|
||
|
||
<div className="bg-neutral-900 border border-neutral-800 p-4 rounded-3xl space-y-1 shadow-lg">
|
||
<div className="flex items-center justify-between text-neutral-400 text-xs font-bold uppercase tracking-wider">
|
||
<span>Zapatillas Vinculadas</span>
|
||
<Package className="w-4 h-4 text-fuchsia-400" />
|
||
</div>
|
||
<p className="text-2xl font-black text-fuchsia-300">{products.length}</p>
|
||
<p className="text-[10px] text-neutral-400">Modelos en catálogo</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Info Banner About Historical Safety */}
|
||
<div className="bg-gradient-to-r from-neutral-900 via-neutral-900 to-purple-950/40 border border-purple-500/20 rounded-3xl p-4 flex items-start space-x-3 text-xs text-neutral-300 shadow-md">
|
||
<Info className="w-5 h-5 text-purple-400 shrink-0 mt-0.5" />
|
||
<div className="space-y-1">
|
||
<p className="font-bold text-white">
|
||
🛡️ Trazabilidad & Protección Histórica Garantizada
|
||
</p>
|
||
<p className="text-[11px] text-neutral-400">
|
||
Al desactivar un proveedor, <strong>ningún pedido pasado se altera ni se pierde</strong>. 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.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Filter and Search Bar */}
|
||
<div className="flex flex-col sm:flex-row items-stretch sm:items-center justify-between gap-3">
|
||
<div className="flex items-center space-x-1.5 bg-neutral-900 border border-neutral-800 p-1 rounded-2xl overflow-x-auto">
|
||
<button
|
||
onClick={() => setStatusFilter('all')}
|
||
className={`text-xs font-bold px-3.5 py-1.5 rounded-xl cursor-pointer transition-all ${
|
||
statusFilter === 'all' ? 'bg-white text-neutral-950 shadow' : 'text-neutral-400 hover:text-white'
|
||
}`}
|
||
>
|
||
Todos ({suppliers.length})
|
||
</button>
|
||
<button
|
||
onClick={() => setStatusFilter('active')}
|
||
className={`text-xs font-bold px-3.5 py-1.5 rounded-xl cursor-pointer transition-all flex items-center gap-1.5 ${
|
||
statusFilter === 'active'
|
||
? 'bg-emerald-500/30 border border-emerald-500/50 text-emerald-300 shadow'
|
||
: 'text-neutral-400 hover:text-emerald-400'
|
||
}`}
|
||
>
|
||
<span className="w-2 h-2 rounded-full bg-emerald-400" />
|
||
<span>Activos ({activeSuppliers.length})</span>
|
||
</button>
|
||
<button
|
||
onClick={() => setStatusFilter('inactive')}
|
||
className={`text-xs font-bold px-3.5 py-1.5 rounded-xl cursor-pointer transition-all flex items-center gap-1.5 ${
|
||
statusFilter === 'inactive'
|
||
? 'bg-amber-500/30 border border-amber-500/50 text-amber-300 shadow'
|
||
: 'text-neutral-400 hover:text-amber-400'
|
||
}`}
|
||
>
|
||
<span className="w-2 h-2 rounded-full bg-amber-400" />
|
||
<span>Inactivos ({inactiveSuppliers.length})</span>
|
||
</button>
|
||
</div>
|
||
|
||
<div className="max-w-xs w-full">
|
||
<div className="relative">
|
||
<input
|
||
type="text"
|
||
placeholder="Buscar proveedor, teléfono o bodega..."
|
||
value={search}
|
||
onChange={(e) => 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"
|
||
/>
|
||
<Search className="w-4 h-4 text-neutral-400 absolute left-3 top-1/2 -translate-y-1/2" />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* Supplier Cards Grid */}
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||
{filteredSuppliers.length === 0 ? (
|
||
<div className="col-span-full bg-neutral-900 border border-neutral-800 rounded-3xl p-12 text-center text-neutral-500 space-y-2">
|
||
<Building2 className="w-12 h-12 text-neutral-600 mx-auto" />
|
||
<p className="font-bold text-white text-sm">No se encontraron proveedores</p>
|
||
<p className="text-xs">Prueba con otro término de búsqueda o cambia los filtros.</p>
|
||
</div>
|
||
) : (
|
||
filteredSuppliers.map((supplier) => {
|
||
const isSupActive = supplier.isActive !== false;
|
||
const linkedProductsCount = getProductCountForSupplier(supplier.id, supplier.name);
|
||
|
||
return (
|
||
<div
|
||
key={supplier.id}
|
||
className={`bg-neutral-900 border rounded-3xl p-5 shadow-xl transition-all flex flex-col justify-between space-y-4 ${
|
||
isSupActive
|
||
? 'border-neutral-800 hover:border-purple-500/40'
|
||
: 'border-neutral-800/80 opacity-75 bg-neutral-950/60'
|
||
}`}
|
||
>
|
||
{/* Card Top: Status & Name */}
|
||
<div className="space-y-2">
|
||
<div className="flex items-center justify-between">
|
||
<span
|
||
className={`text-[10px] font-bold px-2.5 py-0.5 rounded-full border flex items-center gap-1 ${
|
||
isSupActive
|
||
? 'bg-emerald-500/20 border-emerald-500/40 text-emerald-300'
|
||
: 'bg-amber-500/20 border-amber-500/40 text-amber-300'
|
||
}`}
|
||
>
|
||
<span
|
||
className={`w-1.5 h-1.5 rounded-full ${
|
||
isSupActive ? 'bg-emerald-400 animate-pulse' : 'bg-amber-400'
|
||
}`}
|
||
/>
|
||
<span>{isSupActive ? 'Activo para Pedidos' : 'Inactivo (Histórico Seguro)'}</span>
|
||
</span>
|
||
|
||
<button
|
||
onClick={() => handleToggleActive(supplier)}
|
||
className={`text-[11px] font-bold px-2.5 py-1 rounded-xl border flex items-center gap-1 cursor-pointer transition-all ${
|
||
isSupActive
|
||
? 'bg-red-500/10 border-red-500/30 text-red-400 hover:bg-red-500/20'
|
||
: 'bg-emerald-500/10 border-emerald-500/30 text-emerald-400 hover:bg-emerald-500/20'
|
||
}`}
|
||
title={isSupActive ? 'Desactivar proveedor (conserva historial)' : 'Reactivar proveedor'}
|
||
>
|
||
<Power className="w-3 h-3" />
|
||
<span>{isSupActive ? 'Desactivar' : 'Activar'}</span>
|
||
</button>
|
||
</div>
|
||
|
||
<h3 className="font-black text-white text-base leading-snug">{supplier.name}</h3>
|
||
|
||
{/* Details List */}
|
||
<div className="space-y-1.5 text-xs pt-1">
|
||
{supplier.contactPerson && (
|
||
<p className="text-neutral-300 flex items-center gap-1.5">
|
||
<User className="w-3.5 h-3.5 text-purple-400 shrink-0" />
|
||
<span>Contacto: <strong className="text-white">{supplier.contactPerson}</strong></span>
|
||
</p>
|
||
)}
|
||
|
||
<p className="text-neutral-300 flex items-center gap-1.5">
|
||
<Phone className="w-3.5 h-3.5 text-emerald-400 shrink-0" />
|
||
<span className="font-mono text-emerald-300 font-semibold">{supplier.phone}</span>
|
||
</p>
|
||
|
||
{supplier.address && (
|
||
<p className="text-neutral-400 flex items-center gap-1.5 text-[11px]">
|
||
<MapPin className="w-3.5 h-3.5 text-pink-400 shrink-0" />
|
||
<span>{supplier.address}</span>
|
||
</p>
|
||
)}
|
||
|
||
{supplier.notes && (
|
||
<p className="text-neutral-400 italic text-[11px] bg-neutral-950 p-2 rounded-xl border border-neutral-800 mt-1">
|
||
"{supplier.notes}"
|
||
</p>
|
||
)}
|
||
</div>
|
||
</div>
|
||
|
||
{/* Card Bottom: Metrics & Actions */}
|
||
<div className="pt-3 border-t border-neutral-800 space-y-3">
|
||
<div className="flex items-center justify-between text-xs text-neutral-400">
|
||
<span className="flex items-center gap-1">
|
||
<Package className="w-3.5 h-3.5 text-fuchsia-400" />
|
||
<span>Modelos asignados:</span>
|
||
</span>
|
||
<strong className="text-white bg-neutral-950 px-2 py-0.5 rounded-lg border border-neutral-800">
|
||
{linkedProductsCount} pares
|
||
</strong>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<button
|
||
onClick={() => handleOpenWhatsApp(supplier)}
|
||
className="bg-emerald-600 hover:bg-emerald-500 text-white font-bold text-xs py-2 px-3 rounded-xl flex items-center justify-center gap-1.5 cursor-pointer shadow transition-all active:scale-95"
|
||
>
|
||
<MessageCircle className="w-3.5 h-3.5" />
|
||
<span>WhatsApp</span>
|
||
</button>
|
||
|
||
<button
|
||
onClick={() => handleOpenEditModal(supplier)}
|
||
className="bg-neutral-800 hover:bg-neutral-700 text-neutral-200 font-bold text-xs py-2 px-3 rounded-xl flex items-center justify-center gap-1.5 cursor-pointer transition-all active:scale-95"
|
||
>
|
||
<Edit2 className="w-3.5 h-3.5 text-purple-400" />
|
||
<span>Modificar</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})
|
||
)}
|
||
</div>
|
||
|
||
{/* Modal Crear / Editar Proveedor */}
|
||
{isModalOpen && (
|
||
<div className="fixed inset-0 z-50 bg-black/80 backdrop-blur-xs flex items-center justify-center p-4 animate-in fade-in">
|
||
<div className="bg-neutral-900 border border-neutral-800 rounded-3xl max-w-lg w-full p-6 space-y-4 shadow-2xl">
|
||
<div className="flex items-center justify-between border-b border-neutral-800 pb-3">
|
||
<h3 className="font-black text-white text-base flex items-center gap-2">
|
||
<Building2 className="w-5 h-5 text-purple-400" />
|
||
<span>{editingSupplier ? 'Modificar Proveedor' : 'Registrar Nuevo Proveedor'}</span>
|
||
</h3>
|
||
<button
|
||
onClick={() => setIsModalOpen(false)}
|
||
className="text-neutral-400 hover:text-white cursor-pointer"
|
||
>
|
||
✕
|
||
</button>
|
||
</div>
|
||
|
||
<form onSubmit={handleSaveSupplier} className="space-y-4 text-xs">
|
||
<div>
|
||
<label className="block text-neutral-400 font-bold mb-1">Nombre Comercial / Bodega *</label>
|
||
<input
|
||
type="text"
|
||
required
|
||
placeholder="Ej: Bodega Central Mayorista"
|
||
value={name}
|
||
onChange={(e) => 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"
|
||
/>
|
||
</div>
|
||
|
||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||
<div>
|
||
<label className="block text-emerald-400 font-bold mb-1">Celular / WhatsApp *</label>
|
||
<input
|
||
type="tel"
|
||
required
|
||
placeholder="Ej: 573XXXXXXXXX"
|
||
value={phone}
|
||
onChange={(e) => 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"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-neutral-400 font-bold mb-1">Persona de Contacto</label>
|
||
<input
|
||
type="text"
|
||
placeholder="Ej: Asesor de Despachos"
|
||
value={contactPerson}
|
||
onChange={(e) => 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"
|
||
/>
|
||
</div>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-neutral-400 font-bold mb-1">Ubicación / Dirección de la Bodega</label>
|
||
<input
|
||
type="text"
|
||
placeholder="Ej: Centro Comercial Mayorista Local 102"
|
||
value={address}
|
||
onChange={(e) => 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"
|
||
/>
|
||
</div>
|
||
|
||
<div>
|
||
<label className="block text-neutral-400 font-bold mb-1">Notas / Políticas de Garantía & Horarios</label>
|
||
<textarea
|
||
rows={3}
|
||
placeholder="Ej: Horario de despacho y recogida de 9:00 AM a 6:00 PM."
|
||
value={notes}
|
||
onChange={(e) => setNotes(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"
|
||
/>
|
||
</div>
|
||
|
||
|
||
<div className="bg-neutral-950 p-3 rounded-2xl border border-neutral-800 flex items-center justify-between">
|
||
<div>
|
||
<p className="font-bold text-white text-xs">Estado del Proveedor</p>
|
||
<p className="text-[10px] text-neutral-400">
|
||
{isActive
|
||
? '🟢 Activo: disponible para asignar nuevas zapatillas y recibir pedidos'
|
||
: '⚪ Desactivado: no aparecerá en nuevas publicaciones (el historial se mantiene)'}
|
||
</p>
|
||
</div>
|
||
<label className="relative inline-flex items-center cursor-pointer">
|
||
<input
|
||
type="checkbox"
|
||
checked={isActive}
|
||
onChange={(e) => setIsActive(e.target.checked)}
|
||
className="sr-only peer"
|
||
/>
|
||
<div className="w-11 h-6 bg-neutral-800 peer-focus:outline-hidden rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-neutral-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-emerald-500"></div>
|
||
</label>
|
||
</div>
|
||
|
||
<div className="flex justify-end space-x-2 pt-2 border-t border-neutral-800">
|
||
<button
|
||
type="button"
|
||
onClick={() => setIsModalOpen(false)}
|
||
className="bg-neutral-800 hover:bg-neutral-700 text-neutral-300 font-bold py-2.5 px-4 rounded-xl cursor-pointer"
|
||
>
|
||
Cancelar
|
||
</button>
|
||
<button
|
||
type="submit"
|
||
disabled={isSaving}
|
||
className="bg-gradient-to-r from-purple-600 to-fuchsia-600 hover:from-purple-500 hover:to-fuchsia-500 text-white font-bold py-2.5 px-5 rounded-xl shadow-lg cursor-pointer transition-all disabled:opacity-50"
|
||
>
|
||
{isSaving ? 'Guardando...' : editingSupplier ? 'Actualizar Proveedor' : 'Guardar Proveedor'}
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
);
|
||
}
|