'use client'; import { useState, useEffect, useCallback } from 'react'; import type { Customer } from '@/types'; import { customersApi } from '@/lib/api-client'; const PAGE_SIZE = 20; // ── Modal genérico ──────────────────────────────────────────────────────────── function Modal({ title, onClose, children }: { title: string; onClose: () => void; children: React.ReactNode }) { return (
e.stopPropagation()}>

{title}

{children}
); } // ── Formulario crear cliente ───────────────────────────────────────────────── function CreateForm({ onClose, onCreated }: { onClose: () => void; onCreated: () => void }) { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [displayName, setDisplayName] = useState(''); const [phone, setPhone] = useState(''); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); const handle = async (e: React.FormEvent) => { e.preventDefault(); setSaving(true); setError(''); try { await customersApi.create({ email, password, displayName: displayName || undefined, phone: phone || undefined }); onCreated(); onClose(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al crear cliente'); } finally { setSaving(false); } }; return (
setEmail(e.target.value)} required className="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none" />
setPassword(e.target.value)} required minLength={8} className="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none" />
setDisplayName(e.target.value)} placeholder="Opcional" className="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none" />
setPhone(e.target.value)} placeholder="+34 600 000 000" className="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none" />
{error &&

{error}

}
); } // ── Formulario editar cliente ──────────────────────────────────────────────── function EditForm({ customer, onClose, onSaved }: { customer: Customer; onClose: () => void; onSaved: () => void }) { const [displayName, setDisplayName] = useState(''); const [phone, setPhone] = useState(''); const [saving, setSaving] = useState(false); const [error, setError] = useState(''); useEffect(() => { setDisplayName(customer.displayName || ''); setPhone(customer.phone || ''); }, [customer]); const handle = async (e: React.FormEvent) => { e.preventDefault(); setSaving(true); setError(''); try { await customersApi.update(customer.id, { displayName: displayName || undefined, phone: phone || undefined, }); onSaved(); onClose(); } catch (err) { setError(err instanceof Error ? err.message : 'Error al guardar'); } finally { setSaving(false); } }; return (
setDisplayName(e.target.value)} className="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none" />
setPhone(e.target.value)} placeholder="+34 600 000 000" className="w-full px-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] outline-none" />
{error &&

{error}

}
); } // ── Página principal ─────────────────────────────────────────────────────────── export default function CustomersPage() { const [customers, setCustomers] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [search, setSearch] = useState(''); const [debounced, setDebounced] = useState(''); const [page, setPage] = useState(0); const [total, setTotal] = useState(0); const [showCreate, setShowCreate] = useState(false); const [editing, setEditing] = useState(null); const [msg, setMsg] = useState(''); useEffect(() => { const t = setTimeout(() => setDebounced(search), 400); return () => clearTimeout(t); }, [search]); useEffect(() => { setPage(0); }, [debounced]); const load = useCallback(async () => { setLoading(true); setError(''); try { const data = await customersApi.list({ limit: PAGE_SIZE, offset: page * PAGE_SIZE, q: debounced || undefined }); setCustomers(data.items ?? []); setTotal(data.total ?? 0); } catch (e) { setError(e instanceof Error ? e.message : 'Error'); } finally { setLoading(false); } }, [page, debounced]); useEffect(() => { load(); }, [load]); const handleCreated = () => { setMsg('Cliente creado correctamente'); setTimeout(() => setMsg(''), 3000); load(); }; const handleSaved = () => { setMsg('Cliente actualizado'); setTimeout(() => setMsg(''), 3000); load(); }; return (
{/* Header */}

Clientes

{total > 0 ? `${total} cliente${total !== 1 ? 's' : ''}` : ''}

{msg && (
{msg}
)} {/* Buscador */}
setSearch(e.target.value)} className="w-full pl-10 pr-4 py-2.5 border border-gray-300 rounded-xl text-sm focus:ring-2 focus:ring-[#2D6A4F] focus:border-transparent outline-none" />
{/* Tabla */}
{loading ? (
Cargando...
) : error ? (

{error}

) : customers.length === 0 ? (

👥

No hay clientes

) : ( <> {['Email', 'Nombre', 'Teléfono', 'Rol', 'Alta', ''].map((h) => ( ))} {customers.map((c) => ( ))}
{h}
{c.email} {c.displayName || '—'} {c.phone || '—'} {c.role} {c.createdAt ? new Date(c.createdAt).toLocaleDateString('es-ES') : '—'}
{/* Paginación */}

Página {page + 1}

)}
{/* Modal crear */} {showCreate && ( setShowCreate(false)}> setShowCreate(false)} onCreated={handleCreated} /> )} {/* Modal editar */} {editing && ( setEditing(null)}> setEditing(null)} onSaved={handleSaved} /> )}
); }