From 6999154c51cd633c550497215e497fc985a478b1 Mon Sep 17 00:00:00 2001 From: akshaya988 Date: Mon, 18 May 2026 18:37:30 +0530 Subject: [PATCH] feat: add reusable widget error boundary --- src/app/dashboard/page.tsx | 70 +-------------- src/components/DashboardWidgets.tsx | 114 +++++++++++++++++++++++++ src/components/TopRepos.tsx | 1 + src/components/WidgetErrorBoundary.tsx | 64 ++++++++++++++ 4 files changed, 182 insertions(+), 67 deletions(-) create mode 100644 src/components/DashboardWidgets.tsx create mode 100644 src/components/WidgetErrorBoundary.tsx diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 9e4bdb6..ea082dd 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,20 +1,5 @@ -import ContributionGraph from "@/components/ContributionGraph"; -import ContributionHeatmap from "@/components/ContributionHeatmap"; -import PRMetrics from "@/components/PRMetrics"; -import PRBreakdownChart from "@/components/PRBreakdownChart"; -import GoalTracker from "@/components/GoalTracker"; -import DashboardHeader from "@/components/DashboardHeader"; -import StreakTracker from "@/components/StreakTracker"; -import TopRepos from "@/components/TopRepos"; -import PinnedRepos from "@/components/PinnedRepos"; -import LanguageBreakdown from "@/components/LanguageBreakdown"; -import CommitTimeChart from "@/components/CommitTimeChart"; -import IssueMetrics from "@/components/IssueMetrics"; -import StreakAtRiskBanner from "@/components/StreakAtRiskBanner"; -import FriendComparison from "@/components/FriendComparison"; -import WeeklySummaryCard from "@/components/WeeklySummaryCard"; -import ExportButton from "@/components/ExportButton"; -import PersonalRecords from "@/components/PersonalRecords"; +import DashboardWidgets from "@/components/DashboardWidgets"; + import { authOptions } from "@/lib/auth"; import { getServerSession } from "next-auth"; import { redirect } from "next/navigation"; @@ -28,56 +13,7 @@ export default async function DashboardPage() { return (
- -
- -
- - - - -
- -
- - {/* Row 1: Contribution graph + Streak + Friend Comparison */} -
-
- -
- -
-
- -
- - -
-
- - {/* Row 2: PR metrics, PR breakdown & Time Chart */} -
- - - -
- - {/* Row 3: Issue metrics */} -
- -
- - {/* Row 4: Pinned repositories */} -
- -
- - {/* Row 5: Top repos + Language breakdown + Goal tracker */} -
- - - -
+
); } \ No newline at end of file diff --git a/src/components/DashboardWidgets.tsx b/src/components/DashboardWidgets.tsx new file mode 100644 index 0000000..c38fe1e --- /dev/null +++ b/src/components/DashboardWidgets.tsx @@ -0,0 +1,114 @@ +"use client"; + +import ContributionGraph from "@/components/ContributionGraph"; +import ContributionHeatmap from "@/components/ContributionHeatmap"; +import PRMetrics from "@/components/PRMetrics"; +import PRBreakdownChart from "@/components/PRBreakdownChart"; +import GoalTracker from "@/components/GoalTracker"; +import DashboardHeader from "@/components/DashboardHeader"; +import StreakTracker from "@/components/StreakTracker"; +import TopRepos from "@/components/TopRepos"; +import PinnedRepos from "@/components/PinnedRepos"; +import LanguageBreakdown from "@/components/LanguageBreakdown"; +import CommitTimeChart from "@/components/CommitTimeChart"; +import IssueMetrics from "@/components/IssueMetrics"; +import StreakAtRiskBanner from "@/components/StreakAtRiskBanner"; +import FriendComparison from "@/components/FriendComparison"; +import WeeklySummaryCard from "@/components/WeeklySummaryCard"; +import ExportButton from "@/components/ExportButton"; +import PersonalRecords from "@/components/PersonalRecords"; +import WidgetErrorBoundary from "@/components/WidgetErrorBoundary"; + +export default function DashboardWidgets() { + return ( + <> + + + + +
+ + + +
+ + + + + + + + + +
+ + + +
+ +
+
+ + + + +
+ + + +
+
+ +
+ + + + + + + +
+
+ +
+ + + + + + + + + + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + + + + + + + + + + +
+ + ); +} \ No newline at end of file diff --git a/src/components/TopRepos.tsx b/src/components/TopRepos.tsx index fdd492a..0e35ec7 100644 --- a/src/components/TopRepos.tsx +++ b/src/components/TopRepos.tsx @@ -72,6 +72,7 @@ export default function TopRepos() { }, [fetchRepos, fetchHealthScores, selectedAccount]); const maxCommits = repos[0]?.commits ?? 1; + // throw new Error("Test widget crash"); return (
diff --git a/src/components/WidgetErrorBoundary.tsx b/src/components/WidgetErrorBoundary.tsx new file mode 100644 index 0000000..c318f9b --- /dev/null +++ b/src/components/WidgetErrorBoundary.tsx @@ -0,0 +1,64 @@ +"use client"; + +import React, { Component, ReactNode } from "react"; + +interface Props { + children: ReactNode; +} + +interface State { + hasError: boolean; +} + +class WidgetErrorBoundary extends React.Component { + constructor(props: Props) { + super(props); + + this.state = { + hasError: false, + }; + } + + static getDerivedStateFromError(_: Error): State { + return { + hasError: true, + }; + } + + componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { + console.error("Widget crashed:", error, errorInfo); + } + + handleRetry = () => { + this.setState({ + hasError: false, + }); + }; + + render() { + if (this.state.hasError) { + return ( +
+

+ Something went wrong +

+ +

+ This widget failed to load. +

+ + +
+ ); + } + + return this.props.children; + } +} + +export default WidgetErrorBoundary; \ No newline at end of file