feat(roadmap): checklist-derived completion percentage

This commit is contained in:
Dave 2026-09-17 07:16:57 +02:00
parent 1c24687dae
commit b164f3273c
2 changed files with 49 additions and 0 deletions

View file

@ -0,0 +1,32 @@
import { describe, it, expect } from "vitest";
import { checklistPercent } from "@/lib/roadmap/progress";
describe("checklistPercent", () => {
it("returns null when there is no checklist", () => {
// A card with no subtasks has no honest completion figure. Showing 0%
// would claim nothing has been done, which is a different statement.
expect(checklistPercent(0, 0)).toBeNull();
});
it("computes a whole percentage", () => {
expect(checklistPercent(3, 4)).toBe(75);
expect(checklistPercent(1, 3)).toBe(33);
});
it("returns 0 for an untouched checklist", () => {
expect(checklistPercent(0, 5)).toBe(0);
});
it("returns 100 for a complete one", () => {
expect(checklistPercent(5, 5)).toBe(100);
});
it("clamps impossible input rather than exceeding 100", () => {
expect(checklistPercent(9, 5)).toBe(100);
expect(checklistPercent(-1, 5)).toBe(0);
});
it("returns null for a negative total", () => {
expect(checklistPercent(0, -3)).toBeNull();
});
});

View file

@ -0,0 +1,17 @@
/**
* Checklist completion for a card.
*
* The per-row percentage from the developer's Gantt reference, mapped onto the
* one thing in this product that honestly supports it: subtasks the developer
* ticked themselves. Nothing is inferred.
*
* Returns null rather than 0 for a card with no checklist. "0%" asserts that
* nothing has been done; "no figure" says nobody has broken this down. They are
* different statements and the second one is true.
*/
export function checklistPercent(done: number, total: number): number | null {
if (!Number.isFinite(total) || total <= 0) return null;
const completed = Math.min(Math.max(done, 0), total);
return Math.round((completed / total) * 100);
}