Overhaul the app's color system by replacing all hardcoded Tailwind color classes with semantic theme variables to ensure consistent theming across all components, pages, and tests. Additional changes: - Add assigned date support for order item status updates: add `assignedDate` field to the order item status PATCH API, implement server-side normalization/validation, and add corresponding tests - Refactor purchase order PDF workflows to use the consolidated `purchase_orders.documents` field instead of the legacy separate `purchase_order_pdfs` collection - Fix quote number parsing and formatting to support both dashed (Q-YYYY-MM-NNN) and dashless (QYYYYMMNNN) formats - Rename `driver_pool` item status to `collection_pool` across the codebase - Add null handling for order item quantities and pricing to display "—" for missing values - Improve filter tab styling: make mobile tabs scrollable, prevent text wrapping, hide scrollbar - Add new utility scripts, API routes, migrations, and polish small UI/UX fixes including tsconfig updates and theme hook improvements
75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import { describe, it, expect } from "vitest";
|
|
import { quoteStatusClassName, formatQuoteStatus } from "./quote-status";
|
|
|
|
describe("quoteStatusClassName", () => {
|
|
it("returns a styled class string for known statuses", () => {
|
|
const cls = quoteStatusClassName("new");
|
|
expect(cls).toContain("border-info");
|
|
expect(cls).toContain("bg-info");
|
|
});
|
|
|
|
it("returns a fallback class for unknown statuses", () => {
|
|
const cls = quoteStatusClassName("not_a_real_status");
|
|
expect(cls).toContain("border-muted");
|
|
expect(cls).toContain("bg-muted");
|
|
});
|
|
|
|
it("supports every documented quote status", () => {
|
|
const statuses = [
|
|
"new",
|
|
"claimed",
|
|
"processed",
|
|
"emailed",
|
|
"approval_pending",
|
|
"approved",
|
|
"rejected",
|
|
"problem",
|
|
"complete",
|
|
"cancelled",
|
|
"follow_up",
|
|
"email_failed",
|
|
"unmatched_bounce",
|
|
"template",
|
|
"sending",
|
|
"mail_failed",
|
|
];
|
|
for (const s of statuses) {
|
|
const cls = quoteStatusClassName(s);
|
|
// Every known status must produce a border-using class so the
|
|
// pill has visual weight. The neutral `cancelled` shares the
|
|
// muted fallback on purpose (it's terminal — no semantic
|
|
// colour needed); everything else must produce its own map
|
|
// entry.
|
|
expect(cls, `class for ${s}`).toMatch(/border-/);
|
|
if (s !== "cancelled") {
|
|
expect(
|
|
cls,
|
|
`class for ${s}`,
|
|
).not.toContain("border-muted bg-muted text-muted-foreground");
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
describe("formatQuoteStatus", () => {
|
|
it("uses workflow-friendly labels for email-status enums", () => {
|
|
expect(formatQuoteStatus("email_failed")).toBe("Email failed");
|
|
expect(formatQuoteStatus("mail_failed")).toBe("Mail failed");
|
|
expect(formatQuoteStatus("unmatched_bounce")).toBe("Unmatched bounce");
|
|
});
|
|
|
|
it("renders workflow-friendly labels for the merged tabs", () => {
|
|
expect(formatQuoteStatus("approval_pending")).toBe("Pending approval");
|
|
expect(formatQuoteStatus("emailed")).toBe("Awaiting reply");
|
|
expect(formatQuoteStatus("sending")).toBe("Sending…");
|
|
expect(formatQuoteStatus("follow_up")).toBe("Follow up");
|
|
});
|
|
|
|
it("leaves single-word and terminal statuses unchanged", () => {
|
|
expect(formatQuoteStatus("new")).toBe("new");
|
|
expect(formatQuoteStatus("complete")).toBe("complete");
|
|
expect(formatQuoteStatus("cancelled")).toBe("cancelled");
|
|
expect(formatQuoteStatus("rejected")).toBe("rejected");
|
|
expect(formatQuoteStatus("claimed")).toBe("claimed");
|
|
});
|
|
});
|