diff --git a/src/components/buyer-tasks/buyer-task-group-card.test.tsx b/src/components/buyer-tasks/buyer-task-group-card.test.tsx new file mode 100644 index 0000000..0ad2182 --- /dev/null +++ b/src/components/buyer-tasks/buyer-task-group-card.test.tsx @@ -0,0 +1,63 @@ +import { describe, it, expect, vi } from "vitest"; +import { render, screen, fireEvent } from "@testing-library/react"; +import { BuyerTaskGroupCard } from "./buyer-task-group-card"; + +const baseGroup = { + groupId: "order-1::sup-1", + orderId: "order-1", + orderNumber: "ORD-001", + supplierId: "sup-1", + supplierName: "Steel Co", + customerName: "J. Smith", + companyName: "Acme", + items: [ + { id: "item-1", description: "HSS drill", quantity: 2, costPrice: 25, sellingPrice: 50 }, + ], + itemCount: 1, + totalCost: 50, + purchaseOrderId: null, + poStatus: null, + step: "needs_po" as const, +}; + +describe("BuyerTaskGroupCard", () => { + it("renders order, supplier, customer info", () => { + render(); + expect(screen.getByText("ORD-001")).toBeInTheDocument(); + expect(screen.getByText("Steel Co")).toBeInTheDocument(); + expect(screen.getByText("J. Smith", { exact: true })).toBeInTheDocument(); + expect(screen.getByText("Acme", { exact: true })).toBeInTheDocument(); + }); + + it("renders the right action button per step", () => { + const cases: Array<{ step: "needs_po" | "po_draft" | "po_sent"; label: RegExp }> = [ + { step: "needs_po", label: /generate po/i }, + { step: "po_draft", label: /send po/i }, + { step: "po_sent", label: /mark as ready/i }, + ]; + for (const { step, label } of cases) { + const { unmount } = render( + + ); + expect( + screen.getByTestId(`buyer-task-action-${baseGroup.groupId}-${step}`) + ).toHaveTextContent(label); + unmount(); + } + }); + + it("calls onAction when the button is clicked", () => { + const onAction = vi.fn(); + render(); + fireEvent.click( + screen.getByTestId(`buyer-task-action-${baseGroup.groupId}-${baseGroup.step}`) + ); + expect(onAction).toHaveBeenCalledWith(baseGroup); + }); + + it("renders the items list", () => { + render(); + fireEvent.click(screen.getByTestId("buyer-task-items-toggle")); + expect(screen.getByText("HSS drill")).toBeInTheDocument(); + }); +}); diff --git a/src/components/buyer-tasks/buyer-task-group-card.tsx b/src/components/buyer-tasks/buyer-task-group-card.tsx new file mode 100644 index 0000000..54e4400 --- /dev/null +++ b/src/components/buyer-tasks/buyer-task-group-card.tsx @@ -0,0 +1,60 @@ +"use client"; + +import { Card, CardContent } from "@/components/ui/card"; +import { Button } from "@/components/ui/button"; +import { BuyerTaskItemsList, type BuyerTaskItem } from "./buyer-task-items-list"; +import type { BuyerTaskGroup } from "@/lib/server/buyer-tasks-service"; + +const ACTION_LABEL: Record = { + needs_po: "Generate PO", + po_draft: "Send PO", + po_sent: "Mark as ready", +}; + +const ACTION_CLASS: Record = { + needs_po: "bg-blue-600 hover:bg-blue-700 text-white", + po_draft: "bg-amber-500 hover:bg-amber-600 text-white", + po_sent: "bg-purple-600 hover:bg-purple-700 text-white", +}; + +export function BuyerTaskGroupCard({ + group, + onAction, + disabled, +}: { + group: BuyerTaskGroup; + onAction: (group: BuyerTaskGroup) => void; + disabled?: boolean; +}) { + return ( + + + + + + {group.orderNumber} + · + {group.supplierName} + + + {group.customerName} · {group.companyName} + + + {group.itemCount} item{group.itemCount === 1 ? "" : "s"} · Cost R{group.totalCost.toFixed(2)} + + + onAction(group)} + disabled={disabled} + className={ACTION_CLASS[group.step]} + data-testid={`buyer-task-action-${group.groupId}-${group.step}`} + > + {ACTION_LABEL[group.step]} + + + + + + ); +} diff --git a/src/test-setup.ts b/src/test-setup.ts index 9a41425..4110b52 100644 --- a/src/test-setup.ts +++ b/src/test-setup.ts @@ -1 +1,7 @@ -import "@testing-library/jest-dom/vitest"; \ No newline at end of file +import "@testing-library/jest-dom/vitest"; +import { afterEach } from "vitest"; +import { cleanup } from "@testing-library/react"; + +afterEach(() => { + cleanup(); +}); \ No newline at end of file