/**
* 清掃面積の内訳を★画面で何件見せるか★を決める純粋関数(指示書AN 段階2 / §5-3 C-3・C-4)。
*
* ★★`lib/dashboard/rescue-visibility.ts` と同じ形の別関数★★ —
* 件数の設定値が違う(`CLEAN_AREA_INITIAL_VISIBLE` / `RESCUE_INITIAL_VISIBLE`)だけで
* 判定は同じ。★どちらかの設定値を変えたときに、もう一方が巻き添えにならないように分けてある★。
*
* ★★`components/` に置かない理由★★:
* `vitest.config.ts` の `include` は `lib/**` と `app/**` なので、
* ★`components/` に置いたテストは走りません★(D-120 項2 / 指示書AN 落とし穴12)。
* 「何件表示するか」は `>` と `>=` を取り違えるだけで静かに壊れる種類の判定
* (★ちょうど10件のときに「もっと表示」が出る★というバグは、
* 例外もテスト失敗も出ないまま運用担当だけが困る)。
*
* ★API は件数で切らない★ — ここで絞るのは★見せ方だけ★で、`items` には常に全件が入っている。
* ★`items.length` がそのまま総数★なので、件数表示は絞る前を使うこと。
*/
import { CLEAN_AREA_INITIAL_VISIBLE } from "@/lib/config";
export interface CleanAreaVisibility<T> {
/** 実際に並べる行(`expanded` なら全件、そうでなければ先頭 `CLEAN_AREA_INITIAL_VISIBLE` 件) */
visible: readonly T[];
/** まだ見えていない件数(`expanded` のときは 0)。★「もっと表示(あと{n}件)」の {n}★ */
remaining: number;
/**
* 開閉ボタンを出すか。
* ★総数が初期表示件数を「超える」ときだけ★ — ★ちょうど同数なら出さない★
* (出すと押しても何も増えない)。`expanded` の有無では変わらない
* (開いたあとは「閉じる」として同じボタンを使うため)。
*/
canToggle: boolean;
}
/**
* @param items API が返した内訳(★全件★。並び替え済み)
* @param expanded 「もっと表示」が押された状態か(★画面のローカル state。URL に持たせない★)
*/
export function cleanAreaVisibility<T>(
items: readonly T[],
expanded: boolean
): CleanAreaVisibility<T> {
// ★件数を直書きしないこと★(`CLAUDE.md` §7)— 設定値は `lib/config` から読む
const canToggle = items.length > CLEAN_AREA_INITIAL_VISIBLE;
const visible =
expanded || !canToggle ? items : items.slice(0, CLEAN_AREA_INITIAL_VISIBLE);
return {
visible,
remaining: items.length - visible.length,
canToggle,
};
}