seahaven-ap/src/dashboard/invoice-date-format.ts
Adam Moussa c6867e6bec
feat(web): expand mock invoice fields and multi-line cells (AP-47) (#16)
* feat(web): fix shell chrome, logo home, and live nav badges

Refs: AP-42

* feat(web): add invoice grid lines and bold headers

Refs: AP-44

* feat(web): support auto row height for multi-line invoice cells

Refs: AP-44

* feat(web): expand mock invoice fields for Stampli column catalog

Refs: AP-47

* feat(web): add multi-line Stampli invoice cell renderers

Refs: AP-47

* fix(web): address review feedback

* ci: remove the pr policy caller

* fix(web): keep mock catalog dates and updates in sync

* fix(web): derive mock action labels from invoice status

* fix(ci): drop the unused catalog refresh index

* fix(ci): format invoice mock helpers
2026-09-25 21:51:59 +00:00

56 lines
1.5 KiB
TypeScript

function startOfLocalDay(date: Date): Date {
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
}
function formatUnit(count: number, unit: "day" | "month" | "year", future: boolean): string {
const noun = count === 1 ? unit : `${unit}s`;
return future ? `in ${count} ${noun}` : `${count} ${noun} ago`;
}
export function formatSlashDate(value: string | null | undefined): string {
if (!value) {
return "—";
}
const parsed = new Date(`${value.slice(0, 10)}T00:00:00`);
if (Number.isNaN(parsed.getTime())) {
return value;
}
return new Intl.DateTimeFormat("en-US", {
year: "numeric",
month: "2-digit",
day: "2-digit",
}).format(parsed);
}
export function formatRelativeFromIsoDate(
value: string | null | undefined,
now: Date = new Date(),
): string {
if (!value) {
return "";
}
const parsed = new Date(`${value.slice(0, 10)}T00:00:00`);
if (Number.isNaN(parsed.getTime())) {
return "";
}
const dayMs = 24 * 60 * 60 * 1000;
const days = Math.round(
(startOfLocalDay(now).getTime() - startOfLocalDay(parsed).getTime()) / dayMs,
);
if (days === 0) {
return "today";
}
const future = days < 0;
const absDays = Math.abs(days);
if (absDays < 30) {
return formatUnit(absDays, "day", future);
}
const months = Math.floor(absDays / 30);
if (months < 12) {
return formatUnit(months, "month", future);
}
const years = Math.floor(months / 12);
return formatUnit(years, "year", future);
}