2.6 KiB
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:
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:
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
- useFormatters hook — create hook + update all 14 consumer files
- Test helper migration — replace hand-written SQL with migrate()
- Todo cleanup — move stale todo to done