# Code Quality Improvements (Round 2) Design

**Date:** 2026-04-03
**Scope:** Combined formatters hook, test helper schema generation, stale todo cleanup

## 1. useFormatters Combined Hook

**Problem:** 14 component files import the same 3-4 lines: `useWeightUnit`, `useCurrency`, `formatWeight`, `formatPrice`. This is repetitive boilerplate.

**Solution:** Create `src/client/hooks/useFormatters.ts` that returns pre-bound formatting functions:

```ts
export function useFormatters() {
  const unit = useWeightUnit();
  const currency = useCurrency();
  return {
    weight: (grams: number | null) => formatWeight(grams, unit),
    price: (cents: number | null) => formatPrice(cents, currency),
    unit,
    currency,
  };
}
```

**Consumer files to update (14):**
- CollectionView.tsx
- setups/$setupId.tsx
- routes/index.tsx
- WeightSummaryCard.tsx
- TotalsBar.tsx
- settings.tsx
- ThreadCard.tsx
- SetupCard.tsx
- ItemPicker.tsx
- ItemCard.tsx
- ComparisonTable.tsx
- CandidateCard.tsx
- CandidateListItem.tsx
- CategoryHeader.tsx

Each file replaces 3-4 imports + 2 hook calls with 1 import + 1 destructured hook call. Components that need raw `unit` or `currency` (e.g., WeightSummaryCard uses `unit` as a type, TotalsBar has a unit toggle) get them from the return object.

## 2. Test Helper Schema Generation

**Problem:** `tests/helpers/db.ts` has 120 lines of hand-written CREATE TABLE SQL that must manually mirror `src/db/schema.ts`. Any schema change requires updating both files — a known source of `SqliteError: no such column` failures.

**Solution:** Replace hand-written SQL with Drizzle's migration runner:

```ts
import { migrate } from "drizzle-orm/bun-sqlite/migrator";

export function createTestDb() {
  const sqlite = new Database(":memory:");
  sqlite.run("PRAGMA foreign_keys = ON");
  const db = drizzle(sqlite, { schema });
  migrate(db, { migrationsFolder: "./drizzle" });
  db.insert(schema.categories).values({ name: "Uncategorized", icon: "package" }).run();
  return db;
}
```

This reduces the file from ~128 lines to ~15 lines and eliminates all future manual sync.

## 3. Stale Todo Cleanup

**Problem:** Pending todo "Replace planning category filter select with icon-aware dropdown" from 2026-03-15 is already resolved — `PlanningView.tsx` uses `<CategoryFilterDropdown>` which renders Lucide icons.

**Solution:** Move the todo file from `pending/` to `done/`.

## Commit Strategy

1. **useFormatters hook** — create hook + update all 14 consumer files
2. **Test helper migration** — replace hand-written SQL with migrate()
3. **Todo cleanup** — move stale todo to done
