"use client";
/* The Team shell: one app bar, one tab row, one nav, four screens inside it.
*
* Approvals, Round, Ward and Raise are four views of the same job, and before this they were four
* separate screens with a back chevron and a two-item nav of their own — a manager with an empty
* queue could not reach any of them without typing the address. The tabs are real links to the
* routes that already existed, so the back button, a screen reader and the emailed approval link
* all keep working.
*
* Which tabs a reader gets comes from teamTabs() in lib/staffreq.ts, off the same two counts the
* tab badge is built from. That is the point of it living there: a tab drawn from one fact and a
* route fenced on another is a tab that 404s, which is exactly what this shell is here to stop.
*
* Review is deliberately NOT in here. It is a detail screen — it gets a back chevron, like the
* order, the thread and the request — because a decision screen with a tab row invites somebody to
* wander off it mid-decision.
*/
import Link from "next/link";
import { MBody, MONO, MRule, MTop } from "@/components/m";
import { INK, Kicker, SegmentLinks } from "@/components/staffui";
import StaffNav from "@/components/staffnav";
import { useStaff } from "@/lib/staffclient";
import { teamTabs, teamTitle } from "@/lib/staffreq";
/** A section band: the heading a list hangs off, with an optional mono note at the right.
*
* The four screens in this shell each had their own copy of this div. One of them is enough, and
* it is exported because the bands are the shell's own furniture as much as the tab row is. */
export function Band({ label, right, tone = "quiet" }: {
label: string; right?: React.ReactNode; tone?: "quiet" | "attention";
}) {
return (
);
}
/** The decision buttons that sit inside a row — Approve 3 / Open, Nudge / Collected, Sign.
*
* Not CompactAction: these share the width of the row between them (the mockup's `.decide .chip`,
* flex:1), where CompactAction is a fixed-width control sitting beside a block of text. Same 2px
* ink border, same uppercase label, 46px rather than the 44px floor. The small variant is the
* decline reasons — three across a phone, directly under the garment line they decline — and it
* sat at 42 until somebody measured it. Nothing anyone taps in this app goes under 44. */
export function ChipAction({ label, onClick, href, disabled, small }: {
label: string; onClick?: () => void; href?: string; disabled?: boolean;
/** Three across rather than two — the decline reasons, which are phrases rather than words. */
small?: boolean;
}) {
const st: React.CSSProperties = {
flex: 1, minWidth: 0, minHeight: small ? 44 : 46, padding: "0 10px", border: `2px solid ${INK}`, borderRadius: 0,
background: "#fff", color: INK, font: "inherit", fontSize: small ? 13 : 15, fontWeight: 800,
lineHeight: 1.25,
display: "flex", alignItems: "center", justifyContent: "center", textAlign: "center",
textDecoration: "none", cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.45 : 1,
};
// A Link, not an anchor: a full page load on "Open" or "Nudge" throws away the list the reader
// is standing in and re-fetches the whole screen on ward wifi.
if (href && !disabled) return {label};
return ;
}
/** The row of decision buttons. */
export function ChipRow({ children }: { children: React.ReactNode }) {
return
{children}
;
}
export default function Team({ active, children, foot }: {
/** The href of the tab being shown, so the segment row can mark it. */
active: string;
children: React.ReactNode;
/** Anything that belongs below the scrolling body and above the nav — Round's "sign for all",
* Raise's send bar. Bars cannot live inside MBody or they scroll away with the list. */
foot?: React.ReactNode;
}) {
const { me, counts } = useStaff();
const tabs = teamTabs(me, counts);
const single = tabs.length === 1 ? tabs[0] : null;
return (
<>
{/* One tab is not a choice, and a single inverted button that does nothing when pressed is
a control that lies. A clerk who only signs for the trolley gets the band instead — and
no tabs at all draws nothing, rather than an empty
{foot}
>
);
}