# Moderation Queue Components

## Component Reference

### ModerationQueue (Root Component)

**Location:** `src/components/moderation/ModerationQueue.tsx`

**Purpose:** Root component for moderation interface. Orchestrates all sub-components and manages UI state.

**Props:**
```typescript
interface ModerationQueueProps {
  optimisticallyUpdateStats?: (delta: Partial<{
    pendingSubmissions: number;
    openReports: number;
    flaggedContent: number;
  }>) => void;
}
```

**Ref API:**
```typescript
interface ModerationQueueRef {
  refresh: () => void;
}
```

**Usage:**
```tsx
import { useRef } from 'react';
import { ModerationQueue } from '@/components/moderation/ModerationQueue';

function AdminPanel() {
  const queueRef = useRef<ModerationQueueRef>(null);
  
  return (
    <div>
      <button onClick={() => queueRef.current?.refresh()}>
        Refresh Queue
      </button>
      <ModerationQueue ref={queueRef} />
    </div>
  );
}
```

---

### ModerationErrorBoundary

**Location:** `src/components/error/ModerationErrorBoundary.tsx`

**Purpose:** Catches React render errors in queue items, preventing full queue crashes.

**Props:**
```typescript
interface ModerationErrorBoundaryProps {
  children: ReactNode;
  submissionId?: string;
  fallback?: ReactNode;
  onError?: (error: Error, errorInfo: ErrorInfo) => void;
}
```

**Features:**
- Automatic error logging
- User-friendly error UI
- Retry functionality
- Copy error details button
- Development-mode stack traces

**Usage:**
```tsx
<ModerationErrorBoundary submissionId={item.id}>
  <QueueItem item={item} {...props} />
</ModerationErrorBoundary>
```

**Custom Fallback:**
```tsx
<ModerationErrorBoundary
  submissionId={item.id}
  fallback={<div>Custom error message</div>}
  onError={(error, info) => {
    // Send to monitoring service
    trackError(error, info);
  }}
>
  <QueueItem item={item} {...props} />
</ModerationErrorBoundary>
```

---

### QueueItem

**Location:** `src/components/moderation/QueueItem.tsx`

**Purpose:** Renders individual submission in queue with all interaction controls.

**Props:**
```typescript
interface QueueItemProps {
  item: ModerationItem;
  isMobile: boolean;
  actionLoading: string | null;
  isLockedByMe: boolean;
  isLockedByOther: boolean;
  lockStatus: LockStatus;
  currentLockSubmissionId?: string;
  notes: Record<string, string>;
  isAdmin: boolean;
  isSuperuser: boolean;
  queueIsLoading: boolean;
  onNoteChange: (id: string, value: string) => void;
  onApprove: (item: ModerationItem, action: 'approved' | 'rejected', notes?: string) => void;
  onResetToPending: (item: ModerationItem) => void;
  onRetryFailed: (item: ModerationItem) => void;
  onOpenPhotos: (photos: PhotoForDisplay[], index: number) => void;
  onOpenReviewManager: (submissionId: string) => void;
  onOpenItemEditor: (submissionId: string) => void;
  onClaimSubmission: (submissionId: string) => void;
  onDeleteSubmission: (item: ModerationItem) => void;
  onInteractionFocus: (id: string) => void;
  onInteractionBlur: (id: string) => void;
}
```

**Key Features:**
- Displays submission type, status, timestamps
- User profile with avatar
- Validation summary (errors, warnings)
- Lock status indicators
- Moderator edit badges
- Action buttons (approve, reject, claim)
- Responsive mobile/desktop layouts

**Accessibility:**
- Keyboard navigation support
- ARIA labels on interactive elements
- Focus management
- Screen reader compatible

---

### QueueFilters

**Location:** `src/components/moderation/QueueFilters.tsx`

**Purpose:** Filter and sort controls for moderation queue.

**Props:**
```typescript
interface QueueFiltersProps {
  activeEntityFilter: EntityFilter;
  activeStatusFilter: StatusFilter;
  sortConfig: SortConfig;
  isMobile: boolean;
  isLoading?: boolean;
  onEntityFilterChange: (filter: EntityFilter) => void;
  onStatusFilterChange: (filter: StatusFilter) => void;
  onSortChange: (config: SortConfig) => void;
  onClearFilters: () => void;
  showClearButton: boolean;
}
```

**Features:**
- Entity type filter (all, reviews, submissions, photos)
- Status filter (pending, approved, rejected, etc.)
- Sort controls (date, type, status)
- Clear filters button
- Fully accessible (ARIA labels, keyboard navigation)

**Usage:**
```tsx
<QueueFilters
  activeEntityFilter={filters.entityFilter}
  activeStatusFilter={filters.statusFilter}
  sortConfig={filters.sortConfig}
  isMobile={isMobile}
  onEntityFilterChange={filters.setEntityFilter}
  onStatusFilterChange={filters.setStatusFilter}
  onSortChange={filters.setSortConfig}
  onClearFilters={filters.clearFilters}
  showClearButton={filters.hasActiveFilters}
/>
```

---

### ValidationSummary

**Location:** `src/components/moderation/ValidationSummary.tsx`

**Purpose:** Displays validation results for submission items.

**Props:**
```typescript
interface ValidationSummaryProps {
  item: {
    item_type: string;
    item_data: SubmissionItemData;
    id?: string;
  };
  onValidationChange?: (result: ValidationResult) => void;
  compact?: boolean;
  validationKey?: number;
}
```

**View Modes:**

**Compact (for queue items):**
- Status badges (Valid, Errors, Warnings)
- Always-visible error details (no hover needed)
- Minimal space usage

**Detailed (for review manager):**
- Expandable validation details
- Full error, warning, and suggestion lists
- Re-validate button

**Usage:**
```tsx
{/* Compact view in queue */}
<ValidationSummary
  item={{
    item_type: 'park',
    item_data: parkData,
    id: itemId
  }}
  compact={true}
  onValidationChange={(result) => {
    if (result.blockingErrors.length > 0) {
      setCanApprove(false);
    }
  }}
/>

{/* Detailed view in editor */}
<ValidationSummary
  item={{
    item_type: 'ride',
    item_data: rideData
  }}
  compact={false}
/>
```

---

## Hooks Reference

### useModerationQueueManager

**Location:** `src/hooks/moderation/useModerationQueueManager.ts`

**Purpose:** Orchestrator hook combining all moderation queue logic.

**Usage:**
```typescript
const queueManager = useModerationQueueManager({
  user,
  isAdmin: isAdmin(),
  isSuperuser: isSuperuser(),
  toast,
  settings: {
    refreshMode: 'auto',
    pollInterval: 30000,
    refreshStrategy: 'merge',
    preserveInteraction: true,
    useRealtimeQueue: true,
  },
});

// Access sub-hooks
queueManager.filters.setEntityFilter('reviews');
queueManager.pagination.setCurrentPage(2);
queueManager.queue.claimSubmission(itemId);

// Perform actions
await queueManager.performAction(item, 'approved', 'Looks good!');
await queueManager.deleteSubmission(item);
```

---

### useModerationQueue

**Location:** `src/hooks/useModerationQueue.ts`

**Purpose:** Lock management and queue statistics.

**Features:**
- Claim/release submission locks
- Lock expiry countdown
- Lock status checking
- Queue statistics

**Usage:**
```typescript
const queue = useModerationQueue({
  onLockStateChange: () => {
    console.log('Lock state changed');
  }
});

// Claim submission
await queue.claimSubmission('submission-123');

// Extend lock (adds 15 minutes)
await queue.extendLock();

// Release lock
await queue.releaseLock('submission-123');

// Check lock status
const timeRemaining = queue.getTimeRemaining();
const progress = queue.getLockProgress();
```

---

## Testing Components

### Unit Testing Example

```typescript
import { render, screen } from '@testing-library/react';
import { ModerationErrorBoundary } from '@/components/error/ModerationErrorBoundary';

describe('ModerationErrorBoundary', () => {
  it('catches errors and shows fallback UI', () => {
    const ThrowError = () => {
      throw new Error('Test error');
    };
    
    render(
      <ModerationErrorBoundary submissionId="test-123">
        <ThrowError />
      </ModerationErrorBoundary>
    );
    
    expect(screen.getByText(/queue item error/i)).toBeInTheDocument();
    expect(screen.getByText(/test error/i)).toBeInTheDocument();
  });
  
  it('shows retry button', () => {
    const ThrowError = () => {
      throw new Error('Test error');
    };
    
    render(
      <ModerationErrorBoundary>
        <ThrowError />
      </ModerationErrorBoundary>
    );
    
    expect(screen.getByRole('button', { name: /retry/i })).toBeInTheDocument();
  });
});
```

### Integration Testing Example

```typescript
import { renderHook, act } from '@testing-library/react';
import { useModerationQueueManager } from '@/hooks/moderation/useModerationQueueManager';

describe('useModerationQueueManager', () => {
  it('filters items correctly', async () => {
    const { result } = renderHook(() => useModerationQueueManager(config));
    
    act(() => {
      result.current.filters.setEntityFilter('reviews');
    });
    
    await waitFor(() => {
      expect(result.current.items.every(item => item.type === 'review')).toBe(true);
    });
  });
});
```

---

## Accessibility Guidelines

### Keyboard Navigation

**Queue Filters:**
- `Tab`: Navigate between filter controls
- `Enter`/`Space`: Open dropdown
- `Arrow keys`: Navigate dropdown options
- `Escape`: Close dropdown

**Queue Items:**
- `Tab`: Navigate between interactive elements
- `Enter`/`Space`: Activate buttons
- `Escape`: Close expanded sections

### Screen Reader Support

All components include:
- Semantic HTML (`<button>`, `<label>`, `<select>`)
- ARIA labels for icon-only buttons
- ARIA live regions for dynamic updates
- Proper heading hierarchy

### Focus Management

- Focus trapped in modals
- Focus returned to trigger on close
- Skip links for keyboard users
- Visible focus indicators

---

## Styling Guidelines

### Semantic Tokens

Use design system tokens instead of hardcoded colors:

```tsx
// ❌ DON'T
<div className="text-white bg-blue-500">

// ✅ DO
<div className="text-foreground bg-primary">
```

### Responsive Design

All components support mobile/desktop layouts:

```tsx
<div className={`${isMobile ? 'flex-col' : 'flex-row'}`}>
```

### Dark Mode

All components automatically adapt to light/dark mode using CSS variables.

---

## Performance Considerations

### Memoization

```tsx
// QueueItem is memoized
export const QueueItem = memo(({ item, ...props }) => {
  // Component will only re-render if props change
});
```

### Lazy Loading

Large components can be lazy-loaded:

```tsx
const SubmissionReviewManager = lazy(() => 
  import('./SubmissionReviewManager')
);
```

### Debouncing

Filters use debounced updates to reduce query load:

```tsx
const filters = useModerationFilters({
  debounceDelay: 300, // Wait 300ms before applying filter
});
```

---

## Troubleshooting

### Error Boundary Not Catching Errors

**Issue:** Error boundary doesn't catch async errors or event handler errors.

**Solution:** Error boundaries only catch errors during rendering, lifecycle methods, and constructors. For async errors:

```tsx
try {
  await performAction();
} catch (error) {
  handleError(error); // Manual error handling
}
```

### Lock Timer Memory Leak

**Issue:** Lock timer continues after component unmount.

**Solution:** Already fixed in Phase 4. Timer now checks `isMounted` flag and cleans up properly.

### Validation Summary Not Updating

**Issue:** Validation summary shows stale data after edits.

**Solution:** Pass `validationKey` prop to force re-validation:

```tsx
<ValidationSummary
  item={item}
  validationKey={editCount} // Increment on each edit
/>
```

---

## References

- Architecture: `docs/moderation/ARCHITECTURE.md`
- Submission Patterns: `docs/moderation/SUBMISSION_PATTERNS.md`
- Type Definitions: `src/types/moderation.ts`
- Hooks: `src/hooks/moderation/`
