diff --git a/e2e/dashboard-widgets.spec.js b/e2e/dashboard-widgets.spec.js index 8612d2e3..7ba431bc 100644 --- a/e2e/dashboard-widgets.spec.js +++ b/e2e/dashboard-widgets.spec.js @@ -179,6 +179,27 @@ test.beforeEach(async ({ page }) => { body: "data: {}\n\n", }); }); + + await page.route("**/api/user/dashboard-layout**", async (route) => { + if (route.request().method() === "GET") { + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ layout: null }), + }); + } else { + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ ok: true }), + }); + } + }); + + await page.route("**/api/daily-note**", async (route) => { + await route.fulfill({ + contentType: "application/json", + body: JSON.stringify({ note: null }), + }); + }); }); test("dashboard widgets render with mocked metrics", async ({ page }) => { await page.goto("/dashboard", { waitUntil: "load" }); @@ -329,7 +350,7 @@ function mockMetricResponse(url) { }; } if (url.includes("/api/streak/freeze")) { - return { freezes: [] }; + return { hasFreeze: false, freezeDate: null }; } if (url.includes("/api/integrations/jira")) { return null; diff --git a/e2e/notifications.spec.js b/e2e/notifications.spec.js index be4320a0..a92717b4 100644 --- a/e2e/notifications.spec.js +++ b/e2e/notifications.spec.js @@ -153,6 +153,10 @@ test.beforeEach(async ({ page }) => { }); }); + await page.route("**/api/notifications**", async (route) => { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ notifications: [], unreadCount: 0 }) }); + }); + await page.route("**/api/user/github-accounts", async (route) => { await route.fulfill({ contentType: "application/json", @@ -255,6 +259,10 @@ test.beforeEach(async ({ page }) => { }); } + await page.route("**/api/streak/freeze**", async (route) => { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ hasFreeze: false, freezeDate: null }) }); + }); + await page.route("**/api/stream**", async (route) => { await route.fulfill({ status: 200, @@ -262,6 +270,18 @@ test.beforeEach(async ({ page }) => { body: "data: {}\n\n", }); }); + + await page.route("**/api/user/dashboard-layout**", async (route) => { + if (route.request().method() === "GET") { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ layout: null }) }); + } else { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ ok: true }) }); + } + }); + + await page.route("**/api/daily-note**", async (route) => { + await route.fulfill({ contentType: "application/json", body: JSON.stringify({ note: null }) }); + }); }); test("notification bell opens and closes drawer", async ({ page }) => { diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 3c7a6a7d..3ee7eec7 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -21,19 +21,19 @@ export default async function DashboardPage() { {/* Quick actions */} -
+
{/* Left side actions */}
Year in Code Settings @@ -44,32 +44,35 @@ export default async function DashboardPage() {
-
+ {/* Info Banners */} +
-
+ {/* Today Focus Section */} +
-
-
-
+ {/* Featured Section */} +
+
+
- + New Feature - + AI Resume Generator
-

+

Generate an ATS-Friendly CV Backed by Your Real Code

-

+

Analyze your GitHub contributions, merged PRs, and lines of code changed to automatically generate professional bullet points for your target roles. @@ -78,10 +81,10 @@ export default async function DashboardPage() { Build Resume - +

diff --git a/src/components/dashboard/CustomizableDashboard.tsx b/src/components/dashboard/CustomizableDashboard.tsx index 95353860..01fd4003 100644 --- a/src/components/dashboard/CustomizableDashboard.tsx +++ b/src/components/dashboard/CustomizableDashboard.tsx @@ -204,17 +204,17 @@ const SECTION_ANCHOR_IDS: Record = { }; const SECTION_ACCENT_CLASSES: Record = { - overview: "bg-[var(--accent)] shadow-[0_0_15px_var(--accent)]", - activity: "bg-emerald-500 shadow-[0_0_15px_rgba(16,185,129,0.5)]", - analytics: "bg-blue-500 shadow-[0_0_15px_rgba(59,130,246,0.5)]", - goals: "bg-purple-500 shadow-[0_0_15px_rgba(168,85,247,0.5)]", + overview: "h-1 bg-gradient-to-r from-[var(--accent)] to-[var(--accent)]/60 rounded-full shadow-md", + activity: "h-1 bg-gradient-to-r from-emerald-500 to-emerald-500/60 rounded-full shadow-md", + analytics: "h-1 bg-gradient-to-r from-blue-500 to-blue-500/60 rounded-full shadow-md", + goals: "h-1 bg-gradient-to-r from-purple-500 to-purple-500/60 rounded-full shadow-md", }; const SECTION_GRID_CLASSES: Record = { - overview: "grid grid-cols-1 xl:grid-cols-2 gap-6 w-full", - activity: "grid grid-cols-1 xl:grid-cols-3 gap-6 w-full", - analytics: "grid grid-cols-1 lg:grid-cols-2 gap-6 w-full", - goals: "grid grid-cols-1 xl:grid-cols-3 gap-6 w-full", + overview: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 gap-6 w-full", + activity: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full", + analytics: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-2 xl:grid-cols-3 gap-6 w-full", + goals: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 w-full", }; const WIDGET_SPAN_CLASSES: Partial> = { @@ -584,7 +584,7 @@ export default function CustomizableDashboard() { }; return ( -
+
-
+
-

- {DASHBOARD_SECTION_LABELS[sectionId]} -

+
+

+ {DASHBOARD_SECTION_LABELS[sectionId]} +

+

+ {sectionId === "overview" && "Quick summary of your development profile"} + {sectionId === "activity" && "Your coding patterns and contributions"} + {sectionId === "analytics" && "In-depth analysis of your repositories and code"} + {sectionId === "goals" && "Track progress, milestones, and insights"} +

+
-
+
{sectionWidgets.map((widgetId) => ( -
-
-

- Dashboard Layout +
+
+
+

+

-

- Reorder widgets, hide unused cards, and reset the dashboard anytime. +

+ Reorder widgets by dragging, hide cards you don't need, and reset to default anytime.

-
+
{isEditing ? ( ) : null}
{isEditing ? ( -
-

- Hidden widgets +
+

+

{hiddenWidgets.length > 0 ? ( -
+
{hiddenWidgets.map((widgetId) => (
) : ( -

- No widgets are hidden. +

+ ✓ All widgets are visible. No hidden widgets to restore.

)}
diff --git a/src/components/dashboard/SortableDashboardWidget.tsx b/src/components/dashboard/SortableDashboardWidget.tsx index 8f4acb31..56bb74e4 100644 --- a/src/components/dashboard/SortableDashboardWidget.tsx +++ b/src/components/dashboard/SortableDashboardWidget.tsx @@ -46,16 +46,16 @@ export default function SortableDashboardWidget({ ref={setNodeRef} style={style} className={`relative min-w-0 ${className} ${ - isDragging ? "opacity-70" : "" - }`} + isDragging ? "opacity-60 scale-95" : "" + } transition-all duration-150`} > {isEditing ? ( -
+
@@ -77,8 +77,8 @@ export default function SortableDashboardWidget({
{children}