import { kpiDeltaView } from "@/lib/format/kpi-delta";
import { displayRate } from "@/lib/judge/grade";
import styles from "./KpiCard.module.css";
/**
* 数値そのものの色。モック(d-watch-mock.jsx:688)の4枚のカードに対応する。
* `ProgressBar` の tone と同じ5つに揃えている(`StatTone` は `pr` を持たないため流用不可)。
*/
export type KpiTone = "ok" | "wn" | "ng" | "ac" | "pr";
interface KpiCardProps {
/** 「稼働率」等。★呼び出し側で `t()` 済みの文字列を渡す★ */
label: string;
/** 生値(%)。分母0の期間は null(`lib/judge/kpi.ts` の `rate()` 参照) */
value: number | null;
/** 前期との差(%)。`value`/`prev` のどちらかが null なら null(`toKpiValue`) */
diff: number | null;
/** 「前週」または「前月」。★呼び出し側で `t()` 済みの文字列を渡す★ */
prevLabel: string;
/** 前期の生値(%) */
prevValue: number | null;
/**
* 数値の色。どのKPIが何色かは呼び出し側の知識なので、ここでは受け取った色を使うだけ。
* モック:688 では 稼働率=ok / 出発成功率=pr / 清掃完了率=ac / エラー発生率=ng。
*/
tone: KpiTone;
/**
* ★前期比の色分けの向き(指示書F 5-4。間違えやすい)★
* true : 上がったら良い(稼働率 / 出発成功率 / 清掃完了率)
* false: ★下がったら良い(エラー発生率)★
* 呼び出し側が▲▼の色を毎回組み立てなくて済むよう、反転の判断はこのコンポーネントに閉じる。
*/
betterWhenHigher: boolean;
}
/**
* レポート(F-04)のKPIカード。
*
* ★`components/ui/StatCard.tsx` を流用せず新設した理由★(指示書F 5-4 の選択肢2)
* - モックのカードは「前期比の行(▲▼)+補助行(前週: N%)」の2行構成だが、
* `StatCard` の `sub` は1行のテキストのみ
* - `StatTone` に出発成功率の `pr`(青)が無い
* `StatCard` 本体を拡張するとダッシュボード(F-01)に影響が出るため、
* レポート専用のカードとして分離した。
*
* ★色の受け渡し★
* `useTheme()` は呼ばず、CSS変数(`app/globals.css` の `--ok` / `--ng` / `--tx-m` 等)
* だけで完結させている。トークンは `[data-theme]` で切り替わるので JS 側で色を持つ必要がなく、
* `StatCard` / `ProgressBar` と同じ「色を知らない純粋な表示部品」に揃えられる
* (`DsAlertsScreen` 等が `useTheme()` を呼ぶのは、色を条件分岐で組み立てる画面側の都合)。
*/
export function KpiCard({
label,
value,
diff,
prevLabel,
prevValue,
tone,
betterWhenHigher,
}: KpiCardProps) {
return (
<div className={styles.card}>
<div className={styles.label}>{label}</div>
<div className={`${styles.value} ${styles[tone]}`}>
{displayRate(value)}
</div>
{/* diff === null(新規施設など前期データなし)は▲▼を出さない。
`lib/judge/kpi.ts` の `toKpiValue` のコメント参照。
差が取れないので「→0%」ではなく行そのものを出さない。 */}
{diff !== null &&
(() => {
const view = kpiDeltaView(diff, betterWhenHigher);
return (
<div className={styles.deltaRow}>
<span className={`${styles.delta} ${styles[view.tone]}`}>
{/* 矢印・数・色は kpiDeltaView()(丸めて0なら「→」・色なし。施設別の表の「変化」と同じ。指示書BC 5-3) */}
{view.arrow}
{view.percent}%
</span>
<span className={styles.deltaLabel}>{prevLabel}比</span>
</div>
);
})()}
<div className={styles.prev}>
{prevLabel}: {displayRate(prevValue)}
</div>
</div>
);
}