Files
GearBox/docs/superpowers/specs/2026-04-03-code-quality-round2-design.md

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

  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