Skip to article
Documentation

src/features/reviews/income-validation.ts

Linked repository file from this build.

import { MAX_MONEY_CENTS } from "@/programs/snap-negative/input-limits";
import type { HouseholdMember, IncomeStream } from "@/programs/snap-negative/types";

export type IncomeField =
  | "memberId"
  | "typeCode"
  | "category"
  | "selfEmploymentKind"
  | "amountCents"
  | "expensesCents";

function moneyError(cents: number) {
  return !Number.isSafeInteger(cents) || cents < 0 || cents > MAX_MONEY_CENTS
    ? "Enter $0–$1,000,000 with up to two decimal places."
    : undefined;
}

export function incomeFieldErrors(
  draft: IncomeStream,
  members: HouseholdMember[],
): Partial<Record<IncomeField, string>> {
  const errors: Partial<Record<IncomeField, string>> = {};
  if (!members.some((member) => member.id === draft.memberId))
    errors.memberId = "Choose a household member.";
  if (!draft.typeCode.trim()) errors.typeCode = "Enter an income type.";
  if (!["earned", "unearned", "self_employment"].includes(draft.category))
    errors.category = "Choose an income category.";
  errors.amountCents = moneyError(draft.amountCents);
  if (draft.category === "self_employment") {
    if (!["farm", "non_farm"].includes(draft.selfEmploymentKind ?? ""))
      errors.selfEmploymentKind = "Choose a business type.";
    errors.expensesCents = moneyError(draft.expensesCents);
  }
  return errors;
}