"use client"; import { useState } from "react"; import { LiveRegion } from "@/components/ui"; import { Panel } from "@/components/portal"; import { useSnap } from "@/lib/client"; import { fmtDate, money } from "@/lib/compute"; import { HeadActions, PanelEmpty, TableWrap, TOTAL, plural } from "./bits"; import type { ReportData } from "./useReportData"; function SubHead({ children }: { children: React.ReactNode }) { return

{children}

; } /* The yearly figure is a reporting number, not a limit, so it lives here and nowhere else. */ function YearlyFigure() { const { s, isAdmin, busy, mutate } = useSnap(); const [editing, setEditing] = useState(false); const [val, setVal] = useState(""); const [msg, setMsg] = useState<{ text: string; err: boolean } | null>(null); const current = s.settings.defaultEntitlement; async function save() { const n = Number(val); if (!Number.isInteger(n) || n < 0) { setMsg({ text: "Enter a whole number, 0 or more.", err: true }); return; } const r = await mutate("settings.update", { defaultEntitlement: n }); if (!r.ok) { setMsg({ text: r.error, err: true }); return; } setEditing(false); setMsg({ text: "Saved.", err: false }); } return (
{!editing ? ( <> Yearly figure for reports · {current} garments per person {isAdmin && } ) : (
{ e.preventDefault(); void save(); }}> setVal(e.target.value)} style={{ width: 90 }} autoFocus /> garments per person
)}
); } export default function PeopleTab({ d }: { d: ReportData }) { const { R, mLbl, csv, print } = d; return (
0} aside={threshold {R.excThreshold} items/month} onCsv={csv.exceptions} onPrint={print.exceptions} />}> {R.excRows.length === 0 ? No exceptions in {mLbl}. : ( StaffGroupCost centreItems (month)Items (FY)Flag {R.excRows.map((r, i) => {r.who}{r.group}{r.cc || "—"}{r.mQty}{r.fyQty}{r.flags.map((f, j) => {f})})} )} 0} aside={ 0 ? `${plural(R.apprTot, "set")} outstanding` : undefined} onCsv={csv.approvals} onPrint={print.approvals} />}> {R.apprRows.length === 0 ? No uncollected approvals. : ( StaffWardApproved byDateSets approvedCollectedRemaining {R.apprRows.map((r, i) => {r.who}{r.dept}{r.by}{fmtDate(r.date)}{r.sets}{r.used}{r.rem})} TOTAL OUTSTANDING{R.apprTot} )} saved {money(R.plSaved)}} onCsv={csv.preloved} onPrint={print.preloved} />}>

Issued free · {R.plQty}

{R.plIssueRows.length === 0 ? Nothing issued from the pool in {mLbl}. : ( DateStaffItemSizeQtyValue saved {R.plIssueRows.map((r, i) => {fmtDate(r.date)}{r.who}{r.item}{r.size}{r.qty}{money(r.saved)})} )} Hand-ins · {R.ragMonth} to rag {R.hiRows.length === 0 ? No hand-ins in {mLbl}. : ( DateStaffReceived byGoodRagAllowance {R.hiRows.map((r, i) => {fmtDate(r.date)}{r.who}{r.by}{r.good}{r.rag}{r.credit})} )} Pool today · {R.plPoolTotal} at $0 {R.plPoolRows.length === 0 ? The pool is empty. : ( ItemSizes on handTotal {R.plPoolRows.map((r, i) => {r.item}{r.sizes}{r.total})} )}
); }