diff --git a/src/lib/__tests__/format-date.test.ts b/src/lib/__tests__/format-date.test.ts new file mode 100644 index 0000000..6487bf7 --- /dev/null +++ b/src/lib/__tests__/format-date.test.ts @@ -0,0 +1,36 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; +import { formatRelativeTime } from "../format-date"; + +describe("formatRelativeTime", () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-06-17T12:00:00Z")); + }); + afterEach(() => { + vi.useRealTimers(); + }); + + it("returns 'just now' for < 45s", () => { + expect(formatRelativeTime("2026-06-17T11:59:30Z")).toBe("just now"); + }); + + it("returns '5m ago' for ~5 minutes", () => { + expect(formatRelativeTime("2026-06-17T11:55:00Z")).toBe("5m ago"); + }); + + it("returns '2h ago' for ~2 hours", () => { + expect(formatRelativeTime("2026-06-17T10:00:00Z")).toBe("2h ago"); + }); + + it("returns 'yesterday' for 1 day", () => { + expect(formatRelativeTime("2026-06-16T12:00:00Z")).toBe("yesterday"); + }); + + it("returns '3d ago' for 3 days", () => { + expect(formatRelativeTime("2026-06-14T12:00:00Z")).toBe("3d ago"); + }); + + it("returns MM/DD/YYYY for > 7 days", () => { + expect(formatRelativeTime("2026-06-01T12:00:00Z")).toBe("06/01/2026"); + }); +}); diff --git a/src/lib/format-date.ts b/src/lib/format-date.ts index bdd6d86..73a2de9 100644 --- a/src/lib/format-date.ts +++ b/src/lib/format-date.ts @@ -36,4 +36,28 @@ export function formatTime(date: string | Date | null | undefined): string { hour: "2-digit", minute: "2-digit", }); +} + +/** + * "Just now" / "5m ago" / "2h ago" / "yesterday" / "3d ago" / MM/DD/YYYY. + * + * Used by the v2 admin Orders list (CardList time-ago badge) and any + * other place that needs a humanized, glanceable timestamp without + * pulling in a date library. Buckets are deliberately coarse — anything + * past a week is shown as the absolute date (MM/DD/YYYY) via formatDate. + */ +export function formatRelativeTime(input: string | Date | number): string { + const date = input instanceof Date ? input : new Date(input); + if (isNaN(date.getTime())) return "—"; + const diffMs = Date.now() - date.getTime(); + const diffSec = Math.round(diffMs / 1000); + if (diffSec < 45) return "just now"; + const diffMin = Math.round(diffSec / 60); + if (diffMin < 60) return `${diffMin}m ago`; + const diffHr = Math.round(diffMin / 60); + if (diffHr < 24) return `${diffHr}h ago`; + const diffDay = Math.round(diffHr / 24); + if (diffDay === 1) return "yesterday"; + if (diffDay < 7) return `${diffDay}d ago`; + return formatDate(date); } \ No newline at end of file