import { useState } from 'react' import { api } from '../bridge.js' import { usePolled, fmtDate } from '../hooks.js' import * as Icon from '../ui/icons.jsx' import CustomerForm from './CustomerForm.jsx' // The customer database, and the form staff fill in when someone walks in. export default function Customers({ session }) { const [query, setQuery] = useState('') const [selected, setSelected] = useState(null) const { data, error, reload } = usePolled( () => api.customers(query, 200), 30000, [query]) const rows = data ?? [] const named = rows.filter(r => r.has_profile).length return (

Customers

Everyone this business has recognised. Fill in details once and they are known at every store.

{error &&
{error}
}
r.visit_count > 1).length || '—'} /> r.has_consent).length || '—'} />
{rows.length === 0 ?
No customers yet

They appear here the first time a camera recognises them. Click one to add a name and phone number.

:
{rows.map(c => ( setSelected(c)}> ))}
CustomerPhone Visits First seenLast seenDetails
{c.full_name || {c.label}} {/* Only beside a name a human typed: the auto label already IS the number ("Visitor 13"), so showing both reads as two identifiers for one person. */} {c.full_name && c.ref && · {c.ref}} {c.phone || '—'} {c.visit_count} {fmtDate(c.first_seen_at)} {fmtDate(c.last_seen_at)} {c.has_profile ? captured : needed}
}
{selected && ( setSelected(null)} onSaved={() => { setSelected(null); reload() }} /> )}
) } function Metric({ k, v, s }) { return (
{k}
{v}
{s &&
{s}
}
) }