feat(frontend): wire Vite app to FastAPI parser with NDJSON streaming + Upload page
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
const usd = new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
maximumFractionDigits: 0,
|
||||
});
|
||||
|
||||
const usdPrecise = new Intl.NumberFormat("en-US", {
|
||||
style: "currency",
|
||||
currency: "USD",
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
|
||||
const number = new Intl.NumberFormat("en-US");
|
||||
|
||||
const date = new Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
const dateShort = new Intl.DateTimeFormat("en-US", {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
const time = new Intl.DateTimeFormat("en-US", {
|
||||
hour: "numeric",
|
||||
minute: "2-digit",
|
||||
});
|
||||
|
||||
const relative = new Intl.RelativeTimeFormat("en-US", { numeric: "auto" });
|
||||
|
||||
/**
|
||||
* Coerce a backend Decimal-serialized value (string) or a number to a finite
|
||||
* number. Returns the supplied fallback (default 0) on null/undefined/NaN.
|
||||
* Used everywhere the FastAPI `Decimal` field needs to flow into a UI that
|
||||
* expects `number`.
|
||||
*/
|
||||
export const toNum = (v: string | number | null | undefined, fallback = 0): number => {
|
||||
if (v === null || v === undefined) return fallback;
|
||||
const n = typeof v === "number" ? v : Number(v);
|
||||
return Number.isFinite(n) ? n : fallback;
|
||||
};
|
||||
|
||||
export const fmt = {
|
||||
usd: (n: number) => usd.format(n),
|
||||
usdPrecise: (n: number) => usdPrecise.format(n),
|
||||
usdDecimal: (v: string | number | null | undefined) =>
|
||||
usdPrecise.format(toNum(v)),
|
||||
num: (n: number) => number.format(n),
|
||||
date: (iso: string) => date.format(new Date(iso)),
|
||||
dateShort: (iso: string) => dateShort.format(new Date(iso)),
|
||||
time: (iso: string) => time.format(new Date(iso)),
|
||||
pct: (n: number, digits = 1) => `${n.toFixed(digits)}%`,
|
||||
relative: (iso: string) => {
|
||||
const ms = new Date(iso).getTime() - Date.now();
|
||||
const minutes = Math.round(ms / 60_000);
|
||||
if (Math.abs(minutes) < 60) return relative.format(minutes, "minute");
|
||||
const hours = Math.round(minutes / 60);
|
||||
if (Math.abs(hours) < 24) return relative.format(hours, "hour");
|
||||
const days = Math.round(hours / 24);
|
||||
if (Math.abs(days) < 7) return relative.format(days, "day");
|
||||
return fmt.date(iso);
|
||||
},
|
||||
};
|
||||
Reference in New Issue
Block a user