Improve workforce scanning, site transfers and timesheet exports. Audit plant imports, duplicate identities, rates and dashboard totals. Repair delivery PO selection, periodic rechecks and receiving guards. Align financial ledgers, supplier periods and mobile layouts. Add the site map preview, shared theme controls and audit evidence. Verify 3,455 application tests, six fuel export tests, TypeScript and an optimized production build. Clean up a leaked test timer and keep local worktrees and generated reports out of ESLint traversal. Changed-file lint passes; repository-wide lint retains 33 existing errors in unchanged files.
24 lines
1.1 KiB
TypeScript
24 lines
1.1 KiB
TypeScript
import { format } from "date-fns";
|
||
import type { ProgressState } from "@/lib/site-map-v2/progress";
|
||
|
||
export const fmt = (n: number) => (Number.isInteger(n) || Math.abs(n) >= 100 ? Math.round(n).toLocaleString() : n.toFixed(1));
|
||
export const hex = (c: number) => `#${c.toString(16).padStart(6, "0")}`;
|
||
export const km = (ch: number) => (ch / 1000).toFixed(3);
|
||
export const sectionLabel = (from: number, to: number) => `km ${km(from)}–${km(to)}`;
|
||
|
||
/** "Last change: Johan, 14 Oct 09:12" for an item, or null if it was never changed. */
|
||
export function lastChange(state: ProgressState, key: string): string | null {
|
||
const e = state[key];
|
||
if (!e) return null;
|
||
const d = new Date(e.created.replace(" ", "T"));
|
||
return `Last change: ${e.user_name || "unknown"}, ${Number.isNaN(d.getTime()) ? e.created : format(d, "d MMM HH:mm")}`;
|
||
}
|
||
|
||
export function download(name: string, text: string, type: string) {
|
||
const a = document.createElement("a");
|
||
a.href = URL.createObjectURL(new Blob([text], { type }));
|
||
a.download = name;
|
||
a.click();
|
||
setTimeout(() => URL.revokeObjectURL(a.href), 1000);
|
||
}
|
||
export const csvCell = (v: unknown) => `"${String(v).replace(/"/g, '""')}"`;
|