arbritage/pages/Customers.tsx

168 lines
11 KiB
TypeScript
Raw Permalink Normal View History

2026-01-26 14:20:25 +00:00
import React, { useState } from 'react';
import { Users, Plus, Edit2, Trash2, Mail, Phone, MapPin } from 'lucide-react';
import { useCRM } from '../context/CRMContext';
import { Customer } from '../types';
const Customers: React.FC = () => {
const { customers, addCustomer, updateCustomer, deleteCustomer } = useCRM();
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingId, setEditingId] = useState<string | null>(null);
const [formData, setFormData] = useState<Partial<Customer>>({
name: '', email: '', phone: '', city: '', status: 'Active'
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (editingId) {
updateCustomer(editingId, formData);
} else {
addCustomer(formData as any);
}
closeModal();
};
const openModal = (customer?: Customer) => {
if (customer) {
setEditingId(customer.id);
setFormData(customer);
} else {
setEditingId(null);
setFormData({ name: '', email: '', phone: '', city: '', status: 'Active' });
}
setIsModalOpen(true);
};
const closeModal = () => {
setIsModalOpen(false);
setEditingId(null);
};
return (
<div className="space-y-8 animate-in fade-in duration-500">
{/* HEADER */}
<div className="flex justify-between items-center glass-card p-6 rounded-2xl border border-white/5 shadow-sm">
<div>
<h2 className="text-xl font-bold text-white tracking-tight">Carteira de Clientes</h2>
<p className="text-xs text-slate-500 tracking-wide mt-1">Gestão de Relacionamento (CRM)</p>
</div>
<button
onClick={() => openModal()}
className="flex items-center gap-2 bg-indigo-600 hover:bg-indigo-500 text-white px-5 py-2.5 rounded-lg font-bold text-sm transition-all shadow-lg shadow-indigo-600/20 active:scale-95"
>
<Plus size={16} /> Novo Cliente
</button>
</div>
{/* LIST */}
<div className="glass-card rounded-2xl border border-white/5 overflow-hidden">
<table className="w-full text-left border-collapse">
<thead>
<tr className="bg-black/20 text-[10px] font-bold text-slate-500 uppercase tracking-widest border-b border-white/5">
<th className="px-6 py-4">Cliente</th>
<th className="px-6 py-4">Status</th>
<th className="px-6 py-4">Contato</th>
<th className="px-6 py-4 text-right">LTV (Total Pago)</th>
<th className="px-6 py-4 text-right">Ações</th>
</tr>
</thead>
<tbody className="divide-y divide-white/5">
{customers.map(c => (
<tr key={c.id} className="hover:bg-white/[0.02] transition-colors group">
<td className="px-6 py-4">
<div className="flex items-center gap-3">
<div className="w-8 h-8 bg-slate-800 rounded-lg flex items-center justify-center text-white font-bold text-xs">
{c.name.charAt(0)}
</div>
<div>
<p className="text-sm font-bold text-slate-200">{c.name}</p>
<p className="text-[10px] text-slate-500">{c.city || 'Localização n/a'}</p>
</div>
</div>
</td>
<td className="px-6 py-4">
<span className={`px-2 py-0.5 rounded text-[10px] font-bold uppercase tracking-wide border ${c.status === 'Active' ? 'text-emerald-500 border-emerald-500/20 bg-emerald-500/5' :
c.status === 'Prospect' ? 'text-amber-500 border-amber-500/20 bg-amber-500/5' :
'text-slate-500 border-slate-600/30 bg-slate-500/5'
}`}>
{c.status === 'Active' ? 'ATIVO' : c.status === 'Prospect' ? 'PROSPECT' : 'INATIVO'}
</span>
</td>
<td className="px-6 py-4">
<div className="space-y-1">
{c.email && (
<div className="flex items-center gap-2 text-slate-400 text-xs">
<Mail size={12} className="text-slate-600" /> {c.email}
</div>
)}
{c.phone && (
<div className="flex items-center gap-2 text-slate-400 text-xs">
<Phone size={12} className="text-slate-600" /> {c.phone}
</div>
)}
</div>
</td>
<td className="px-6 py-4 text-right">
<p className="text-xs font-mono font-bold text-emerald-400">R$ {c.totalPurchased?.toLocaleString('pt-BR') || '0,00'}</p>
</td>
<td className="px-6 py-4 text-right opacity-0 group-hover:opacity-100 transition-opacity">
<div className="flex justify-end gap-2">
<button onClick={() => openModal(c)} className="p-1.5 text-slate-500 hover:text-white hover:bg-white/10 rounded transition-all"><Edit2 size={14} /></button>
<button onClick={() => deleteCustomer(c.id)} className="p-1.5 text-slate-500 hover:text-rose-400 hover:bg-rose-500/10 rounded transition-all"><Trash2 size={14} /></button>
</div>
</td>
</tr>
))}
</tbody>
</table>
{customers.length === 0 && (
<div className="py-20 text-center text-slate-700 font-mono text-xs">NO CUSTOMERS FOUND.</div>
)}
</div>
{/* MODAL */}
{isModalOpen && (
<div className="fixed inset-0 bg-black/80 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-[#0F1115] border border-white/10 w-full max-w-md rounded-2xl p-6 shadow-2xl animate-in zoom-in-95 duration-200">
<h3 className="text-lg font-bold text-white mb-6 border-b border-white/5 pb-4">{editingId ? 'Editar Cliente' : 'Novo Cliente'}</h3>
<form onSubmit={handleSubmit} className="space-y-4">
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Nome Completo</label>
<input required type="text" value={formData.name} onChange={e => setFormData({ ...formData, name: e.target.value })} className="w-full bg-black/40 border border-white/10 rounded-lg px-3 py-2 text-sm text-white focus:border-indigo-500 outline-none transition-all" />
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Telefone</label>
<input type="text" value={formData.phone} onChange={e => setFormData({ ...formData, phone: e.target.value })} className="w-full bg-black/40 border border-white/10 rounded-lg px-3 py-2 text-sm text-white focus:border-indigo-500 outline-none transition-all" />
</div>
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Status</label>
<select value={formData.status} onChange={e => setFormData({ ...formData, status: e.target.value as any })} className="w-full bg-black/40 border border-white/10 rounded-lg px-3 py-2 text-sm text-white focus:border-indigo-500 outline-none transition-all">
<option value="Active">Ativo</option>
<option value="Prospect">Prospect</option>
<option value="Inactive">Inativo</option>
</select>
</div>
</div>
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Email</label>
<input type="email" value={formData.email} onChange={e => setFormData({ ...formData, email: e.target.value })} className="w-full bg-black/40 border border-white/10 rounded-lg px-3 py-2 text-sm text-white focus:border-indigo-500 outline-none transition-all" />
</div>
<div>
<label className="block text-[10px] font-bold text-slate-500 uppercase mb-1">Cidade / Estado</label>
<input type="text" value={formData.city} onChange={e => setFormData({ ...formData, city: e.target.value })} className="w-full bg-black/40 border border-white/10 rounded-lg px-3 py-2 text-sm text-white focus:border-indigo-500 outline-none transition-all" />
</div>
<div className="flex gap-3 mt-8 pt-4 border-t border-white/5">
<button type="button" onClick={closeModal} className="flex-1 py-2 text-xs font-bold text-slate-400 hover:text-white transition-colors uppercase tracking-wide">Cancelar</button>
<button type="submit" className="flex-1 bg-indigo-600 hover:bg-indigo-500 text-white py-2 rounded-lg font-bold shadow-lg transition-all text-sm">Salvar</button>
</div>
</form>
</div>
</div>
)}
</div>
);
};
export default Customers;