diff --git a/app/dashboard/page.tsx b/app/dashboard/page.tsx
index dc32c51..8f9efc6 100644
--- a/app/dashboard/page.tsx
+++ b/app/dashboard/page.tsx
@@ -1,3 +1,5 @@
+"use client"
+
import { Send, PiggyBank, FileText, Shield } from "lucide-react";
import CurrentMoneySplitWidget from '@/components/CurrentMoneySplitWidget'
import GoalProgress from "@/components/Dashboard/GoalProgress";
@@ -9,69 +11,89 @@ import TransactionHistoryItem, { Transaction } from "@/components/Dashboard/Tran
import MoneyDistributionWidget from "@/components/Dashboard/MoneyDistributionWidget";
import RecentTransactionsWidget from "@/components/Dashboard/RecentTransactionsWidget";
import QuickActions from "@/components/Dashboard/QuickActions";
+import WidgetErrorBoundary from '@/components/ui/WidgetErrorBoundary'
export default function Dashboard() {
return (
{/* Stats Overview */}
- }
- trend="up"
- />
- }
- trend="up"
- />
- }
- trend="none"
- />
- }
- trend="none"
- />
+
+ }
+ trend="up"
+ />
+
+
+ }
+ trend="up"
+ />
+
+
+ }
+ trend="none"
+ />
+
+
+ }
+ trend="none"
+ />
+
{/* Quick Actions Panel */}
-
+
+
+
{/* Money Split Visualization */}
-
+
+
+
-
+
+
+
{/* Recent Transactions */}
-
+
+
+
{/* Savings Goals Progress */}
-
+
+
+
{/* Bills by Type */}
-
+
+
@@ -106,7 +128,8 @@ export default function Dashboard() {
gradient={{ from: "#5F1515", to: "#4F1111" }}
/>
-
+
+
);
diff --git a/components/ui/WidgetErrorBoundary.tsx b/components/ui/WidgetErrorBoundary.tsx
new file mode 100644
index 0000000..c517c74
--- /dev/null
+++ b/components/ui/WidgetErrorBoundary.tsx
@@ -0,0 +1,62 @@
+"use client"
+
+import React from 'react'
+import WidgetErrorState from '@/components/ui/WidgetErrorState'
+import { logError } from '@/lib/logger'
+import { generateRequestId } from '@/lib/requestId'
+
+interface WidgetErrorBoundaryProps {
+ widgetName: string
+ children: React.ReactNode
+}
+
+interface WidgetErrorBoundaryState {
+ hasError: boolean
+ error: Error | null
+}
+
+/**
+ * Reusable React error boundary for dashboard widgets.
+ * Catches render-time errors in wrapped widgets, logs via logger,
+ * and renders WidgetErrorState with retry.
+ */
+class WidgetErrorBoundary extends React.Component<
+ WidgetErrorBoundaryProps,
+ WidgetErrorBoundaryState
+> {
+ state: WidgetErrorBoundaryState = { hasError: false, error: null }
+
+ static getDerivedStateFromError(error: Error): WidgetErrorBoundaryState {
+ return { hasError: true, error }
+ }
+
+ componentDidCatch(error: Error, _info: React.ErrorInfo): void {
+ const requestId = generateRequestId()
+ logError(requestId, 'WIDGET_ERROR', `dashboard/${this.props.widgetName}`, error)
+ console.error(`Widget error in ${this.props.widgetName}:`, error)
+ }
+
+ reset = (): void => {
+ this.setState({ hasError: false, error: null })
+ }
+
+ render(): React.ReactNode {
+ if (this.state.hasError) {
+ return (
+
+
+
+ )
+ }
+
+ return this.props.children
+ }
+}
+
+export default WidgetErrorBoundary