import { useEffect, useState } from 'react' import { api } from '../bridge.js' // The customer's face, when there is one. // // Fetched when the sheet opens rather than stored with the customer row: the // server hands out a signed link that expires in minutes, deliberately, so // that "delete my data" can actually make a picture stop loading. A link kept // in a list rendered an hour ago is a broken image. // // The fetch lives in a hook and happens ONCE per sheet, because the server // writes an audit_log row for every read of a face image — "who looked at my // customers" has to be answerable — and a component that fetched its own copy // for the picture and again for the caption would put two rows in that log for // one glance at one person. export function useCustomerPhoto(id) { const [photo, setPhoto] = useState(null) useEffect(() => { let alive = true setPhoto(null) api.visitorPhoto(id) .then(p => { if (alive) setPhoto(p) }) // A failure to load a photo must never take the customer record with // it: the name and phone number are what staff opened this for. .catch(() => { if (alive) setPhoto({ available: false, reason: '' }) }) return () => { alive = false } }, [id]) return photo } // No photo is the normal case — images are off by default — so this renders // initials, not an error. export default function CustomerPhoto({ photo, name, customerRef, onBroken }) { if (photo?.available) { return {`Photo } return (
{avatarText(name, customerRef)}
) } // Initials of a name a human typed; the NUMBER for a customer the system named // itself. Taking the first letter of each word of "Visitor 13" gives "V1" — // which is also what "Visitor 10" and "Visitor 15" give, so three different // people wear the same badge, and it reads as the V-1 reference for a fourth. // Same fix as the web app's arrivals feed; the two must not disagree. // // customerRef, not `ref`: React reserves that prop name and it would never // reach this component. function avatarText(name, customerRef) { const auto = /^Visitor (\d+)$/.exec(String(name || '').trim()) if (auto) return auto[1] const n = /^V-(\d+)$/.exec(String(customerRef || '')) if (n) return n[1] return String(name || '').split(/\s+/).filter(Boolean).slice(0, 2) .map(w => w[0].toUpperCase()).join('') || '?' }