- Login with role-based auth (CTO/Manager/Employee) - Calendar view (month/week) with task chips and quick-add - Kanban board with status columns - Sortable list view with action menus - Task detail drawer with subtasks, comments, activity - Add task modal with validation - Dashboard with stats, workload, priority breakdown - Team tasks grouped by assignee - Reports page with recharts (bar, pie, line, horizontal bar) - Members page with invite modal - Search and assignee filter across views - ErrorBoundary for production error handling - Full dark design system via index.css
49 lines
1.9 KiB
TypeScript
49 lines
1.9 KiB
TypeScript
import React from 'react';
|
||
|
||
interface Props { children: React.ReactNode; }
|
||
interface State { hasError: boolean; error: Error | null; }
|
||
|
||
export class ErrorBoundary extends React.Component<Props, State> {
|
||
constructor(props: Props) {
|
||
super(props);
|
||
this.state = { hasError: false, error: null };
|
||
}
|
||
|
||
static getDerivedStateFromError(error: Error): State {
|
||
return { hasError: true, error };
|
||
}
|
||
|
||
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
||
console.error('ErrorBoundary caught:', error, errorInfo);
|
||
}
|
||
|
||
render() {
|
||
if (this.state.hasError) {
|
||
return (
|
||
<div style={{
|
||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||
minHeight: '100vh', background: '#0a0f1a', color: '#e2e8f0',
|
||
fontFamily: '"DM Sans", sans-serif', flexDirection: 'column', gap: 16,
|
||
}}>
|
||
<div style={{ fontSize: 48 }}>⚠️</div>
|
||
<h1 style={{ fontSize: 24, fontWeight: 700 }}>Something went wrong</h1>
|
||
<p style={{ color: '#94a3b8', maxWidth: 400, textAlign: 'center', lineHeight: 1.6 }}>
|
||
{this.state.error?.message || 'An unexpected error occurred.'}
|
||
</p>
|
||
<button
|
||
onClick={() => { this.setState({ hasError: false, error: null }); window.location.reload(); }}
|
||
style={{
|
||
background: '#6366f1', color: '#fff', border: 'none', borderRadius: 8,
|
||
padding: '10px 24px', fontSize: 14, fontWeight: 600, cursor: 'pointer',
|
||
marginTop: 8,
|
||
}}
|
||
>
|
||
Reload App
|
||
</button>
|
||
</div>
|
||
);
|
||
}
|
||
return this.props.children;
|
||
}
|
||
}
|