Skip to content

Commit ce70f68

Browse files
feat: create ErrorBoundary component with error handling UI and reload functionality
1 parent afbc425 commit ce70f68

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

frontend/src/App.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ import SignUp from "./pages/Signup.js";
88
import SignIn from "./pages/Signin.js";
99
import OAuthSuccess from "./pages/OAuthSuccess.js";
1010
import RoomActions from "./pages/RoomActions.js";
11+
import ErrorBoundary from "./components/ErrorBoundary.js";
1112
import "./index.css"
1213
const queryClient = new QueryClient();
1314

1415
const App = () => (
16+
<ErrorBoundary>
1517
<QueryClientProvider client={queryClient}>
1618
<TooltipProvider>
1719
<Toaster />
@@ -27,6 +29,7 @@ const App = () => (
2729
</BrowserRouter>
2830
</TooltipProvider>
2931
</QueryClientProvider>
32+
</ErrorBoundary>
3033
);
3134

3235
export default App;
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import React, { Component, ReactNode } from "react";
2+
import { AlertTriangle } from "lucide-react";
3+
interface Props {
4+
children: ReactNode;
5+
fallback?: ReactNode;
6+
}
7+
8+
interface State {
9+
hasError: boolean;
10+
error?: Error;
11+
}
12+
13+
class ErrorBoundary extends Component<Props, State> {
14+
declare props: Readonly<Props>;
15+
state: State = { hasError: false };
16+
17+
constructor(props: Props) {
18+
super(props);
19+
}
20+
static getDerivedStateFromError(error: Error): State {
21+
return { hasError: true, error };
22+
}
23+
handleReload = () => {
24+
window.location.reload();
25+
};
26+
render() {
27+
const { hasError, error } = this.state;
28+
const { children, fallback } = this.props;
29+
30+
if (hasError) {
31+
return (
32+
fallback ?? (
33+
<div className="flex flex-col items-center justify-center min-h-screen bg-gray-50 dark:bg-gray-900 text-gray-800 dark:text-gray-100 p-6 transition-colors">
34+
<div className=" p-8 max-w-md text-center ">
35+
<div className="flex justify-center mb-4">
36+
<div className="bg-red-100 dark:bg-red-900/30 p-3 rounded-full">
37+
<AlertTriangle className="text-red-600 dark:text-red-400 w-8 h-8" />
38+
</div>
39+
</div>
40+
41+
<h2 className="text-2xl font-semibold mb-2">
42+
Oops! Something went wrong
43+
</h2>
44+
<p className="text-sm text-gray-500 dark:text-gray-400 mb-6">
45+
{error?.message ?? "An unexpected error occurred. Please try again."}
46+
</p>
47+
48+
<div className="flex gap-3 justify-center">
49+
<button
50+
onClick={this.handleReload}
51+
className="px-5 py-2 bg-blue-600 hover:bg-blue-700 text-white rounded-lg transition font-medium shadow-sm"
52+
>
53+
Reload Page
54+
</button>
55+
<button
56+
onClick={() => this.setState({ hasError: false, error: undefined })}
57+
className="px-5 py-2 bg-gray-200 hover:bg-gray-300 dark:bg-gray-700 dark:hover:bg-gray-600 text-gray-700 dark:text-gray-200 rounded-lg transition font-medium"
58+
>
59+
Dismiss
60+
</button>
61+
</div>
62+
</div>
63+
64+
<p className="mt-6 text-xs text-gray-400">
65+
If the issue persists, please contact support.
66+
</p>
67+
</div>
68+
)
69+
);
70+
}
71+
72+
return children;
73+
}
74+
}
75+
export default ErrorBoundary;

0 commit comments

Comments
 (0)