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
- 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
- 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 />;
})()}
- 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 };
}
- Event Handler Types
// β
Always add void return type
const handleClick = (event: React.MouseEvent): void => {
// handler logic
};
- 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:
- Remove old files after confirming new structure works
- Update test imports to point to new paths
- Fix any circular dependencies
- Update documentation if needed
π¨ Common Pitfalls to Avoid
- Don't forget to update test files - Test imports break after moving files
- Preserve functionality - Refactoring shouldn't change behavior
- Keep git history clean - Commit each phase separately
- Don't over-engineer - Keep it simple and maintainable
- 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
npm run lint
npm run type-check
npm run test
npm run lint:fix
npm run format
npm run test
npm run quality # or equivalent comprehensive check
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
- Use TODO comments for future work: // TODO: Implement pagination
- Create shared components for common patterns (EmptyState, LoadingState, ErrorState)
- Keep hooks pure - No side effects in custom hooks besides React hooks
- Batch related changes - Update all similar patterns at once
- 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.