# Refactoring Guides

Comprehensive guides for common refactoring patterns and sessions in Stratofusion.

---

## Table of Contents

1. [Backup Duplicate Prevention Refactoring](#backup-duplicate-prevention-refactoring)
2. [Token Retrieval Refactoring](#token-retrieval-refactoring)
3. [Archived: Hybrid Download Strategy Refactoring](#archived-hybrid-download-strategy-refactoring) - Historical ZIP-era notes (January 2025)
4. [Refactoring Session Summary](#refactoring-session-summary)
5. [Common Refactoring Patterns](#common-refactoring-patterns)
6. [Best Practices](#best-practices)

---

## Backup Duplicate Prevention Refactoring

**Date:** October 25, 2025
**Status:** âœ… Phases 1-2 Complete, Phase 3 Deferred
**Impact:** High - Affects backup operations, code quality, and maintainability

### Problem Statement

The backup duplicate prevention code in `BatchFileTransferDialog.tsx` had several critical issues:

1. **Component Size**: 2640 lines (532% over 500-line limit)
2. **Code Duplication**: 6 instances of manual `setIsSubmitting` calls
3. **Lack of Abstraction**: No custom hook for submission guard
4. **Mixed Concerns**: `handleTransferBatch` function (570 lines) handled multiple operation types
5. **Race Conditions**: useEffect race condition for isSubmitting reset
6. **Database Performance**: O(nÂ²) complexity in duplicate detection function

### Solution

Implemented a comprehensive refactoring plan in two phases:

#### Phase 1: Critical Refactorings âœ… COMPLETE

**1. Create useSubmissionGuard Hook** (Commit: bb15423b)

Extracted submission guard logic into a reusable hook with automatic cleanup.

**Before:**
```typescript
// In BatchFileTransferDialog.tsx
const [isSubmitting, setIsSubmitting] = useState(false);

const handleSubmit = async () => {
  if (isSubmitting) return;
  setIsSubmitting(true);
  try {
    await someOperation();
  } finally {
    setIsSubmitting(false);
  }
};

// Problem: Manual state management repeated 6 times
// Problem: No automatic cleanup on unmount
// Problem: Race conditions with useEffect
```

**After:**
```typescript
// In src/hooks/useSubmissionGuard.ts
export function useSubmissionGuard(options = {}) {
  const [isSubmitting, setIsSubmitting] = useState(false);
  const isMountedRef = useRef(true);

  useEffect(() => {
    return () => {
      isMountedRef.current = false;
    };
  }, []);

  const withSubmissionGuard = useCallback(
    async (fn) => {
      if (isSubmitting) return null;
      setIsSubmitting(true);
      try {
        const result = await fn();
        return result;
      } finally {
        if (isMountedRef.current) {
          setIsSubmitting(false);
        }
      }
    },
    [isSubmitting]
  );

  return { isSubmitting, withSubmissionGuard };
}

// In BatchFileTransferDialog.tsx
const { isSubmitting, withSubmissionGuard } = useSubmissionGuard();

const handleSubmit = async () => {
  await withSubmissionGuard(async () => {
    await someOperation();
  });
};
```

**Benefits:**
- Eliminated 6 manual `setIsSubmitting` calls.
- Automatic cleanup on unmount.
- Reusable across components.
- 13 unit tests for reliability.

**2. Refactor Backup Flow** (Commit: 437dfa12)

Separated backup-specific logic from general transfer logic.

**Before:**
```typescript
const handleTransferBatch = async () => {
  // 570 lines of mixed logic
  if (operationType === "backup") {
    // Backup logic inline
  }
  // Transfer logic inline
};
```

**After:**
```typescript
const handleBackupOperation = async () => {
  // 116 lines of backup-specific logic
  // Clear separation of concerns
};

const handleTransferBatch = async () => {
  if (operationType === "backup") {
    return handleBackupOperation();
  }
  return handleTransferBatchInternal();
};

const handleTransferBatchInternal = async () => {
  // Transfer logic only
};
```

**Benefits:**
- Clear separation of concerns.
- Easier to test and maintain.
- Removed problematic useEffect.

#### Phase 2: High Priority Refactorings âœ… COMPLETE

**1. Create useBackupOperation Hook** (Commit: 58f003d2)

Extracted backup operation logic into a reusable hook.

**Before:**
```typescript
// In handleBackupOperation (116 lines)
const handleBackupOperation = async () => {
  // Validation logic
  if (!selectedFiles || selectedFiles.length === 0) {
    setError("No files selected");
    return;
  }

  // Scheduled backup logic
  if (schedule !== "none") {
    const jobId = await createBackupJob({...});
    toast({ title: "Backup scheduled" });
  }

  // Run-now backup logic
  else {
    const timestampedFolder = await createTimestampedFolder({...});
    setDestinationFolderId(timestampedFolder.folderId);
  }
};
```

**After:**
```typescript
// In src/hooks/useBackupOperation.ts
export function useBackupOperation(options) {
  const validateBackupParams = (selectedFiles, destinationAccountId) => {
    // Validation logic
  };

  const createScheduledBackup = async (params) => {
    // Scheduled backup logic
  };

  const createRunNowBackup = async (params) => {
    // Run-now backup logic
  };

  return {
    validateBackupParams,
    createScheduledBackup,
    createRunNowBackup,
    isProcessing,
    error,
    clearError
  };
}

// In BatchFileTransferDialog.tsx (58 lines)
const {
  validateBackupParams,
  createScheduledBackup,
  createRunNowBackup
} = useBackupOperation({
  onScheduledBackupSuccess: (jobId) => {
    toast({ title: "Backup scheduled" });
  },
  onRunNowBackupReady: (folderId, jobId) => {
    setDestinationFolderId(folderId);
  },
  onError: (error) => setError(error)
});

const handleBackupOperation = async () => {
  const validation = validateBackupParams(selectedFiles, destinationAccountId);
  if (!validation.isValid) return;

  if (schedule !== "none") {
    await createScheduledBackup({...});
  } else {
    await createRunNowBackup({...});
  }
};
```

**Benefits:**
- Reduced `handleBackupOperation` from 116 lines to 58 lines (50% reduction).
- Reusable backup logic.
- 18 unit tests for reliability.
- Better error handling.

**2. Optimize Database Function** (Commit: 8c4dc62b)

Optimized `findDuplicateScheduledBackup()` from O(nÂ²) to O(n) complexity.

**Before:**
```typescript
export async function findDuplicateScheduledBackup(input) {
  const allJobs = await db.select().from(backupJobs);

  for (const job of allJobs) {
    const payload = JSON.parse(job.payload);

    // O(nÂ²) comparison
    for (const source of input.sources) {
      for (const existingSource of payload.sources) {
        if (source.id === existingSource.id) {
          // Match found
        }
      }
    }
  }
}
```

**After:**
```typescript
export async function findDuplicateScheduledBackup(input) {
  // Filter candidates by schedule type first
  const candidateJobs = await db
    .select()
    .from(backupJobs)
    .where(
      and(
        eq(backupJobs.userId, input.userId),
        eq(backupJobs.status, "scheduled"),
        eq(backupJobs.schedule, input.schedule)
      )
    );

  // Use backupJobItems table for source matching
  for (const job of candidateJobs) {
    const jobItems = await db
      .select()
      .from(backupJobItems)
      .where(eq(backupJobItems.jobId, job.id));

    // Use Set for O(1) lookups
    const existingSourceKeys = new Set(
      jobItems.map(item => `${item.sourceService}:${item.sourceAccountId}:${item.sourceId}`)
    );

    const newSourceKeys = new Set(
      input.sources.map(s => `${s.service}:${s.accountId}:${s.id}`)
    );

    // O(n) comparison
    const allMatch =
      existingSourceKeys.size === newSourceKeys.size &&
      [...newSourceKeys].every(key => existingSourceKeys.has(key));

    if (allMatch) return job;
  }

  return null;
}
```

**Benefits:**
- Reduced complexity from O(nÂ²) to O(n).
- Faster duplicate detection.
- Reduced database load.
- Less memory usage.

**3. Extract Validation Logic** (Commit: 74a45475)

Created reusable validation utilities.

**Before:**
```typescript
// Validation logic scattered across components
if (!selectedFiles || selectedFiles.length === 0) {
  setError("No files selected");
  return;
}

if (!destinationAccountId) {
  setError("No destination selected");
  return;
}

const parsedAccount = parseDestinationAccountId(destinationAccountId);
if (!parsedAccount) {
  setError("Invalid destination");
  return;
}
```

**After:**
```typescript
// In src/lib/validation/transfer-validation.ts
export function validateTransferRequirements(selectedFiles, destinationAccountId) {
  if (!selectedFiles || selectedFiles.length === 0) {
    return { isValid: false, error: "No files or folders selected for transfer" };
  }

  if (!destinationAccountId) {
    return { isValid: false, error: "Destination account not specified" };
  }

  const parsedAccount = parseDestinationAccountId(destinationAccountId);
  if (!parsedAccount) {
    return {
      isValid: false,
      error: "Invalid destination account ID format. Expected format: 'service-accountId'"
    };
  }

  return {
    isValid: true,
    parsedDestination: {
      service: parsedAccount.service,
      accountId: parsedAccount.accountId
    }
  };
}

// In components
const validation = validateTransferRequirements(selectedFiles, destinationAccountId);
if (!validation.isValid) {
  setError(validation.error);
  return;
}
```

**Benefits:**
- Consistent validation across all transfer operations.
- Reusable validation logic.
- Better error messages.
- 33 unit tests for reliability.

### Files Modified

**Created:**
1. `src/hooks/useSubmissionGuard.ts` - Submission guard hook
2. `src/hooks/__tests__/useSubmissionGuard.test.ts` - 13 unit tests
3. `src/hooks/useBackupOperation.ts` - Backup operation hook
4. `src/hooks/__tests__/useBackupOperation.test.ts` - 18 unit tests
5. `src/lib/validation/transfer-validation.ts` - Validation utilities
6. `src/lib/validation/__tests__/transfer-validation.test.ts` - 33 unit tests

**Updated:**
1. `src/components/BatchFileTransferDialog.tsx` - Integrated hooks
2. `src/lib/database/backup-jobs.ts` - Optimized duplicate detection

### Testing

**Unit Tests:** 64 tests total
- useSubmissionGuard: 13 tests âœ….
- useBackupOperation: 18 tests âœ….
- transfer-validation: 33 tests âœ….

**E2E Tests:** Scheduled backup job creation âœ…
- User authentication and navigation.
- File/folder selection.
- Backup dialog configuration.
- Job submission and verification.
- All refactored code validated.

### Benefits

**Code Quality:**
- Eliminated code duplication.
- Improved separation of concerns.
- Better error handling and validation.
- Consistent patterns across codebase.

**Performance:**
- Database query optimization (O(nÂ²) â†’ O(n)).
- Reduced memory usage.
- Faster duplicate detection.

**Maintainability:**
- Reusable hooks and utilities.
- Comprehensive test coverage (64 unit tests).
- Clear documentation.
- Easier to extend and modify.

**User Experience:**
- Prevents duplicate submissions.
- Better error messages.
- Consistent validation.
- Reliable backup operations.

### Phase 3: Component Splitting â¸ï¸ DEFERRED

**Reason:** BatchFileTransferDialog (2640 lines) has significant business logic that makes splitting complex.

**Recommendation:** Consider splitting by operation type (CopyDialog, MoveDialog, BackupDialog) in future work.

**Identified Components for Extraction:**
1. TransferItemProgressList (~270 lines)
2. TransferDestinationSelector (~80 lines)
3. TransferBackupSchedule (~45 lines)
4. TransferDialogFooter (~75 lines)
5. TransferSelectedItemsSummary (~35 lines)
6. TransferProgressDisplay (~20 lines)
7. TransferCompletionMessage (~35 lines)
8. TransferOperationMessage (~15 lines)
9. TransferErrorDisplay (~10 lines)

**Expected Results:**
- Total extraction: ~585 lines of JSX.
- Estimated final size: ~2100 lines (20% reduction, still over guideline).
- Further reduction requires extracting business logic into custom hooks.

---

## Token Retrieval Refactoring

**Date:** October 2025
**Status:** âœ… Complete
**Impact:** High - Affects all rclone operations

### Problem Statement

Token retrieval logic was scattered across multiple files with inconsistent error handling and no centralized management. This led to:

- Code duplication.
- Inconsistent error messages.
- Difficult debugging.
- Hard to maintain.

### Solution

Centralized token retrieval into a single utility module with:

- Consistent error handling.
- Proper logging.
- Fallback mechanisms.
- Type safety.

### Implementation

#### Before

```typescript
// In multiple files
async function someOperation() {
  const tokens = await getPersistedTokens(userId, service, accountId);
  if (!tokens) {
    throw new Error('No tokens found');
  }
  // Use tokens...
}
```

#### After

```typescript
// Centralized in src/lib/rclone/services/token-retrieval.ts
export async function getTokensForService(
  userId: string,
  service: ServiceType,
  accountId: string
): Promise<ServiceTokens> {
  try {
    const tokens = await getPersistedTokens(userId, service, accountId);

    if (!tokens) {
      throw new TokenRetrievalError(
        `No tokens found for ${service}:${accountId}`,
        'TOKEN_NOT_FOUND'
      );
    }

    // Validate token expiry
    if (isTokenExpired(tokens)) {
      return await refreshToken(userId, service, accountId, tokens);
    }

    return tokens;
  } catch (error) {
    logger.error('Token retrieval failed', { userId, service, accountId, error });
    throw error;
  }
}
```

### Files Modified

1. **Created:**
   - `src/lib/rclone/services/token-retrieval.ts` - Centralized token logic.
   - `src/lib/rclone/services/token-retrieval.test.ts` - Comprehensive tests.

2. **Updated:**
   - `src/lib/rclone/services/config-builder.ts` - Use centralized retrieval.
   - `src/lib/rclone/services/transfer-utils.ts` - Use centralized retrieval.
   - `src/app/api/cron/execute-backups/route.ts` - Use centralized retrieval.
   - `src/app/api/rclone/*/route.ts` - All rclone routes updated.

### Benefits

- âœ… **Single source of truth** - One place for token logic.
- âœ… **Better error handling** - Consistent error messages.
- âœ… **Easier testing** - Centralized mocking.
- âœ… **Better logging** - Comprehensive debug info.
- âœ… **Type safety** - Proper TypeScript types.

### Testing

**Test Coverage:**
- Unit tests for token retrieval.
- Unit tests for token refresh.
- Unit tests for error handling.
- Integration tests with rclone operations.

**Test Results:**
- 100% code coverage.
- All edge cases covered.
- Performance within limits.

### Migration Guide

**For Developers:**

1. **Replace direct token calls:**
   ```typescript
   // Old
   const tokens = await getPersistedTokens(userId, service, accountId);

   // New
   const tokens = await getTokensForService(userId, service, accountId);
   ```

2. **Update error handling:**
   ```typescript
   // Old
   if (!tokens) throw new Error('No tokens');

   // New
   // Error handling is built-in, just catch TokenRetrievalError
   try {
     const tokens = await getTokensForService(...);
   } catch (error) {
     if (error instanceof TokenRetrievalError) {
       // Handle token error
     }
   }
   ```

3. **Update imports:**
   ```typescript
   import { getTokensForService } from '~/lib/rclone/services/token-retrieval';
   ```

---

## Archived Hybrid Download Strategy Refactoring
The old hybrid refactoring notes covered the ZIP-era download implementation.
That path has been removed from the active product, so the detailed notes now
live in the archive instead of this active guide.
Archive references:
- public/docs/archive/refactoring/HYBRID_DOWNLOAD_REFACTORING_2025-01-26.md.
- public/docs/consolidation-history/REFACTORING_SUMMARY_HYBRID_DOWNLOAD_2025-01-26.md.
## Refactoring Session Summary

**Period:** September - October 2025
**Total Sessions:** 9
**Lines Refactored:** ~5,500

### Session 1: Service Abstraction Layer

**Date:** September 2025
**Duration:** 2 days
**Impact:** High

**Changes:**
- Created `CloudStorageService` interface.
- Implemented `BaseCloudStorageService` abstract class.
- Refactored Google Drive, OneDrive, Dropbox services.
- Created `ServiceRegistry` for service management.

**Benefits:**
- Unified interface for all services.
- Easier to add new services.
- Better code reuse.
- Improved testability.

### Session 2: API Response Standardization

**Date:** September 2025
**Duration:** 1 day
**Impact:** Medium

**Changes:**
- Created `ApiResponse<T>` interface.
- Implemented response utility functions.
- Updated all API routes to use standard format.
- Added error code mapping.

**Benefits:**
- Consistent API responses.
- Better error handling.
- Easier frontend integration.
- Improved debugging.

### Session 3: File ID Resolution

**Date:** October 2025
**Duration:** 3 days
**Impact:** High

**Changes:**
- Created unified file resolver.
- Moved resolution from rclone to Next.js.
- Implemented service-specific resolvers.
- Added comprehensive error handling.

**Benefits:**
- Better separation of concerns.
- Easier testing.
- More reliable operations.
- Better error messages.

### Session 4: State Management

**Date:** October 2025
**Duration:** 2 days
**Impact:** Medium

**Changes:**
- Created `ServiceManagerContext`.
- Implemented `FileSelectionContext`.
- Created `DriveNavigationContext`.
- Refactored components to use contexts.

**Benefits:**
- Reduced prop drilling.
- Better state organization.
- Easier to maintain.
- Improved performance.

### Session 5: Component Modularization

**Date:** October 2025
**Duration:** 2 days
**Impact:** Medium

**Changes:**
- Split large components (> 500 lines).
- Extracted reusable UI components.
- Created custom hooks for logic.
- Improved component hierarchy.

**Benefits:**
- Better code organization.
- Improved reusability.
- Easier testing.
- Better performance.

### Session 6: Testing Infrastructure

**Date:** October 2025
**Duration:** 1 day
**Impact:** Medium

**Changes:**
- Set up Vitest configuration.
- Created test utilities.
- Added React Testing Library.
- Implemented test patterns.

**Benefits:**
- Faster test execution.
- Better test organization.
- Improved test coverage.
- Easier to write tests.

### Session 7: Error Handling

**Date:** October 2025
**Duration:** 1 day
**Impact:** Medium

**Changes:**
- Created `CloudStorageError` class.
- Implemented error boundaries.
- Added error logging.
- Improved error messages.

**Benefits:**
- Better error tracking.
- Improved user experience.
- Easier debugging.
- Better error recovery.

### Session 8: Performance Optimization

**Date:** October 2025
**Duration:** 2 days
**Impact:** Medium

**Changes:**
- Implemented pagination.
- Added virtualization support.
- Optimized re-renders.
- Added memory monitoring.

**Benefits:**
- Faster page loads.
- Better large file handling.
- Improved responsiveness.
- Better resource usage.

### Session 9: Auto-Refresh UX Refactoring

**Date:** October 21, 2025
**Duration:** 1 day
**Impact:** Medium
**Branch:** feature/111-backup-tidyup

**Problem Statement:**

The Jobs page auto-refreshes every 8 seconds, which was causing UX issues when users were editing backup jobs:
- Dialog interference during editing (re-fetching job data).
- Potential loss of user input.
- Unnecessary API calls.
- Poor editing experience.

**Issues Identified:**

1. **DRY Violation** - Dialog state notification logic duplicated in both `EditBackupDialog` and `DeleteBackupConfirmDialog`
2. **Poor Separation of Concerns** - `EditBackupDialog` had too many responsibilities (data fetching, form state, dirty tracking, dialog notification, save/close logic)
3. **Hardcoded UI Logic** - Using `window.confirm` for unsaved changes warning instead of consistent shadcn/ui dialogs
4. **Missing Abstraction** - Dirty state tracking logic was inline and not reusable
5. **Code Duplication** - Nearly identical success handlers in Jobs page

**Solution Implemented:**

Created three reusable abstractions to eliminate code duplication and improve separation of concerns:

**1. `useDialogStateNotification` Hook**
- **Location:** `src/hooks/useDialogStateNotification.ts`.
- **Purpose:** Notify parent components when dialog state changes.
- **Benefits:** Eliminates duplicate useEffect code, enables auto-refresh pause pattern.
- **Test Coverage:** 8 comprehensive test cases.

```typescript
export function useDialogStateNotification(
  isOpen: boolean,
  onDialogStateChange?: (isOpen: boolean) => void
) {
  useEffect(() => {
    onDialogStateChange?.(isOpen);
  }, [isOpen, onDialogStateChange]);
}
```

**2. `useFormDirtyState` Hook**
- **Location:** `src/hooks/useFormDirtyState.ts`.
- **Purpose:** Generic hook for tracking form unsaved changes.
- **Benefits:** Reusable across any form, automatic dirty state detection.
- **Test Coverage:** 19 comprehensive test cases.

```typescript
export function useFormDirtyState<T extends Record<string, unknown>>(
  currentValues: T | null,
  initialValues: T | null
) {
  const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);

  useEffect(() => {
    if (!initialValues || !currentValues) {
      setHasUnsavedChanges(false);
      return;
    }
    const keys = Object.keys(initialValues) as Array<keyof T>;
    const hasChanges = keys.some(
      (key) => currentValues[key] !== initialValues[key]
    );
    setHasUnsavedChanges(hasChanges);
  }, [currentValues, initialValues]);

  const resetDirtyState = () => setHasUnsavedChanges(false);
  return { hasUnsavedChanges, resetDirtyState };
}
```

**3. `UnsavedChangesDialog` Component**
- **Location:** `src/components/UnsavedChangesDialog.tsx`.
- **Purpose:** Reusable dialog for warning about unsaved changes.
- **Benefits:** Replaces `window.confirm`, consistent with app design system.
- **Test Coverage:** 15 comprehensive test cases.
- **Features:** Accessible, responsive, dark mode support, keyboard navigation.

**Files Modified:**

1. **Created:**
   - `src/hooks/useDialogStateNotification.ts` - Dialog state notification hook.
   - `src/hooks/useFormDirtyState.ts` - Form dirty state tracking hook.
   - `src/components/UnsavedChangesDialog.tsx` - Unsaved changes warning dialog.
   - `src/hooks/__tests__/useDialogStateNotification.test.ts` - Hook tests (8 cases).
   - `src/hooks/__tests__/useFormDirtyState.test.ts` - Hook tests (19 cases).
   - `src/components/__tests__/UnsavedChangesDialog.test.tsx` - Component tests (15 cases).
   - `src/components/UnsavedChangesDialog.stories.tsx` - Storybook stories (7 stories).
   - `src/hooks/hooks.stories.mdx` - Hook documentation (MDX format).

2. **Refactored:**
   - `src/components/EditBackupDialog.tsx` - Now uses all three new abstractions.
   - `src/components/DeleteBackupConfirmDialog.tsx` - Now uses `useDialogStateNotification`.
   - `src/app/user/jobs/page.tsx` - Consolidated success handlers, added auto-refresh pause.

**Benefits Achieved:**

- âœ… **DRY Principle** - Eliminated ~20 lines of duplicate code.
- âœ… **Single Responsibility** - Each hook/component has one clear purpose.
- âœ… **Reusability** - Hooks can be used by any form or dialog component.
- âœ… **Consistent UX** - Replaced `window.confirm` with app-consistent dialog.
- âœ… **Better Testing** - 42 comprehensive tests with 100% pass rate.
- âœ… **Improved Performance** - Memoized callbacks, optimized re-renders.
- âœ… **Better Accessibility** - ARIA attributes, keyboard navigation.
- âœ… **Mobile Support** - Responsive design, touch-friendly.

**Testing:**
- 42 comprehensive tests across 3 test files.
- 100% test pass rate.
- TypeScript compilation successful.
- ESLint validation successful.
- 7 Storybook stories for visual documentation.

**Lessons Learned:**
- Extract reusable logic early to prevent duplication.
- Use custom hooks for complex state management.
- Replace browser-native dialogs with app-consistent components.
- Comprehensive testing from the start prevents regressions.
- Storybook stories serve as living documentation.

---

## Common Refactoring Patterns

### Pattern 1: Extract Function

**When to use:**
- Function > 50 lines.
- Complex nested logic.
- Repeated code blocks.

**Example:**
```typescript
// Before
function processFiles(files: File[]) {
  // Validation logic (20 lines)
  // Transformation logic (20 lines)
  // Formatting logic (20 lines)
}

// After
function processFiles(files: File[]) {
  const validated = validateFiles(files);
  const transformed = transformFiles(validated);
  return formatFiles(transformed);
}
```

### Pattern 2: Extract Component

**When to use:**
- Component > 200 lines.
- Repeated JSX patterns.
- Complex UI logic.

**Example:**
```typescript
// Before
function FileList() {
  return (
    <div>
      {/* 100 lines of file item JSX */}
    </div>
  );
}

// After
function FileList() {
  return (
    <div>
      {files.map(file => <FileItem key={file.id} file={file} />)}
    </div>
  );
}
```

### Pattern 3: Extract Hook

**When to use:**
- Reusable state logic.
- Complex side effects.
- Multiple components need same logic.

**Example:**
```typescript
// Before
function Component1() {
  const [data, setData] = useState();
  useEffect(() => { /* fetch logic */ }, []);
  // ...
}

function Component2() {
  const [data, setData] = useState();
  useEffect(() => { /* same fetch logic */ }, []);
  // ...
}

// After
function useData() {
  const [data, setData] = useState();
  useEffect(() => { /* fetch logic */ }, []);
  return { data, setData };
}

function Component1() {
  const { data } = useData();
}

function Component2() {
  const { data } = useData();
}
```

### Pattern 4: Replace Conditional with Polymorphism

**When to use:**
- Multiple if/else or switch statements.
- Type-based behavior.
- Growing conditional complexity.

**Example:**
```typescript
// Before
function getServiceIcon(service: ServiceType) {
  if (service === 'google') return <GoogleIcon />;
  if (service === 'onedrive') return <OneDriveIcon />;
  if (service === 'dropbox') return <DropboxIcon />;
}

// After
const SERVICE_ICONS: Record<ServiceType, React.ComponentType> = {
  google: GoogleIcon,
  onedrive: OneDriveIcon,
  dropbox: DropboxIcon,
};

function getServiceIcon(service: ServiceType) {
  const Icon = SERVICE_ICONS[service];
  return <Icon />;
}
```

---

## Best Practices

### Before Refactoring

1. **Understand the code** - Read and understand existing implementation
2. **Write tests** - Ensure good test coverage before changes
3. **Plan the refactoring** - Know what you want to achieve
4. **Get buy-in** - Discuss with team if it's a large refactoring

### During Refactoring

1. **Small steps** - Make incremental changes
2. **Keep tests passing** - Run tests after each change
3. **Commit frequently** - Small, logical commits
4. **Document changes** - Update comments and docs

### After Refactoring

1. **Verify tests** - All tests should still pass
2. **Check performance** - Ensure no regressions
3. **Update documentation** - Reflect new structure
4. **Code review** - Get team feedback

---

**Last Updated:** 2025-10-21
**Next Session:** TBD

