From 4b0c9435b925c1b1ec88b1e93759c2ed9f4de0d1 Mon Sep 17 00:00:00 2001 From: Grisha Bhatia Date: Sun, 31 May 2026 22:49:30 +0530 Subject: [PATCH 1/2] feat: add skeleton loading placeholders for dashboard stats cards --- frontend/src/components/ui/SkeletonCard.jsx | 18 ++ frontend/src/pages/DashboardPage.jsx | 176 +++++++++++--------- 2 files changed, 116 insertions(+), 78 deletions(-) create mode 100644 frontend/src/components/ui/SkeletonCard.jsx diff --git a/frontend/src/components/ui/SkeletonCard.jsx b/frontend/src/components/ui/SkeletonCard.jsx new file mode 100644 index 0000000..0ff1563 --- /dev/null +++ b/frontend/src/components/ui/SkeletonCard.jsx @@ -0,0 +1,18 @@ +const SkeletonCard = () => ( + +); + +export default SkeletonCard; \ No newline at end of file diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index 08c4a4b..3366272 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -1,4 +1,4 @@ -import { useState } from "react"; +import { useState, useEffect } from "react"; import { useAuth } from "../context/AuthContext"; import { useNavigate, Link } from "react-router-dom"; import { useCodeforces } from "../hooks/useCodeforces"; @@ -6,11 +6,15 @@ import ConnectBanner from "../components/codeforces/ConnectBanner"; import VerifyModal from "../components/codeforces/VerifyModal"; import DashboardExecutiveSummary from "../components/dashboard/DashboardExecutiveSummary"; import LoaderSwitcher from "../components/shared/loaders/LoaderSwitcher"; +import SkeletonCard from "../components/ui/SkeletonCard"; export default function DashboardPage() { const { user, loading, logout } = useAuth(); const navigate = useNavigate(); const [modalOpen, setModalOpen] = useState(false); + + // Skeleton loading state + const [isSkeletonLoading, setIsSkeletonLoading] = useState(true); const { dashboardSummary: cfData, @@ -24,10 +28,18 @@ export default function DashboardPage() { } = useCodeforces(true); const handleLogout = async () => { - await logout(); // clears HttpOnly cookies server-side + await logout(); navigate("/"); }; + // Simulate loading for skeleton demo (3 seconds) + useEffect(() => { + const timer = setTimeout(() => { + setIsSkeletonLoading(false); + }, 3000); + return () => clearTimeout(timer); + }, []); + if (loading) { return ; } @@ -52,98 +64,106 @@ export default function DashboardPage() { - {/* AI Executive Summary - The Hero of the Dashboard */} + {/* AI Executive Summary */} - {/* Metrics Grid */} -
- {/* GitHub Stats */} -
-

GitHub

-
-
- Commits - -
-
- Active PRs - -
-
+ {/* Metrics Grid - Skeleton OR Actual Content */} + {isSkeletonLoading ? ( +
+ + +
- - {/* Codeforces Widget */} - {cfLoading ? ( -
-
-
- ) : cfConnected && cfData ? ( - -

Codeforces

-
+ ) : ( +
+ {/* GitHub Stats */} +
+

GitHub

+
- Rating - {cfData.rating ?? "—"} + Commits +
- Solved - {cfData.totalSolved ?? "—"} -
-
- Streak - {cfData.currentStreak ?? 0} Days 🔥 + Active PRs +
- - ) : ( -
setModalOpen(true)} - > -

Codeforces

-

- No CF account connected. Click to link your handle. -

-
- )} - {/* Focus Quality */} -
-

Focus Quality

-
-
- CF Streak - - {cfConnected && cfData ? `${cfData.currentStreak}D` : "—"} - + {/* Codeforces Widget */} + {cfLoading ? ( +
+
-
-
-
+ ) : cfConnected && cfData ? ( + +

Codeforces

+
+
+ Rating + {cfData.rating ?? "—"} +
+
+ Solved + {cfData.totalSolved ?? "—"} +
+
+ Streak + {cfData.currentStreak ?? 0} Days 🔥 +
-
- Current - - Best: {cfConnected && cfData ? `${cfData.longestStreak}D` : "—"} + + ) : ( +
setModalOpen(true)} + > +

Codeforces

+

+ No CF account connected. Click to link your handle. +

+ +
+ )} + + {/* Focus Quality */} +
+

Focus Quality

+
+
+ CF Streak + + {cfConnected && cfData ? `${cfData.currentStreak}D` : "—"}
+
+
+
+
+
+ Current + + Best: {cfConnected && cfData ? `${cfData.longestStreak}D` : "—"} + +
+
-
+ )} {/* Connect Banner — only shown if CF is not connected */} {!cfLoading && !cfConnected && ( @@ -165,4 +185,4 @@ export default function DashboardPage() { />
); -} +} \ No newline at end of file From c1fc062daa557d24cb465c013dedc7a265aed45c Mon Sep 17 00:00:00 2001 From: Grisha Bhatia Date: Sun, 31 May 2026 23:33:37 +0530 Subject: [PATCH 2/2] fix: add md:grid-cols-2 breakpoint for tablet responsive --- frontend/src/pages/DashboardPage.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index 3366272..f63c2f9 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -69,13 +69,13 @@ export default function DashboardPage() { {/* Metrics Grid - Skeleton OR Actual Content */} {isSkeletonLoading ? ( -
+
) : ( -
+
{/* GitHub Stats */}

GitHub