Newer
Older
client_dwatch / lib / clean-logs / detail-log-date-range.ts
/**
 * 清掃詳細ログ画面(F-02。`components/features/detail-log/DetailLogScreen.tsx`)の
 * ★期間(`date_from` / `date_to`)の扱い★。★純粋関数のみ★(D-159 追記 / 指示書AV 段階5b)。
 *
 * ★画面の既定は「期間を指定しない(全期間)」★(ユーザー指示 2026-10-06「C」)—
 *   ダッシュボードは「各清掃エリアの直近の清掃(7日以内)」を出すので、既定を当日にすると
 *   前日 19:00 の出発失敗がダッシュボードには出るのに、カードや「全項目 →」で移った先に出ない。
 *
 * ★画面のコンポーネントは vitest の `include`(`lib/**` / `app/**`)に入らない★ので、
 *   URL の組み立てと検証の条件だけをここに切り出してテストする
 *   (`lib/clean-logs/__tests__/detail-log-date-range.test.ts`)。
 *
 * ★API(`/api/clean-logs` / `/api/clean-logs/export`)は変えない★ — 期間なし=全期間、
 *   片方だけ=その側だけの範囲、は `parseCleanLogQuery()`(`lib/clean-logs/query.ts`)の既存の挙動。
 */
import { inclusiveDayCount } from "@/lib/format/date";

/**
 * 期間のクエリパラメータを足す。★空の側は付けない★(空文字の `date_from=` も送らない)。
 *
 * ★片方だけ入っているときは、入っている側だけを付ける★(その側だけで区切った範囲になる)。
 *   ★これは 5b 以前の画面の挙動と同じ★ — 以前も片方を消すと `date_from=`(空文字)が飛び、
 *   API は空の側を「指定なし」と読んでいた。「両方そろうまで送らない」「片方だけなら捨てる」は
 *   どちらも入力した日付が効かない時間ができるので採らない(指示書AV 段階5b-6)。
 */
export function appendDateRangeParams(
  params: URLSearchParams,
  dateFrom: string,
  dateTo: string
): void {
  if (dateFrom) params.set("date_from", dateFrom);
  if (dateTo) params.set("date_to", dateTo);
}

/**
 * 期間の検証。★両方入っているときだけ行う★(指示書AV 段階5b-2)。問題なければ `null`。
 *
 * ★文言・境界はサーバ(`parseCleanLogQuery()`)と同じ★ — 上限ちょうどは通す(`>`)、
 *   開始=終了(1日)は通す。★画面は「親切」、サーバは「歯止め」★(APIを直接叩く経路が残る)。
 * 形式が不正(`inclusiveDayCount()` が `null`)のときも画面では止めない(サーバが 422 を返す。従来どおり)。
 */
export function dateRangeError(
  dateFrom: string,
  dateTo: string,
  maxDays: number
): string | null {
  if (!dateFrom || !dateTo) return null;
  const days = inclusiveDayCount(dateFrom, dateTo);
  if (days === null) return null;
  if (days > maxDays) {
    return `date_from〜date_toは${maxDays}日以内で指定してください`;
  }
  if (days < 1) {
    return "date_fromはdate_to以前の日付を指定してください";
  }
  return null;
}