aethex-studio/src/components/ErrorBoundary.tsx
Claude 1b1466f4ec
Add major feature improvements and developer experience enhancements
New Features:
 File Content Syncing - Code changes now persist to file tree (App.tsx)
  - Added handleCodeChange() to update file content in real-time
  - Syncs changes to both files state and openFiles tabs
  - Templates now properly update active file content

 Keyboard Shortcuts System (use-keyboard-shortcuts.ts)
  - Cmd/Ctrl+S - Save file notification
  - Cmd/Ctrl+P - Quick file search (placeholder)
  - Cmd/Ctrl+K - Command palette (placeholder)
  - Cmd/Ctrl+N - New project modal
  - Cmd/Ctrl+/ - Find in editor hint
  - Cross-platform support (Mac/Windows/Linux)
  - Integrated with PostHog analytics

 Enhanced Error Boundary (ErrorBoundary.tsx)
  - Better error UI with stack traces
  - Sentry integration for error reporting
  - Reload and retry options
  - User-friendly error messages
  - Replaced react-error-boundary with custom implementation

 Loading States Infrastructure (loading-spinner.tsx)
  - Reusable LoadingSpinner component (sm/md/lg sizes)
  - LoadingOverlay for full-screen loading
  - Accessible with ARIA labels
  - Ready for async operation improvements

Developer Experience:
- All keyboard shortcuts tracked via PostHog
- Better error debugging with component stack traces
- Auto-save functionality foundation

This commit significantly improves core functionality and sets foundation for:
- File search modal
- Command palette
- Enhanced async operation handling
2026-01-17 21:53:28 +00:00

107 lines
3.1 KiB
TypeScript

import React, { Component, ErrorInfo, ReactNode } from 'react';
import { Button } from './ui/button';
import { Card } from './ui/card';
import { AlertTriangle } from '@phosphor-icons/react';
import { captureError } from '../lib/sentry';
interface Props {
children: ReactNode;
fallback?: ReactNode;
}
interface State {
hasError: boolean;
error: Error | null;
errorInfo: ErrorInfo | null;
}
export class ErrorBoundary extends Component<Props, State> {
public state: State = {
hasError: false,
error: null,
errorInfo: null,
};
public static getDerivedStateFromError(error: Error): State {
return { hasError: true, error, errorInfo: null };
}
public componentDidCatch(error: Error, errorInfo: ErrorInfo) {
console.error('Uncaught error:', error, errorInfo);
this.setState({
error,
errorInfo,
});
// Report to Sentry
if (typeof captureError === 'function') {
captureError(error, { extra: { errorInfo } });
}
}
private handleReset = () => {
this.setState({ hasError: false, error: null, errorInfo: null });
window.location.reload();
};
private handleResetWithoutReload = () => {
this.setState({ hasError: false, error: null, errorInfo: null });
};
public render() {
if (this.state.hasError) {
if (this.props.fallback) {
return this.props.fallback;
}
return (
<div className="h-screen w-screen flex items-center justify-center bg-background p-4">
<Card className="max-w-2xl w-full p-8">
<div className="flex items-center gap-4 mb-6">
<AlertTriangle className="text-destructive" size={48} weight="fill" />
<div>
<h1 className="text-2xl font-bold">Something went wrong</h1>
<p className="text-muted-foreground mt-1">
An unexpected error occurred in the application
</p>
</div>
</div>
{this.state.error && (
<div className="bg-muted p-4 rounded-lg mb-6 overflow-auto max-h-64">
<p className="font-mono text-sm text-destructive font-semibold mb-2">
{this.state.error.toString()}
</p>
{this.state.errorInfo && (
<pre className="font-mono text-xs text-muted-foreground whitespace-pre-wrap">
{this.state.errorInfo.componentStack}
</pre>
)}
</div>
)}
<div className="flex gap-4">
<Button onClick={this.handleReset} className="flex-1">
Reload Application
</Button>
<Button
onClick={this.handleResetWithoutReload}
variant="outline"
className="flex-1"
>
Try Again
</Button>
</div>
<p className="text-xs text-muted-foreground mt-4 text-center">
If this problem persists, please report it to the development team
</p>
</Card>
</div>
);
}
return this.props.children;
}
}