import { useState, useEffect } from 'react' import { CodeError } from '@/types/errors' import { ProjectFile } from '@/types/project' import { ErrorRepairService } from '@/lib/error-repair-service' import { Card } from '@/components/ui/card' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { ScrollArea } from '@/components/ui/scroll-area' import { Separator } from '@/components/ui/separator' import { Warning, X, Wrench, CheckCircle, Info, Lightning, FileCode, ArrowRight } from '@phosphor-icons/react' import { toast } from 'sonner' import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from '@/components/ui/collapsible' interface ErrorPanelProps { files: ProjectFile[] onFileChange: (fileId: string, content: string) => void onFileSelect: (fileId: string) => void } export function ErrorPanel({ files, onFileChange, onFileSelect }: ErrorPanelProps) { const [errors, setErrors] = useState([]) const [isScanning, setIsScanning] = useState(false) const [isRepairing, setIsRepairing] = useState(false) const [autoRepairEnabled, setAutoRepairEnabled] = useState(false) const [expandedErrors, setExpandedErrors] = useState>(new Set()) const scanForErrors = async () => { setIsScanning(true) try { const allErrors: CodeError[] = [] for (const file of files) { const fileErrors = await ErrorRepairService.detectErrors(file) allErrors.push(...fileErrors) } setErrors(allErrors) if (allErrors.length === 0) { toast.success('No errors found!') } else { toast.info(`Found ${allErrors.length} issue${allErrors.length > 1 ? 's' : ''}`) } } catch (error) { toast.error('Error scanning failed') console.error(error) } finally { setIsScanning(false) } } const repairSingleError = async (error: CodeError) => { const file = files.find(f => f.id === error.fileId) if (!file) return setIsRepairing(true) try { const result = await ErrorRepairService.repairCode(file, [error]) if (result.success && result.fixedCode) { onFileChange(file.id, result.fixedCode) setErrors(prev => prev.map(e => e.id === error.id ? { ...e, isFixed: true, fixedCode: result.fixedCode } : e )) toast.success(`Fixed: ${error.message}`, { description: result.explanation, }) await scanForErrors() } else { toast.error('Failed to repair error') } } catch (error) { toast.error('Repair failed') console.error(error) } finally { setIsRepairing(false) } } const repairAllErrors = async () => { setIsRepairing(true) try { const results = await ErrorRepairService.repairMultipleFiles(files, errors) let fixedCount = 0 results.forEach((result, fileId) => { if (result.success && result.fixedCode) { onFileChange(fileId, result.fixedCode) fixedCount++ } }) if (fixedCount > 0) { toast.success(`Repaired ${fixedCount} file${fixedCount > 1 ? 's' : ''}`) await scanForErrors() } else { toast.error('No files could be repaired') } } catch (error) { toast.error('Batch repair failed') console.error(error) } finally { setIsRepairing(false) } } const repairFileWithContext = async (fileId: string) => { const file = files.find(f => f.id === fileId) if (!file) return const fileErrors = errors.filter(e => e.fileId === fileId) if (fileErrors.length === 0) return setIsRepairing(true) try { const relatedFiles = files.filter(f => f.id !== fileId).slice(0, 3) const result = await ErrorRepairService.repairWithContext(file, fileErrors, relatedFiles) if (result.success && result.fixedCode) { onFileChange(file.id, result.fixedCode) toast.success(`Repaired ${file.name}`, { description: result.explanation, }) await scanForErrors() } else { toast.error('Failed to repair file') } } catch (error) { toast.error('Context-aware repair failed') console.error(error) } finally { setIsRepairing(false) } } const toggleErrorExpanded = (errorId: string) => { setExpandedErrors(prev => { const next = new Set(prev) if (next.has(errorId)) { next.delete(errorId) } else { next.add(errorId) } return next }) } const getSeverityIcon = (severity: string) => { switch (severity) { case 'error': return case 'warning': return case 'info': return default: return } } const getSeverityColor = (severity: string) => { switch (severity) { case 'error': return 'destructive' case 'warning': return 'secondary' case 'info': return 'outline' default: return 'outline' } } const errorsByFile = errors.reduce((acc, error) => { if (!acc[error.fileId]) { acc[error.fileId] = [] } acc[error.fileId].push(error) return acc }, {} as Record) const errorCount = errors.filter(e => e.severity === 'error').length const warningCount = errors.filter(e => e.severity === 'warning').length useEffect(() => { if (files.length > 0 && errors.length === 0) { scanForErrors() } }, []) return (

Error Detection & Repair

{errors.length > 0 && (
{errorCount > 0 && ( {errorCount} {errorCount === 1 ? 'Error' : 'Errors'} )} {warningCount > 0 && ( {warningCount} {warningCount === 1 ? 'Warning' : 'Warnings'} )}
)}
{errors.length === 0 && !isScanning && (

No Issues Found

All files are looking good! Click "Scan" to check again.

)} {isScanning && (

Scanning Files...

Analyzing your code for errors and issues

)} {errors.length > 0 && (
{Object.entries(errorsByFile).map(([fileId, fileErrors]) => { const file = files.find(f => f.id === fileId) if (!file) return null return (
{file.name} {fileErrors.length} {fileErrors.length === 1 ? 'issue' : 'issues'}
{fileErrors.map((error) => (
{getSeverityIcon(error.severity)}
{error.type} {error.line && ( Line {error.line} )} {error.isFixed && ( Fixed )}

{error.message}

{error.code && ( )}
{error.code && (
{error.code}
)}
))}
) })}
)}
) }