"use client"; /* Delivery round — everything waiting, grouped by ward, handed over on the floor with a signature. Reuses the same signature pad and photo upload as the desktop, so a handover looks identical in the record whichever screen recorded it. */ import { useMemo, useRef, useState } from "react"; import { useSnap } from "@/lib/client"; import { daysBetween, itemMap, label, staffMap, staffName, type PickupRec } from "@/lib/compute"; import { uploadPhoto } from "@/lib/photo"; import { SignaturePad } from "@/components/dialogs"; import { INK, MBar, MBody, MEmpty, MError, MNav, MRow, MRule, MSection, MTop, inputStyle } from "@/components/m"; export default function MRounds() { const { s, mutate, busy } = useSnap(); const [pick, setPick] = useState(null); const [name, setName] = useState(""); const [err, setErr] = useState(""); const [saving, setSaving] = useState(false); const pad = useRef<{ clear: () => void; dataUrl: () => string | null } | null>(null); const byId = useMemo(() => itemMap(s), [s]); const staffById = useMemo(() => staffMap(s), [s]); /* Grouped by ward — a round is walked ward by ward, not order by order. */ const wards = useMemo(() => { const m: Record = {}; for (const p of s.pickups) { if (p.pickedUp) continue; const w = staffById[p.staffId]?.dept || "No ward recorded"; (m[w] ||= []).push(p); } return Object.entries(m).sort((a, b) => a[0].localeCompare(b[0])); }, [s, staffById]); const items = (p: PickupRec) => p.lines.map((l) => `${label(byId[l.itemId])} ${l.size}${l.qty > 1 ? ` ×${l.qty}` : ""}`).join(", "); const deliver = async () => { if (!pick || saving) return; setSaving(true); setErr(""); let sigId: string | null = null; const png = pad.current?.dataUrl() || null; if (png) { const up = await uploadPhoto(mutate, "sig", png); if ("error" in up) { setSaving(false); setErr(up.error); return; } sigId = up.id; } const r = await mutate("pickup.deliver", { id: pick.id, deliveredTo: name.trim(), sigId }); setSaving(false); if (!r.ok) { setErr(r.error); return; } setPick(null); setName(""); }; const total = wards.reduce((t, [, ps]) => t + ps.length, 0); if (pick) { const st = staffById[pick.staffId]; return ( <> setPick(null)} right={st?.dept || undefined} /> setErr("")} />
{pick.orderCode}
{staffName(st, "Staff member")}
{items(pick)}
setName(e.target.value)} placeholder="Name of whoever signs, e.g. the manager" aria-label="Received by" style={inputStyle} />
Signature
{ pad.current = api; }} />

Handing over records the garments as collected — the same as a pickup at the counter — and keeps the name and signature with the record.

); } return ( <> {total === 0 ? ( ) : wards.map(([ward, ps]) => (
{ps.map((p) => { const st = staffById[p.staffId]; const days = daysBetween(p.received, s.today); return ( { setPick(p); setName(""); }} mark={days > 10 ? "accent" : "ink"} attention={days > 10} title={staffName(st, "Staff member")} sub={`${items(p)} · waiting ${days}d`} right={Sign} /> ); })}
))}
); }