Skip to content

Instantly share code, notes, and snippets.

@inchoate
Created September 13, 2025 11:03
Show Gist options
  • Save inchoate/d6c8aa53befe73591b4b5d926ccd3f7b to your computer and use it in GitHub Desktop.
Save inchoate/d6c8aa53befe73591b4b5d926ccd3f7b to your computer and use it in GitHub Desktop.

Frontend Dashboard Refactoring Playbook

Based on the successful refactoring patterns I've seen before, here's a comprehensive playbook for refactoring another frontend dashboard. This guide will help another agent execute the same high-quality refactoring.

πŸ“‹ Pre-Refactoring Checklist

  1. Analyze Current Structure
    - Map out all files in the dashboard directory
    - Identify monolithic components (>200 lines)
    - Note file naming inconsistencies
    - Document current folder structure
  2. Create Refactoring Plan
    - Write a detailed plan in markdown (REFACTORING_PLAN.md)
    - Break into phases (typically 3-4)
    - Get user approval before starting
  3. Backup Current State
    - Ensure git is clean or commit current changes
    - Create a feature branch for refactoring

πŸ—οΈ Refactoring Structure Template

  dashboard/
  β”œβ”€β”€ [feature-name]/
  β”‚   β”œβ”€β”€ [FeatureName]Page.tsx         (Main page component, <150 lines)
  β”‚   β”œβ”€β”€ components/                   (Feature-specific components)
  β”‚   β”‚   β”œβ”€β”€ [Component1].tsx          (<200 lines each)
  β”‚   β”‚   β”œβ”€β”€ [Component2].tsx
  β”‚   β”‚   └── ...
  β”‚   β”œβ”€β”€ hooks/                        (Custom hooks)
  β”‚   β”‚   β”œβ”€β”€ use[Feature]Data.ts
  β”‚   β”‚   └── use[Feature]Actions.ts
  β”‚   └── utils/                        (Helper functions)
  β”‚       β”œβ”€β”€ [feature]Types.ts         (TypeScript types/interfaces)
  β”‚       └── [feature]Helpers.ts       (Pure utility functions)
  β”œβ”€β”€ shared/                            (Shared across features)
  β”‚   └── components/
  β”‚       β”œβ”€β”€ EmptyState.tsx
  β”‚       β”œβ”€β”€ ErrorState.tsx
  β”‚       └── LoadingState.tsx
  └── index.ts                          (Re-exports)

πŸ“ Step-by-Step Refactoring Process

Phase 1: Plan & Prepare

  1. Create REFACTORING_PLAN.md with:
  • Current structure analysis
  • Identified problems (large files, mixed concerns, poor organization)
  • Proposed new structure
  • Migration phases
  • Success metrics (all components <200 lines, clear separation)

Phase 2: Extract Types & Utils First

  // 1. Create utils/[feature]Types.ts
  export interface FeatureItem {
    // Move all interfaces here
  }

  export type FeatureFilters = {
    // Move all type definitions
  }

  // 2. Create utils/[feature]Helpers.ts
  export const formatFeatureData = (data: FeatureItem): string => {
    // Move pure functions here
  }

  // 3. Update imports in original files
  import type { FeatureItem } from './utils/featureTypes';

Phase 3: Extract Custom Hooks

  // hooks/useFeatureData.ts
  export function useFeatureData(filters: FeatureFilters): {
    data: FeatureItem[];
    loading: boolean;
    error: Error | null;
    // ... other return values
  } {
    // Move data fetching logic here
    // Move derived state logic here
    // Keep hook focused on single responsibility
  }

Phase 4: Break Down Components

  // Original monolithic component
  const FeaturePage = () => {
    // 500+ lines of mixed concerns
  }

  // Refactored structure:
  // FeaturePage.tsx (orchestrator, <150 lines)
  const FeaturePage = () => {
    const { data, loading } = useFeatureData(filters);

    return (
      <div>
        <FeatureHeader />
        <FeatureFilters />
        <FeatureContent data={data} loading={loading} />
      </div>
    );
  }

  // components/FeatureHeader.tsx
  export function FeatureHeader() {
    // Focused component
  }

  // components/FeatureFilters.tsx  
  export function FeatureFilters() {
    // Focused component
  }

🎯 Key Refactoring Patterns

  1. Nested Ternary Fix (ESLint: no-nested-ternary)
  // ❌ Bad: Nested ternary
  {isLoading ? <Loader /> : data ? <DataView /> : <Empty />}

  // βœ… Good: IIFE pattern
  {(() => {
    if (isLoading) return <Loader />;
    if (!data) return <Empty />;
    return <DataView />;
  })()}
  1. TypeScript Return Types (ESLint: explicit-function-return-type)
  // ❌ Bad: Missing return type
  export function useData(id: string) {
    return { data, loading };
  }

  // βœ… Good: Explicit return type
  export function useData(id: string): {
    data: Item | undefined;
    loading: boolean;
    error: Error | null;
  } {
    return { data, loading, error };
  }
  1. Event Handler Types
  // βœ… Always add void return type
  const handleClick = (event: React.MouseEvent): void => {
    // handler logic
  };
  1. Import Organization
  // βœ… Correct import order and grouping
  import React, { useState, useMemo } from 'react';

  import { useAPIFetch } from '@utils/api';
  import { Button } from '@components/ui';

  import { formatData } from '../utils/helpers';
  import type { DataItem, FilterOptions } from '../utils/types';

βœ… Quality Assurance Checklist

After Each Phase:

  • Run npm run lint:fix or equivalent
  • Run npm run format or equivalent
  • Run npm run type-check or equivalent
  • Run npm run test to ensure no breakage
  • Verify the app still works in browser

Final Cleanup:

  1. Remove old files after confirming new structure works
  2. Update test imports to point to new paths
  3. Fix any circular dependencies
  4. Update documentation if needed

🚨 Common Pitfalls to Avoid

  1. Don't forget to update test files - Test imports break after moving files
  2. Preserve functionality - Refactoring shouldn't change behavior
  3. Keep git history clean - Commit each phase separately
  4. Don't over-engineer - Keep it simple and maintainable
  5. Test incrementally - Don't refactor everything then test

πŸ“Š Success Metrics

  • βœ… No component > 200 lines
  • βœ… Clear separation of concerns (UI, data, types, utils)
  • βœ… All TypeScript types explicit
  • βœ… No ESLint errors (warnings acceptable for TODOs)
  • βœ… All tests passing
  • βœ… Consistent file naming convention
  • βœ… Logical folder structure

🎬 Final Commands Sequence

1. Initial quality check

npm run lint
npm run type-check
npm run test

2. After refactoring

npm run lint:fix
npm run format
npm run test

3. Final quality check

npm run quality  # or equivalent comprehensive check

4. Commit with conventional commits

git add -A
git commit -m "refactor(dashboard): reorganize dashboard structure

- Break monolithic components into focused modules
- Extract custom hooks for data management
- Create consistent folder structure
- Add TypeScript return types
- Fix ESLint violations"

πŸ’‘ Pro Tips

  1. Use TODO comments for future work: // TODO: Implement pagination
  2. Create shared components for common patterns (EmptyState, LoadingState, ErrorState)
  3. Keep hooks pure - No side effects in custom hooks besides React hooks
  4. Batch related changes - Update all similar patterns at once
  5. Document complex logic - Add JSDoc comments for non-obvious code

This playbook should enable another agent to execute the same quality refactoring in any frontend repository. The key is systematic approach, incremental changes, and continuous testing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment