'use client'; import { useCallback, useEffect, useState } from 'react'; import { Badge } from '@/components/ui'; import { t } from '@/lib/i18n'; import { formatDate } from '@/lib/utils'; type Customer = { id: string; name: string; email: string; company: string | null; status: string; createdAt: string }; type ListResponse = { items: Customer[]; total: number; page: number; pageSize: number; pages: number }; type FormState = { name: string; email: string; company: string; status: string }; const EMPTY: FormState = { name: '', email: '', company: '', status: 'active' }; const STATUSES = ['active', 'lead', 'churned']; const tone = (status: string) => (status === 'active' ? 'success' : status === 'churned' ? 'danger' : 'warning'); export function CustomersManager({ canWrite, canDelete }: { canWrite: boolean; canDelete: boolean }) { const [items, setItems] = useState([]); const [meta, setMeta] = useState({ page: 1, pages: 1, total: 0 }); const [searchInput, setSearchInput] = useState(''); const [search, setSearch] = useState(''); const [status, setStatus] = useState(''); const [sort, setSort] = useState('newest'); const [page, setPage] = useState(1); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [form, setForm] = useState(null); const [editingId, setEditingId] = useState(null); const [formError, setFormError] = useState(null); const [busy, setBusy] = useState(false); const load = useCallback(async () => { setLoading(true); setError(null); const params = new URLSearchParams({ page: String(page), pageSize: '10', sort }); if (search) params.set('q', search); if (status) params.set('status', status); try { const res = await fetch(`/api/admin/customers?${params.toString()}`); if (!res.ok) throw new Error('request failed'); const data = (await res.json()) as ListResponse; setItems(data.items); setMeta({ page: data.page, pages: data.pages, total: data.total }); } catch { setError(t('common.error')); } finally { setLoading(false); } }, [page, sort, search, status]); useEffect(() => { void load(); }, [load]); function openCreate() { setEditingId(null); setFormError(null); setForm({ ...EMPTY }); } function openEdit(c: Customer) { setEditingId(c.id); setFormError(null); setForm({ name: c.name, email: c.email, company: c.company ?? '', status: c.status }); } async function submit(event: React.FormEvent) { event.preventDefault(); if (!form) return; setBusy(true); setFormError(null); const res = await fetch(editingId ? `/api/admin/customers/${editingId}` : '/api/admin/customers', { method: editingId ? 'PATCH' : 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(form), }); setBusy(false); if (!res.ok) { setFormError(((await res.json().catch(() => ({}))) as { error?: string }).error || t('common.error')); return; } setForm(null); setEditingId(null); await load(); } async function remove(c: Customer) { if (!window.confirm(`${t('admin.delete')} “${c.name}”? This cannot be undone.`)) return; setBusy(true); await fetch(`/api/admin/customers/${c.id}`, { method: 'DELETE' }); setBusy(false); await load(); } return (

{t('admin.customers')}

{meta.total} records

{canWrite && ( )}
{!canWrite &&

{t('admin.readOnly')}

}
{ e.preventDefault(); setPage(1); setSearch(searchInput.trim()); }} >
{form && (

{editingId ? t('admin.editCustomer') : t('admin.newCustomer')}

{formError &&

{formError}

}
)} {error &&

{error}

} {loading ? (

{t('common.loading')}

) : items.length === 0 ? (

{t('admin.empty')}

) : ( <>
{(canWrite || canDelete) && } {items.map((c) => ( {(canWrite || canDelete) && ( )} ))}
{t('admin.name')} {t('admin.email')} {t('admin.company')} {t('admin.status')} {t('admin.created')}{t('admin.actions')}
{c.name} {c.email} {c.company || t('admin.none')} {t(`admin.${c.status}`)} {formatDate(c.createdAt)}
{canWrite && ( )} {canDelete && ( )}
{t('admin.pageOf', { page: meta.page, pages: meta.pages })}
)}
); }