diff --git a/src/components/buyer-tasks/buyer-task-group-card.test.tsx b/src/components/buyer-tasks/buyer-task-group-card.test.tsx
index 5744a1f..45dc136 100644
--- a/src/components/buyer-tasks/buyer-task-group-card.test.tsx
+++ b/src/components/buyer-tasks/buyer-task-group-card.test.tsx
@@ -206,4 +206,111 @@ describe("BuyerTaskGroupCard", () => {
screen.queryByTestId(`buyer-task-po-number-${baseGroup.groupId}`),
).toBeNull();
});
+
+ describe("po_sent sent-info caption", () => {
+ const sentEmail = "orders@acme.co.za";
+ const sentAt = "2026-08-05T13:23:00.000Z";
+
+ it("renders the recipient and send date under the buttons", () => {
+ render(
+ ,
+ );
+ const caption = screen.getByTestId(
+ `buyer-task-sent-info-${baseGroup.groupId}`,
+ );
+ expect(caption).toHaveTextContent(new RegExp(sentEmail.replace(/\./g, "\\.")));
+ expect(caption.textContent).toContain("Sent to");
+ // 5 Aug 2026 — en-GB short month, exact day.
+ expect(caption.textContent).toMatch(/5 Aug 2026/);
+ // Time is rendered in 24-hour HH:mm form.
+ expect(caption.textContent).toMatch(/\d{2}:\d{2}/);
+ });
+
+ it("hides the caption when emailPayload.sentAt is missing", () => {
+ render(
+ ,
+ );
+ expect(
+ screen.queryByTestId(`buyer-task-sent-info-${baseGroup.groupId}`),
+ ).toBeNull();
+ });
+
+ it("still renders the caption on mail_failed when sentAt is set", () => {
+ // The mail-failed banner explains the failure — the operator still
+ // wants to see who we tried and when, so the previous attempt's
+ // recipient/timestamp stays visible above the banner.
+ render(
+ ,
+ );
+ expect(
+ screen.getByTestId(`buyer-task-sent-info-${baseGroup.groupId}`),
+ ).toBeInTheDocument();
+ expect(screen.getByText(/mail failed/i)).toBeInTheDocument();
+ });
+
+ it("falls back to a bare 'Sent' label when the recipient is missing", () => {
+ render(
+ ,
+ );
+ const caption = screen.getByTestId(
+ `buyer-task-sent-info-${baseGroup.groupId}`,
+ );
+ expect(caption.textContent).not.toMatch(/Sent to/);
+ expect(caption.textContent).toMatch(/Sent\s+\d/);
+ });
+
+ it("does not render the caption on the po_draft tab", () => {
+ render(
+ ,
+ );
+ expect(
+ screen.queryByTestId(`buyer-task-sent-info-${baseGroup.groupId}`),
+ ).toBeNull();
+ });
+ });
});
diff --git a/src/components/buyer-tasks/buyer-task-group-card.tsx b/src/components/buyer-tasks/buyer-task-group-card.tsx
index bd23cd6..81a23b8 100644
--- a/src/components/buyer-tasks/buyer-task-group-card.tsx
+++ b/src/components/buyer-tasks/buyer-task-group-card.tsx
@@ -106,34 +106,67 @@ export function BuyerTaskGroupCard({
{group.step === "po_sent" ? (
- // PO Sent: two side-by-side buttons. Re-Send opens the resend modal
- // (reuses the SendPoModal wired up for po_draft on the parent page).
- // Mark as ready opens the MarkReadyDialog. The mail_failed override
- // now lands on the Re-Send button (the Mark as ready button stays
- // primary — collection can proceed independently of mail state).
-
-
-
+ // PO Sent: two side-by-side buttons + a small "sent info"
+ // caption below them showing who we sent the PO to and when.
+ // Re-Send opens the resend modal (reuses the SendPoModal
+ // wired up for po_draft on the parent page). Mark as ready
+ // opens the MarkReadyDialog. The mail_failed override now
+ // lands on the Re-Send button (the Mark as ready button
+ // stays primary — collection can proceed independently of
+ // mail state). The caption is hidden when there's no
+ // recorded `sentAt` (legacy rows predating email_payload,
+ // or a fresh po_draft that got flipped straight to
+ // po_sent without a successful send).
+