"use client";
import type { RatioPoint, RatiosResponse } from "@/types/api";
import { fmtNumber, fmtPct } from "@/lib/format";
const BRASS = "#C2AA7A";
const GAIN = "#4F8C5E";
type Props = {
data: RatiosResponse;
};
type ValueKind = "multiple" | "percent" | "coverage";
function buildLine(values: (number | null)[], width: number, height: number): string {
const numeric = values.filter((value): value is number => value != null && Number.isFinite(value));
if (numeric.length === 0) return "";
if (numeric.length === 1) {
const y = height / 2;
return `0,${y} ${width},${y}`;
}
const min = Math.min(...numeric);
const max = Math.max(...numeric);
const range = max - min || 1;
return numeric
.map((value, index) => {
const x = (index / (numeric.length - 1)) * width;
const y = max === min ? height / 2 : height - ((value - min) / range) * height;
return `${x.toFixed(1)},${y.toFixed(1)}`;
})
.join(" ");
}
function fmtMultiple(value?: number | null): string {
if (value == null || Number.isNaN(value)) return "—";
return `${fmtNumber(value)}x`;
}
function fmtCoverage(value?: number | null): string {
if (value == null || Number.isNaN(value)) return "—";
return `${fmtNumber(value)}x`;
}
function formatValue(value: number | null, kind: ValueKind): string {
if (kind === "percent") return fmtPct(value);
if (kind === "coverage") return fmtCoverage(value);
return fmtMultiple(value);
}
function MiniSpark({ values, color }: { values: (number | null)[]; color: string }) {
const points = buildLine(values, 88, 24);
if (!points) {
return —;
}
return (
);
}
function HeroSpark({ values, color }: { values: (number | null)[]; color: string }) {
const points = buildLine(values, 196, 52);
if (!points) {
return No trend;
}
return (
);
}
function HeroCard({
label,
point,
kind,
color,
}: {
label: string;
point: RatioPoint;
kind: ValueKind;
color: string;
}) {
return (