# 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 `` 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