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). +
+
+ + +
+ {group.emailPayload?.sentAt ? ( +
+ {group.emailPayload.to ? ( + + Sent to {group.emailPayload.to} + + + ) : ( + Sent + )} + + {new Date(group.emailPayload.sentAt).toLocaleString("en-GB", { + day: "numeric", + month: "short", + year: "numeric", + hour: "2-digit", + minute: "2-digit", + hour12: false, + })} + +
+ ) : null}
) : ( // needs_po / po_draft: single button (unchanged behaviour).