Skip to content

Refactor ShotHistoryView to use shared chart components and reduce 3,000-line monolith #175

@hessius

Description

@hessius

Chart Component Refactoring

Problem

ShotHistoryView.tsx is a 3,039-line monolith that contains inline Recharts rendering logic, custom tooltips, chart constants, and stage coloring — all duplicated from what now exists in the shared charts/ directory.

During the Control Center implementation (#169 Phase 3), we extracted reusable chart components into apps/web/src/components/charts/:

File Purpose
chartConstants.ts Colors, themes, stage ranges, speed options
CustomTooltip.tsx Shared tooltip component for Recharts
EspressoChart.tsx Reusable espresso shot chart with pressure/flow/weight/temp traces
index.ts Barrel exports

These components are used by LiveShotView.tsx for real-time shot monitoring. However, ShotHistoryView.tsx still uses its own inline versions of the same logic — it imports recharts directly and has its own tooltip, color constants, and chart rendering code.

Goals

  1. Eliminate duplicationShotHistoryView should import from @/components/charts/ instead of maintaining parallel implementations
  2. Reduce file size — Target: from 3,039 lines to under 1,500 lines by extracting chart logic and splitting into sub-components
  3. Zero visual regression — Shot history charts must look identical before and after refactoring
  4. Establish chart conventions — All future chart rendering goes through the shared charts/ components

Current Architecture

ShotHistoryView.tsx (3,039 lines)
├── Inline Recharts imports (recharts directly)
├── Inline color constants (duplicated from chartConstants.ts)
├── Inline tooltip component (duplicated from CustomTooltip.tsx)
├── Inline chart rendering logic (duplicated from EspressoChart.tsx)
├── Shot list / selection UI
├── Shot analysis display
├── Profile overlay logic
├── Stage highlighting
└── Export / comparison features

charts/
├── chartConstants.ts ← shared, used by LiveShotView only
├── CustomTooltip.tsx ← shared, used by LiveShotView only
├── EspressoChart.tsx ← shared, used by LiveShotView only
└── index.ts

Target Architecture

ShotHistoryView.tsx (~800-1000 lines)
├── Shot list / selection logic
├── Shot analysis display
├── Orchestration (which sub-view to show)
└── Export / comparison features

charts/
├── chartConstants.ts ← shared by LiveShotView + ShotHistoryView
├── CustomTooltip.tsx ← shared by LiveShotView + ShotHistoryView
├── EspressoChart.tsx ← shared by LiveShotView + ShotHistoryView
├── ChartOverlay.tsx ← NEW: profile target curve overlay component
├── StageHighlight.tsx ← NEW: extraction stage coloring/bands
├── index.ts ← updated barrel exports

ShotHistoryView/
├── ShotHistoryView.tsx ← main orchestrator (slim)
├── ShotList.tsx ← shot selection sidebar/list
├── ShotDetail.tsx ← individual shot analysis display
├── ShotComparison.tsx ← side-by-side shot comparison
└── index.ts

Implementation Plan

Step 1: Audit & Map Duplications

  • Catalog all inline chart constants in ShotHistoryView.tsx and compare with chartConstants.ts
  • Catalog all inline tooltip logic and compare with CustomTooltip.tsx
  • Catalog all inline Recharts usage and compare with EspressoChart.tsx
  • Identify ShotHistoryView-specific chart features not yet in shared components (profile overlays, stage bands, comparison mode)
  • Create a mapping document: what moves where

Step 2: Extend Shared Chart Components

  • Extend chartConstants.ts with any missing constants from ShotHistoryView
  • Extend CustomTooltip.tsx to handle ShotHistoryView's tooltip variations (or make it configurable via props)
  • Extend EspressoChart.tsx with props for profile overlay, stage highlighting, and static (non-live) data display
  • Create ChartOverlay.tsx — profile target curve overlay (currently inline in ShotHistoryView)
  • Create StageHighlight.tsx — extraction stage coloring bands (if complex enough to warrant extraction)
  • Update charts/index.ts barrel exports

Step 3: Split ShotHistoryView into Sub-Components

  • Extract ShotList.tsx — shot selection list/sidebar with search, filtering, date grouping
  • Extract ShotDetail.tsx — individual shot analysis view (chart + metadata + analysis text)
  • Extract ShotComparison.tsx — side-by-side comparison mode (if it exists)
  • Create ShotHistoryView/index.ts barrel export
  • Slim down ShotHistoryView.tsx to orchestration only

Step 4: Wire Up & Replace

  • Replace all inline Recharts usage in ShotHistoryView with EspressoChart from shared components
  • Replace inline tooltip with shared CustomTooltip
  • Replace inline color constants with shared chartConstants
  • Remove all direct recharts imports from ShotHistoryView
  • Verify TypeScript compiles with zero errors

Step 5: Visual Regression Testing

  • Screenshot before: Shot history list view
  • Screenshot before: Individual shot chart (with profile overlay)
  • Screenshot before: Shot with stage highlighting
  • Screenshot before: Mobile shot history
  • Refactor code
  • Screenshot after: Compare all above views pixel-by-pixel
  • Verify dark mode and light mode both render correctly
  • Verify desktop two-column and mobile single-column layouts

Step 6: Cleanup

  • Remove dead code from ShotHistoryView
  • Run bun run build — verify production build succeeds
  • Run TypeScript strict check — zero errors
  • Update any imports elsewhere in the app that reference ShotHistoryView
  • Update i18n keys if any component boundaries changed

Constraints

  • No new dependencies — use only existing Recharts + shared chart components
  • No API changes — this is purely a frontend refactoring
  • No behavior changes — all chart interactions (zoom, hover, click) must work identically
  • Incremental commits — each step should be a separate commit for easy bisection

Definition of Done

  • ShotHistoryView.tsx is under 1,500 lines (ideally under 1,000)
  • Zero direct recharts imports in ShotHistoryView (uses shared charts/ only)
  • All chart rendering goes through shared components
  • Visual regression: zero pixel differences in charts (verified via screenshots)
  • bun run build succeeds, TypeScript zero errors
  • All existing backend tests still pass (512+)
  • Code review: no duplicated chart logic anywhere in the codebase

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions