Skip to content

feat: Implement Creator Dashboard metrics cards and quick actions#54

Merged
Luluameh merged 1 commit into
LightForgeHub:mainfrom
Agbeleshe:creator-dashboard
Feb 22, 2026
Merged

feat: Implement Creator Dashboard metrics cards and quick actions#54
Luluameh merged 1 commit into
LightForgeHub:mainfrom
Agbeleshe:creator-dashboard

Conversation

@Agbeleshe
Copy link
Copy Markdown
Contributor

@Agbeleshe Agbeleshe commented Feb 22, 2026

close: #38

image image

PR: Implement Creator Dashboard Metrics and Quick Actions (#38)
Description
This PR implements the main content area for the Creator Dashboard, including reusable metric cards and a quick actions section. It also includes a fix for a common Next.js serialization error when passing complex objects between Server and Client components.

Key Changes
New Reusable Component:
MetricCard
for displaying performance data (earnings, students, etc.) with customizable icons and accent colors.
New Component:
QuickActions
containing primary dashboard triggers like "Create Course".
Dashboard Integration: Updated
src/app/dashboard/page.tsx
with a responsive grid layout.
Bug Fix: Converted the dashboard home page to a Client Component ("use client") to resolve a serialization error with Lucide icons.
Visuals
Matches Figma design with dark theme and specific color tokens.
Fully responsive (grid stacks on mobile).

Summary by CodeRabbit

  • New Features
    • Dashboard redesigned with a responsive metrics grid displaying key performance indicators in visually distinct cards featuring icons, numeric values, and descriptive labels, with layout automatically adapting for optimal viewing on mobile, tablet, and desktop devices
    • Added Quick Actions section providing convenient shortcuts to common dashboard operations

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 22, 2026

📝 Walkthrough

Walkthrough

This PR introduces MetricCard and QuickActions components to the dashboard, replacing static content with a responsive metrics grid that maps over a metrics array and displays metric cards dynamically, along with a new quick actions section containing action buttons.

Changes

Cohort / File(s) Summary
Dashboard Page Updates
src/app/dashboard/page.tsx
Replaced static heading/paragraph with a metrics array and responsive grid layout (grid-cols-1 md:grid-cols-2 lg:grid-cols-3) that maps MetricCard components; added QuickActions component below metrics grid.
New Metric Card Component
src/components/dashboard/MetricCard.tsx
New reusable MetricCard component accepting icon (LucideIcon), value, label, and optional iconColor/iconBgColor props; renders styled card with icon in colored pill, prominent value display, and label.
New Quick Actions Component
src/components/dashboard/QuickActions.tsx
New QuickActions component with static array of three actions (Create Course, Viewing Earnings, Student Feedback); renders titled section with responsive row of secondary variant buttons with console.log handlers.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related issues

  • #44: Implementation of the reusable MetricCard component with responsive grid layout and metric card structure directly addresses the metrics cards requirements.
  • #45: QuickActions component with "Create Course," "Viewing Earnings," and "Student Feedback" buttons directly implements the quick actions UI specified.

Possibly related PRs

  • feat: Dashboard layout #39: Modified the same dashboard page file (src/app/dashboard/page.tsx); this PR builds upon that foundation by replacing the initial static content with dynamic metric cards and quick actions components.

Poem

🐰 A dashboard blooms with cards so bright,
Metrics dancing left and right,
Quick actions hop without a care,
Responsive grids float everywhere!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: Implement Creator Dashboard metrics cards and quick actions' directly summarizes the main changes: adding metric cards and quick actions components to the dashboard.
Linked Issues check ✅ Passed All key requirements from issue #38 are met: MetricCard component created with icon/value/label support, QuickActions component with three buttons implemented, responsive grid layout added to dashboard, and client component conversion addresses serialization issues.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #38 objectives: MetricCard and QuickActions components, dashboard page updates, and client component conversion for proper prop handling.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Agbeleshe
Copy link
Copy Markdown
Contributor Author

@Luluameh waiting patiently for your review

@Luluameh Luluameh merged commit 960e509 into LightForgeHub:main Feb 22, 2026
1 check was pending
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/components/dashboard/QuickActions.tsx (1)

6-10: Replace console.log stubs with actual navigation.

All three onClick handlers only log to the console, making the Quick Actions section non-functional. These should use Next.js useRouter (or <Link>) to route to the relevant pages.

Additionally, the actions array is re-created on every render. Moving it outside the component (or converting onClick to router pushes inside the component) avoids this.

♻️ Proposed refactor
 "use client"
-import React from "react"
+import { useRouter } from "next/navigation"
 import { Button } from "@/components/ui/Button"
 
+const ACTIONS: { label: string; href: string }[] = [
+  { label: "Create Course", href: "/courses/create" },
+  { label: "Viewing Earnings", href: "/earnings" },
+  { label: "Student Feedback", href: "/feedback" },
+]
+
 export default function QuickActions() {
-  const actions = [
-    { label: "Create Course", onClick: () => console.log("Create Course clicked") },
-    { label: "Viewing Earnings", onClick: () => console.log("Viewing Earnings clicked") },
-    { label: "Student Feedback", onClick: () => console.log("Student Feedback clicked") },
-  ]
+  const router = useRouter()
 
   return (
     <div className="mt-8">
       <h3 className="text-sm font-medium text-white mb-4">Quick Actions</h3>
       <div className="flex flex-wrap gap-4">
-        {actions.map((action) => (
+        {ACTIONS.map((action) => (
           <Button
             key={action.label}
             variant="secondary"
             className="bg-[`#110719`] border-border/50 hover:bg-white/[0.05]"
-            onClick={action.onClick}
+            onClick={() => router.push(action.href)}
           >
             {action.label}
           </Button>
         ))}
       </div>
     </div>
   )
 }

Would you like me to open an issue to track replacing these stubs with real routing/action handlers?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/dashboard/QuickActions.tsx` around lines 6 - 10, The Quick
Actions array currently uses console.log stubs and is recreated each render;
replace the stubs with real Next.js navigation and avoid reallocating the array
on every render: inside the QuickActions component import and call useRouter()
to get router and update each action's onClick to call
router.push('/courses/new'), router.push('/earnings') and
router.push('/feedback') (or the correct route paths), and then either lift the
actions array outside the component and store only path strings there, or build
the actions via useMemo inside QuickActions so onClick closures capture the
router without re-creating the array on every render.
src/app/dashboard/page.tsx (2)

7-36: All metric values are hardcoded; externalize for dynamic data.

The PR objective explicitly calls for a "flexible structure for dynamic data." The MetricCard component is already structured for it, but the data source ($1,500, 12, 10+) is entirely static. Before this connects to real data, the metrics array should at minimum be derived from a prop, a context value, or an async data fetch (e.g., fetch in a parent Server Component that passes values down).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/dashboard/page.tsx` around lines 7 - 36, The metrics array in
page.tsx is hardcoded; change its sourcing so values are dynamic by fetching or
receiving data and then mapping into the same shape used by MetricCard;
specifically, replace the static const metrics with a function or prop-derived
value (e.g., accept a prop like dashboardMetrics or call an async fetch in the
server component) that returns an array of objects with label, value, icon,
iconColor, and iconBgColor, and then pass that array to where MetricCard is
rendered (keep the MetricCard props/names intact so only the data source
changes).

12-13: Prefer Tailwind semantic color utilities over hardcoded hex values.

#22d3ee, #9d50ff, and #ffa500 are magic hex strings scattered across four metric entries. If the palette changes, every entry needs a manual update. Tailwind's built-in utilities (text-cyan-400, text-purple-500, text-amber-500) or project-level CSS variables would centralise the tokens.

♻️ Example for the first two metrics
-    iconColor: "text-[`#22d3ee`]",
-    iconBgColor: "bg-[`#22d3ee`]/10",
+    iconColor: "text-cyan-400",
+    iconBgColor: "bg-cyan-400/10",
 ...
-    iconColor: "text-[`#9d50ff`]",
-    iconBgColor: "bg-[`#9d50ff`]/10",
+    iconColor: "text-purple-500",
+    iconBgColor: "bg-purple-500/10",

Also applies to: 19-20, 26-27, 33-34

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/dashboard/page.tsx` around lines 12 - 13, The metric objects use
hardcoded hex strings for iconColor and iconBgColor (e.g., "text-[`#22d3ee`]" /
"bg-[`#22d3ee`]/10"); update these to use Tailwind semantic utilities (for example
replace "text-[`#22d3ee`]" with "text-cyan-400" and "bg-[`#22d3ee`]/10" with
"bg-cyan-400/10") across all metric entries where iconColor and iconBgColor are
set (the metric objects in page.tsx), and similarly swap "#9d50ff" ->
"text-purple-500"/"bg-purple-500/10" and "#ffa500" ->
"text-amber-500"/"bg-amber-500/10" so the tokens are semantic and centralized.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/app/dashboard/page.tsx`:
- Line 2: The imported icon choices are semantically wrong and duplicate
visuals: replace Percent with a money-related icon (e.g., DollarSign or
Banknote) for the "Total Earnings" card, and avoid using Briefcase for both
"Number of Enrolled Students" and "Total Courses Published" by swapping one to a
student-related icon (e.g., Users or GraduationCap) and the other to a
course-related icon (e.g., BookOpen or LayoutGrid); update the import list to
include the chosen icons (DollarSign/Banknote, Users/GraduationCap,
BookOpen/LayoutGrid) and remove or replace Briefcase accordingly so the
components rendering those cards use the new icon identifiers.

In `@src/components/dashboard/MetricCard.tsx`:
- Around line 24-34: Wrap the metric text content in an accessible grouping so
screen readers associate the value with its label: inside the MetricCard
component (the returned JSX where {value} and {label} are rendered), replace the
two sibling divs with a semantic grouping such as a <dl> containing <dt> for the
label and <dd> for the value (or alternatively add an explicit
aria-label/aria-labelledby on the wrapping div), and ensure the class names
(text-2xl font-bold text-white and text-sm text-slate-400) are preserved on the
corresponding dt/dd so styling stays the same.

---

Nitpick comments:
In `@src/app/dashboard/page.tsx`:
- Around line 7-36: The metrics array in page.tsx is hardcoded; change its
sourcing so values are dynamic by fetching or receiving data and then mapping
into the same shape used by MetricCard; specifically, replace the static const
metrics with a function or prop-derived value (e.g., accept a prop like
dashboardMetrics or call an async fetch in the server component) that returns an
array of objects with label, value, icon, iconColor, and iconBgColor, and then
pass that array to where MetricCard is rendered (keep the MetricCard props/names
intact so only the data source changes).
- Around line 12-13: The metric objects use hardcoded hex strings for iconColor
and iconBgColor (e.g., "text-[`#22d3ee`]" / "bg-[`#22d3ee`]/10"); update these to
use Tailwind semantic utilities (for example replace "text-[`#22d3ee`]" with
"text-cyan-400" and "bg-[`#22d3ee`]/10" with "bg-cyan-400/10") across all metric
entries where iconColor and iconBgColor are set (the metric objects in
page.tsx), and similarly swap "#9d50ff" -> "text-purple-500"/"bg-purple-500/10"
and "#ffa500" -> "text-amber-500"/"bg-amber-500/10" so the tokens are semantic
and centralized.

In `@src/components/dashboard/QuickActions.tsx`:
- Around line 6-10: The Quick Actions array currently uses console.log stubs and
is recreated each render; replace the stubs with real Next.js navigation and
avoid reallocating the array on every render: inside the QuickActions component
import and call useRouter() to get router and update each action's onClick to
call router.push('/courses/new'), router.push('/earnings') and
router.push('/feedback') (or the correct route paths), and then either lift the
actions array outside the component and store only path strings there, or build
the actions via useMemo inside QuickActions so onClick closures capture the
router without re-creating the array on every render.

@@ -1,8 +1,56 @@
"use client"
import { Percent, Briefcase, MessageSquare } from "lucide-react"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Wrong icon for "Total Earnings"; duplicate icon for "Students" and "Courses".

  • Line 11: Percent renders a % symbol, which is semantically misleading for a monetary earnings metric. DollarSign, Banknote, or TrendingUp would better convey the intent.
  • Lines 18 and 25: Briefcase is used for both "Number of Enrolled Students" and "Total Courses Published". Cards with identical icons are visually indistinguishable at a glance. Consider Users / GraduationCap for students and BookOpen / LayoutGrid for courses.
🐛 Proposed icon corrections
-import { Percent, Briefcase, MessageSquare } from "lucide-react"
+import { DollarSign, Users, BookOpen, MessageSquare } from "lucide-react"

 const metrics = [
   {
     label: "Total Earnings",
     value: "$1,500",
-    icon: Percent,
+    icon: DollarSign,
     ...
   },
   {
     label: "Number of Enrolled Students",
     value: "12",
-    icon: Briefcase,
+    icon: Users,
     ...
   },
   {
     label: "Total Courses Published",
     value: "12",
-    icon: Briefcase,
+    icon: BookOpen,
     ...
   },
   ...
 ]

Also applies to: 11-11, 18-18, 25-25

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/dashboard/page.tsx` at line 2, The imported icon choices are
semantically wrong and duplicate visuals: replace Percent with a money-related
icon (e.g., DollarSign or Banknote) for the "Total Earnings" card, and avoid
using Briefcase for both "Number of Enrolled Students" and "Total Courses
Published" by swapping one to a student-related icon (e.g., Users or
GraduationCap) and the other to a course-related icon (e.g., BookOpen or
LayoutGrid); update the import list to include the chosen icons
(DollarSign/Banknote, Users/GraduationCap, BookOpen/LayoutGrid) and remove or
replace Briefcase accordingly so the components rendering those cards use the
new icon identifiers.

Comment on lines +24 to +34
return (
<Card className={cn("p-6 flex items-center space-x-4", className)}>
<div className={cn("p-3 rounded-full flex-shrink-0", iconBgColor)}>
<Icon className={cn("size-6", iconColor)} />
</div>
<div>
<div className="text-2xl font-bold text-white">{value}</div>
<div className="text-sm text-slate-400">{label}</div>
</div>
</Card>
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Metric value and label lack semantic grouping for screen readers.

The {value} and {label} are in sibling <div>s with no association, so a screen reader reads them as independent text nodes ("$1,500 … Total Earnings") with no explicit relationship. A definition list (<dl>/<dt>/<dd>) or an aria-label on the wrapping element would make the pairing explicit.

♿ Proposed accessibility improvement
-    <div>
-      <div className="text-2xl font-bold text-white">{value}</div>
-      <div className="text-sm text-slate-400">{label}</div>
-    </div>
+    <dl>
+      <dd className="text-2xl font-bold text-white">{value}</dd>
+      <dt className="text-sm text-slate-400">{label}</dt>
+    </dl>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return (
<Card className={cn("p-6 flex items-center space-x-4", className)}>
<div className={cn("p-3 rounded-full flex-shrink-0", iconBgColor)}>
<Icon className={cn("size-6", iconColor)} />
</div>
<div>
<div className="text-2xl font-bold text-white">{value}</div>
<div className="text-sm text-slate-400">{label}</div>
</div>
</Card>
)
return (
<Card className={cn("p-6 flex items-center space-x-4", className)}>
<div className={cn("p-3 rounded-full flex-shrink-0", iconBgColor)}>
<Icon className={cn("size-6", iconColor)} />
</div>
<dl>
<dd className="text-2xl font-bold text-white">{value}</dd>
<dt className="text-sm text-slate-400">{label}</dt>
</dl>
</Card>
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/dashboard/MetricCard.tsx` around lines 24 - 34, Wrap the
metric text content in an accessible grouping so screen readers associate the
value with its label: inside the MetricCard component (the returned JSX where
{value} and {label} are rendered), replace the two sibling divs with a semantic
grouping such as a <dl> containing <dt> for the label and <dd> for the value (or
alternatively add an explicit aria-label/aria-labelledby on the wrapping div),
and ensure the class names (text-2xl font-bold text-white and text-sm
text-slate-400) are preserved on the corresponding dt/dd so styling stays the
same.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Creator Dashboard metrics cards and quick actions

2 participants