From e76619ba3fa066df13bfb0aacb8a07eb59c19d01 Mon Sep 17 00:00:00 2001 From: Brian Schwartz Date: Thu, 16 Jul 2026 16:41:56 +0000 Subject: [PATCH] fix: stamp today's date when a job moves into applied without one normalizeJobForSection was defaulting date to an empty string whenever a job (e.g. a prospect) moved into applied with no date set, so many board cards never showed an applied date. Default to today's date instead, and treat any falsy date (not just undefined) as missing. Co-Authored-By: Claude Sonnet 5 --- app/api/__tests__/jobs.test.ts | 42 ++++++++++++++++++++++++++++++++-- app/api/jobs/route.ts | 2 +- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/app/api/__tests__/jobs.test.ts b/app/api/__tests__/jobs.test.ts index ed06bec..4883ca3 100644 --- a/app/api/__tests__/jobs.test.ts +++ b/app/api/__tests__/jobs.test.ts @@ -1,6 +1,6 @@ import { NextRequest } from "next/server"; -import { beforeEach, describe, expect, it, vi } from "vitest"; -import { POST } from "@/app/api/jobs/route"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { DELETE, POST } from "@/app/api/jobs/route"; import { readJobs, writeJobs } from "@/lib/jobs-repository"; import { generateAiSummary } from "@/lib/job-summary-server"; import type { JobsData } from "@/lib/jobs"; @@ -22,6 +22,14 @@ function request(body: unknown) { }); } +function deleteRequest(body: unknown) { + return new NextRequest("http://localhost/api/jobs", { + method: "DELETE", + body: JSON.stringify(body), + headers: { "Content-Type": "application/json" }, + }); +} + function emptyJobs(): JobsData { return { applied: [], prospect: [], local: [], staffing: [], passed: [], pending: [] }; } @@ -61,3 +69,33 @@ describe("POST /api/jobs", () => { })); }); }); + +describe("DELETE /api/jobs (move to applied)", () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2026-07-16T12:00:00Z")); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it("stamps today's date when a job with no date moves into applied", async () => { + vi.mocked(readJobs).mockResolvedValue({ + ...emptyJobs(), + prospect: [{ company: "Acme", role: "Designer", fit: "good", salary: "", notes: "", url: "" }], + }); + + const response = await DELETE(deleteRequest({ + section: "prospect", + company: "Acme", + role: "Designer", + targetSection: "applied", + })); + + expect(response.status).toBe(200); + expect(writeJobs).toHaveBeenCalledWith(expect.objectContaining({ + applied: [expect.objectContaining({ date: "2026-07-16" })], + })); + }); +}); diff --git a/app/api/jobs/route.ts b/app/api/jobs/route.ts index d13a2f0..f33e7d7 100644 --- a/app/api/jobs/route.ts +++ b/app/api/jobs/route.ts @@ -11,7 +11,7 @@ function normalizeJobForSection(job: AnyJob, targetSection: JobSection): AnyJob const normalized = { ...job }; if (targetSection === "applied") { if (!normalized.status) normalized.status = "applied"; - if (normalized.date === undefined) normalized.date = ""; + if (!normalized.date) normalized.date = new Date().toISOString().slice(0, 10); } else if (targetSection === "prospect" || targetSection === "local" || targetSection === "staffing") { if (!normalized.fit) normalized.fit = "good"; }