Skip to content

Conversation

@Kalpana-chavhan
Copy link

@Kalpana-chavhan Kalpana-chavhan commented Jan 6, 2026

closes #269


Description

This PR significantly enhances the Dashboard user experience by moving away from static "Coming Soon" text to a dynamic, professional interface. The focus was on improving the "perceived performance" of the app—ensuring that even while data is loading or missing, the interface remains polished and guided.

Beyond the UI, I have also synchronized the backend requirements to ensure a smooth "one-click" setup for future contributors, resolving common dependency issues found in the local development environment.


Changes Made

  1. Frontend (UX/UI Refinement):
  • Integrated Skeleton Loading: Added custom pulsing placeholders for dashboard metrics and charts. This eliminates jarring layout shifts while waiting for backend responses.
  • New Empty State Architecture: Created a reusable EmptyState component with context-aware Lucide icons to replace blank screens on tabs like "Analytics" and "Sponsorships."
  • Theme Consistency: Updated Tailwind styles in the DashboardPage to ensure full accessibility and visual parity between light and dark modes.
  • Component Modularization: Added Skeleton.tsx and EmptyState.tsx to the UI kit for future use across the application.
  1. Backend (Stability & Setup):
  • Requirement Alignment: Updated requirements.txt to include essential missing libraries: sqlalchemy, aiopg, and uvicorn.
  • Environment Fix: Resolved ModuleNotFoundError issues that previously blocked the FastAPI server from initializing correctly on Windows environments.

Checklist

  1. I have read the contributing guidelines.
  2. I have verified the frontend UI transitions locally.
  3. I have added necessary documentation (new components are modular and commented).
  4. All backend dependencies are now correctly listed in requirements.txt.

Summary by CodeRabbit

  • New Features

    • Added Skeleton loading placeholders and an Empty State component; dashboard shows loading skeletons and empty-state prompts with actions.
    • AI-driven content sections now render skeletons while loading.
  • Backend / Auth

    • Login response now includes additional user and session fields.
    • Email validation for new users tightened.
  • UI/UX Improvements

    • Updated dashboard header, navigation, top action button, tabs and layout for clearer flow and improved loading transitions.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 6, 2026

📝 Walkthrough

Walkthrough

Adds a new backend LoginResponse schema and stricter email validation, introduces two frontend UI components (EmptyState, Skeleton), and integrates loading/empty-state handling and client-side data fetching into DashboardPage with updated header actions and navigation.

Changes

Cohort / File(s) Summary
Backend Schema Updates
Backend/app/schemas/schema.py
Added LoginResponse Pydantic model (message, user_id, email: EmailStr, optional name, role, session, onboarding_completed) and changed UserCreate.email from str to EmailStr. Added imports: EmailStr, Any, List.
Frontend UI Components
Frontend/src/components/ui/EmptyState.tsx, Frontend/src/components/ui/Skeleton.tsx
New EmptyState component (icon, title, description, optional CTA and handler). New Skeleton component with circle/rect variants and pulse animation for loading placeholders.
Dashboard Integration
Frontend/src/pages/DashboardPage.tsx
Added isLoading state and useEffect data fetch flow; integrated Skeleton and EmptyState across Overview, Sponsorships, Analytics, and Collaborations areas; updated header icons/actions, navigation via useNavigate, and dark-mode-aware styling.

Sequence Diagram(s)

sequenceDiagram
  participant Browser as Browser (DashboardPage)
  participant UI as UI Components (Skeleton / EmptyState)
  participant API as Backend API
  Browser->>API: Request dashboard data (on mount)
  API-->>Browser: Returns data or empty result
  alt while fetching
    Browser->>UI: Render Skeleton placeholders
  else data received
    Browser->>UI: Render populated metric cards / lists
  else no data
    Browser->>UI: Render EmptyState with CTA
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰
I hopped through schemas, fine and neat,
Gave emails a stricter beat,
Skeletons shimmer, EmptyStates sing,
Dashboard wakes—new life they bring,
Carrots, clicks, and tiny feet.

🚥 Pre-merge checks | ✅ 2 | ❌ 3
❌ Failed checks (1 warning, 2 inconclusive)
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.
Title check ❓ Inconclusive The title refers to the main change (Dashboard UX enhancement with Skeletons and Empty States) but contains a typo ('Alignmen' instead of 'Alignment') and is slightly incomplete, making it ambiguous about backend dependencies. Correct the typo to 'Alignment' and clarify whether backend dependencies are a primary focus or secondary: revise to 'Enhance Dashboard UX with Skeletons, Empty States, and Backend Alignment'.
Out of Scope Changes check ❓ Inconclusive Backend changes (requirements.txt updates for sqlalchemy, aiopg, uvicorn) appear tangential to the UX-focused issue #269 and lack linked justification, raising questions about scope alignment. Clarify whether backend dependency updates are necessary for PR #270 scope or should be separated into a dedicated PR; link to any related backend initialization issues if applicable.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR successfully implements the core requirements from issue #269: Skeleton Loader System with CSS-based pulsing, reusable EmptyState component with icon and CTA button, and integration into Dashboard tabs.

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

✨ Finishing touches
  • 📝 Generate docstrings

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.

Copy link
Contributor

@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: 4

🤖 Fix all issues with AI Agents
In @Backend/app/schemas/schema.py:
- Around line 6-15: Change the LoginResponse.email type to use
pydantic.types.EmailStr to match UserCreate: import EmailStr from pydantic (or
pydantic.types) and replace the email: str annotation in the LoginResponse class
with email: EmailStr so login responses get the same email-format validation as
UserCreate.

In @Frontend/src/pages/DashboardPage.tsx:
- Around line 34-41: Replace the artificial setTimeout loader in the useEffect
with an actual async fetch: inside the existing useEffect that currently sets
isLoading via setTimeout, create and call an async function (e.g.,
fetchDashboardData) that sets setIsLoading(true), performs fetch calls to your
dashboard endpoints (e.g., '/api/dashboard/metrics' or other APIs), parses
responses, updates relevant state (replace the simulated loading state with real
data state), and in both success and catch blocks call setIsLoading(false);
ensure you clear or ignore results if the component unmounts (use an abort
controller or mounted flag) and keep references to useEffect, isLoading, and
setIsLoading so the change is localized.
- Around line 241-249: The onAction handler in the EmptyState inside TabsContent
is still a console.log placeholder; replace it with real navigation: import and
use React Router's useNavigate (or your app's router hook), create a navigate =
useNavigate() call in DashboardPage, and change onAction={() =>
console.log(...)} to onAction={() => navigate('/connections' /* or your
connect-accounts route */)} (or call your existing navigateToConnections
function); remove the console.log and ensure the route string matches your
connect social accounts route.
- Around line 226-234: The EmptyState onAction currently logs to console;
replace that with real navigation: import useNavigate from react-router-dom at
the top of the file, call const navigate = useNavigate() in the component, and
change the onAction handler on the EmptyState (value "sponsorships") to () =>
navigate('/profile') (or the app's profile route); ensure you remove the
console.log and use the EmptyState onAction prop to trigger
navigate('/profile').
🧹 Nitpick comments (2)
Frontend/src/components/ui/Skeleton.tsx (1)

10-27: Consider using a className utility for cleaner concatenation.

The template literal concatenation on Line 23 works but could be more robust with a utility like clsx or a custom cn helper to handle edge cases (empty strings, undefined values).

🔎 Example using a cn utility

If you have a cn utility in your project (common in shadcn/ui-based projects):

+import { cn } from "@/lib/utils"
+
 const Skeleton: React.FC<SkeletonProps> = ({ 
   className, 
   variant = "rect", 
   ...props 
 }) => {
   // Base classes for the pulse animation and color
   const baseClasses = "animate-pulse bg-gray-200 dark:bg-gray-700";
   
   // Shape variants
   const variantClasses = variant === "circle" ? "rounded-full" : "rounded-md";

   return (
     <div
-      className={`${baseClasses} ${variantClasses} ${className}`}
+      className={cn(baseClasses, variantClasses, className)}
       {...props}
     />
   );
 };
Frontend/src/pages/DashboardPage.tsx (1)

213-222: Consider adding loading state for CollaborationsPage.

Unlike other sections in the Overview tab (Performance Metrics, Recent Activity, AI-Matched Sponsorships), the Creator Collaborations card renders CollaborationsPage immediately without a skeleton placeholder. This creates an inconsistent loading experience.

🔎 Suggested improvement
 <Card className="col-span-3 bg-white dark:bg-slate-950 border-[hsl(214.3,31.8%,91.4%)] dark:border-slate-800">
   <CardHeader>
     <CardTitle>Creator Collaborations</CardTitle>
     <CardDescription>Creators with complementary audiences</CardDescription>
   </CardHeader>
   <CardContent>
-    <CollaborationsPage />
+    {isLoading ? <Skeleton className="h-40 w-full" /> : <CollaborationsPage />}
   </CardContent>
 </Card>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3be437 and cb219e1.

📒 Files selected for processing (4)
  • Backend/app/schemas/schema.py
  • Frontend/src/components/ui/EmptyState.tsx
  • Frontend/src/components/ui/Skeleton.tsx
  • Frontend/src/pages/DashboardPage.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
Frontend/src/pages/DashboardPage.tsx (4)
Frontend/src/components/dashboard/performance-metrics.tsx (1)
  • PerformanceMetrics (36-50)
Frontend/src/components/dashboard/recent-activity.tsx (1)
  • RecentActivity (3-52)
Frontend/src/components/dashboard/sponsorship-matches.tsx (1)
  • SponsorshipMatches (20-83)
Frontend/src/pages/Collaborations.tsx (1)
  • CollaborationsPage (23-251)
🔇 Additional comments (5)
Backend/app/schemas/schema.py (1)

17-23: LGTM!

The upgrade to EmailStr adds automatic email validation, preventing invalid email formats from being accepted during user creation.

Frontend/src/components/ui/EmptyState.tsx (1)

1-38: LGTM!

The EmptyState component is well-structured with proper conditional rendering, comprehensive dark mode support, and clean prop typing. The implementation correctly handles optional icon and action button scenarios.

Frontend/src/pages/DashboardPage.tsx (3)

44-90: LGTM!

The header navigation refactor using an array and map is a clean improvement that follows DRY principles. The dark mode support and accessibility labels (sr-only) are properly implemented.


112-171: LGTM!

The skeleton loading states properly match the structure of the actual metric cards, preventing layout shift and providing good perceived performance during data loading.


210-210: No action needed. SponsorshipMatches properly handles empty creatorId through early validation checks at lines 26 and 44, preventing unnecessary API calls and displaying a user-friendly message instead.

@Kalpana-chavhan
Copy link
Author

Kalpana-chavhan commented Jan 8, 2026

Hi Maintainers,
Just a gentle follow-up on this PR.
All checks are passing, please let me know if any changes are needed from my side.
Thanks! @Saahi30 , @Aditya30ag , @chandansgowda

@Aditya30ag
Copy link
Contributor

@Kalpana-chavhan please do the coderabbit ai suggestion fix

Copy link
Contributor

@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

🤖 Fix all issues with AI agents
In @Frontend/src/pages/DashboardPage.tsx:
- Around line 243-252: The EmptyState JSX has a duplicate onAction prop; remove
the redundant onAction={() => console.log("Navigate to profile")} so there is
only a single onAction prop using navigate("/profile") (i.e., keep the onAction
that calls navigate and delete the console.log variant) to eliminate the
dead/duplicate prop on the EmptyState component inside the TabsContent for
"sponsorships".
- Around line 41-56: The effect fetch never stores the API result and has a
spacing typo in the dependency array; add component state (e.g., metrics and
setMetrics) to DashboardPage, update fetchDashboardData to call setMetrics(data)
after parsing the response (and keep setting setIsLoading(false) in finally or
both branches), change the Overview metric cards to read values from the metrics
state instead of hardcoded numbers, and fix the dependency array formatting from
"} , [])" to "}, [])".
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cb219e1 and f5f7564.

📒 Files selected for processing (2)
  • Backend/app/schemas/schema.py
  • Frontend/src/pages/DashboardPage.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • Backend/app/schemas/schema.py
🧰 Additional context used
🪛 Biome (2.1.2)
Frontend/src/pages/DashboardPage.tsx

[error] 249-249: This JSX property is assigned multiple times.

This attribute is assigned again here.

(lint/suspicious/noDuplicateJsxProps)

🔇 Additional comments (6)
Frontend/src/pages/DashboardPage.tsx (6)

1-1: LGTM! Clean import additions.

The new imports for useEffect, navigation hooks, icons, and UX components are all properly utilized in the component.

Also applies to: 20-21, 27-32


35-37: LGTM! Proper state initialization.

The isLoading state and navigate hook are correctly initialized and used throughout the component.


61-106: LGTM! Excellent header refactoring.

The navigation items are now cleanly structured using an array with .map(), making the code more maintainable. The search input and mode toggle are properly styled with light/dark mode support.


131-187: Well-implemented skeleton loading pattern.

The skeleton placeholders correctly mirror the structure of the metric cards, preventing layout shift during loading. The conditional rendering is clean and the skeleton variants (circle for icons) are appropriately used.

Note: Once the data fetching issue (lines 41-56) is resolved, replace the hardcoded values with the actual metrics data.


192-239: LGTM! Consistent loading pattern implementation.

The skeleton loading is consistently applied across Performance Metrics, Recent Activity, and AI-Matched Sponsorships sections. The loading states enhance perceived performance while data is being fetched.


254-267: LGTM! Clean empty state implementations.

The Collaborations and Analytics tabs are properly structured. The EmptyState component in the Analytics tab provides clear guidance with contextual messaging and an appropriate call-to-action.

Comment on lines 41 to 56
useEffect(() => {
const fetchDashboardData = async () => {
try {
setIsLoading(true)

const response = await fetch('/api/dashboard/metrics')
const data = await response.json()

setIsLoading(false)
} catch (error) {
console.error('Failed to fetch dashboard data:', error)
setIsLoading(false)
}
}
fetchDashboardData()
} , [])
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fetched data is never stored or used.

The API response (line 47) is assigned to a local variable but never stored in component state. Consequently, the Overview tab always displays hardcoded values (lines 152, 162, 172, 182) regardless of what the backend returns, defeating the purpose of the fetch.

💾 Proposed fix: Store and use the fetched data

Add state to store metrics:

  const { logout, user } = useAuth()
  const [isLoading, setIsLoading] = useState(true)
+ const [metrics, setMetrics] = useState<any>(null)
  const navigate = useNavigate()

Update the fetch to store data:

  useEffect(() => {
  const fetchDashboardData = async () => {
    try {
      setIsLoading(true)
      
      const response = await fetch('/api/dashboard/metrics')
      const data = await response.json()
+     setMetrics(data)
      
      setIsLoading(false)
    } catch (error) {
      console.error('Failed to fetch dashboard data:', error)
      setIsLoading(false)
    }
  }
  fetchDashboardData()
- } , [])
+ }, [])

Then use metrics data in the metric cards instead of hardcoded values.

Minor: Fix spacing in dependency array.

Line 56 has an extra space before the comma: } , []) should be }, []).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @Frontend/src/pages/DashboardPage.tsx around lines 41 - 56, The effect fetch
never stores the API result and has a spacing typo in the dependency array; add
component state (e.g., metrics and setMetrics) to DashboardPage, update
fetchDashboardData to call setMetrics(data) after parsing the response (and keep
setting setIsLoading(false) in finally or both branches), change the Overview
metric cards to read values from the metrics state instead of hardcoded numbers,
and fix the dependency array formatting from "} , [])" to "}, [])".

@Kalpana-chavhan
Copy link
Author

hello, @Aditya30ag ,the checks are passing.

Copy link
Contributor

@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: 6

🤖 Fix all issues with AI agents
In @Frontend/src/pages/DashboardPage.tsx:
- Around line 53-56: The catch block in DashboardPage.tsx currently only logs
errors and leaves the UI without feedback; add a component-level error state
(e.g., const [error, setError] = useState<string | null>(null)) and update the
fetch error handler in the try/catch inside the effect or fetch function to call
setError(error?.message ?? String(error)) and setIsLoading(false); clear the
error on a successful fetch (setError(null)). Then render the provided error UI
snippet conditionally in the DashboardPage JSX (e.g., {error && (...)}) so users
see a friendly error message when loading fails.
- Around line 48-52: The fetch in DashboardPage.tsx does not check response.ok
before calling response.json(), so non-2xx responses will crash parsing; update
the async fetch logic (the block that calls fetch('/api/dashboard/metrics'),
then awaits response.json() and calls setMetrics) to first check if response.ok,
handle non-ok by reading error text/json and either throw a descriptive Error or
set an error state, and ensure setIsLoading(false) runs in both success and
error paths (e.g., via finally) so UI correctly stops loading.
- Around line 43-59: The effect fetchDashboardData sets metrics via setMetrics
but the JSX still renders hardcoded values; update the DashboardPage metric
cards to read from the metrics state (e.g., use metrics.totalUsers,
metrics.activeSessions, metrics.revenue, metrics.conversionRate or whatever keys
the API returns) instead of the literal numbers currently rendered, and add safe
fallbacks (e.g., show loading/0/— when metrics is null) so the component uses
the fetched data from metrics set by useEffect/fetchDashboardData.
- Around line 262-268: The DashboardPage EmptyState uses
navigate("/settings/connections") but that route isn't defined in the app
router; either add a matching route in App.tsx (create a route for
"/settings/connections" that renders the appropriate Connections or Integrations
component) or change the navigation target in DashboardPage (the onAction
callback inside the EmptyState) to an existing route such as "/dashboard" or
"/settings" so the navigate call resolves correctly; update references to the
path string in the navigate call and ensure App.tsx exports/handles the same
route name.
- Around line 247-253: The EmptyState component is calling navigate("/profile")
in DashboardPage (onAction={() => navigate("/profile")}) but there is no
/profile route registered in the router; either add a new route for the profile
page in App.tsx (e.g., <Route path="/profile" element={<ProfilePage/>} /> and
implement ProfilePage) or change the navigation target in DashboardPage to an
existing route (for example replace navigate("/profile") with
navigate("/onboarding") or navigate("/dashboard")) so the button points to a
valid route.
🧹 Nitpick comments (2)
Frontend/src/pages/DashboardPage.tsx (2)

38-38: Prefer typed interfaces over any.

The metrics state uses any, which bypasses TypeScript's type safety.

♻️ Suggested improvement

Define a proper interface for the metrics shape:

+interface DashboardMetrics {
+  totalRevenue: number
+  revenueChange: number
+  activeSponsorships: number
+  collaborations: number
+  audienceGrowth: number
+  // ... other fields
+}
+
-const [metrics, setMetrics] = useState<any>(null)
+const [metrics, setMetrics] = useState<DashboardMetrics | null>(null)

116-119: Consider adding functionality to "New Campaign" button.

The button currently has no onClick handler. Should it navigate to a campaign creation page or open a modal?

Example implementation
- <Button className="bg-[hsl(262.1,83.3%,57.8%)] text-white hover:bg-[hsl(262.1,73.3%,57.8%)]">
+ <Button 
+   className="bg-[hsl(262.1,83.3%,57.8%)] text-white hover:bg-[hsl(262.1,73.3%,57.8%)]"
+   onClick={() => navigate("/dashboard/campaigns/new")}
+ >
    <PlusCircle className="mr-2 h-4 w-4" />
    New Campaign
  </Button>
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5f7564 and 4a3936c.

📒 Files selected for processing (1)
  • Frontend/src/pages/DashboardPage.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-07-12T20:28:05.017Z
Learnt from: Saahi30
Repo: AOSSIE-Org/InPactAI PR: 98
File: Frontend/src/pages/CollaborationDetails.tsx:519-521
Timestamp: 2025-07-12T20:28:05.017Z
Learning: In frontend-only commits that use mock data, hardcoded progress values and similar placeholder data are acceptable and intentional. These values serve as placeholders for UI development and will be replaced with dynamic calculations once backend integration occurs.

Applied to files:

  • Frontend/src/pages/DashboardPage.tsx
🧬 Code graph analysis (1)
Frontend/src/pages/DashboardPage.tsx (5)
Frontend/src/context/AuthContext.tsx (1)
  • useAuth (216-222)
Frontend/src/components/dashboard/performance-metrics.tsx (1)
  • PerformanceMetrics (36-50)
Frontend/src/components/dashboard/recent-activity.tsx (1)
  • RecentActivity (3-52)
Frontend/src/components/dashboard/sponsorship-matches.tsx (1)
  • SponsorshipMatches (20-83)
Frontend/src/pages/Collaborations.tsx (1)
  • CollaborationsPage (23-251)
🔇 Additional comments (6)
Frontend/src/pages/DashboardPage.tsx (6)

1-33: Imports look good.

All new imports are properly used throughout the component for data fetching, navigation, loading states, and empty states.


64-110: LGTM! Header with proper dark mode support.

The header refactoring to use a mapped array for navigation items is clean and maintainable. Dark mode styling is consistently applied throughout.


123-129: Clean tab structure with dark mode support.

The tab layout is well-organized and properly styled for both light and dark modes.


134-146: Well-implemented skeleton loading.

The skeleton placeholders effectively mirror the layout of the metric cards, reducing perceived loading time and layout shift.


193-220: Excellent loading state handling.

The skeleton implementations for both performance metrics and recent activity provide good visual feedback during data loading.


256-258: LGTM! Proper CollaborationsPage integration.

Rendering CollaborationsPage in its own tab with showHeader={false} is the correct approach to avoid duplicate headers.

Comment on lines +43 to +59
useEffect(() => {
const fetchDashboardData = async () => {
try {
setIsLoading(true)

const response = await fetch('/api/dashboard/metrics')
const data = await response.json()
setMetrics(data)

setIsLoading(false)
} catch (error) {
console.error('Failed to fetch dashboard data:', error)
setIsLoading(false)
}
}
fetchDashboardData()
}, [])
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Fetched metrics data is never used.

The useEffect fetches data from /api/dashboard/metrics and stores it in the metrics state, but this data is never rendered. Lines 155, 165, 175, and 185 display hardcoded values instead of the fetched data.

🔧 Proposed fix to use fetched metrics
  ) : (
    <>
      <Card className="bg-white dark:bg-slate-950 border-[hsl(214.3,31.8%,91.4%)] dark:border-slate-800">
        <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
          <CardTitle className="text-sm font-medium text-muted-foreground">Total Revenue</CardTitle>
          <DollarSign className="h-4 w-4 text-muted-foreground" />
        </CardHeader>
        <CardContent>
-         <div className="text-2xl font-bold">$45,231.89</div>
-         <p className="text-xs text-green-600 dark:text-green-400 font-medium">+20.1% from last month</p>
+         <div className="text-2xl font-bold">${metrics?.totalRevenue?.toLocaleString() ?? '0'}</div>
+         <p className="text-xs text-green-600 dark:text-green-400 font-medium">
+           {metrics?.revenueChange ? `+${metrics.revenueChange}% from last month` : 'No change data'}
+         </p>
        </CardContent>
      </Card>

Apply similar changes to the other three metric cards.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @Frontend/src/pages/DashboardPage.tsx around lines 43 - 59, The effect
fetchDashboardData sets metrics via setMetrics but the JSX still renders
hardcoded values; update the DashboardPage metric cards to read from the metrics
state (e.g., use metrics.totalUsers, metrics.activeSessions, metrics.revenue,
metrics.conversionRate or whatever keys the API returns) instead of the literal
numbers currently rendered, and add safe fallbacks (e.g., show loading/0/— when
metrics is null) so the component uses the fetched data from metrics set by
useEffect/fetchDashboardData.

Comment on lines +48 to +52
const response = await fetch('/api/dashboard/metrics')
const data = await response.json()
setMetrics(data)

setIsLoading(false)
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Missing HTTP error handling.

The fetch doesn't check response.ok before calling response.json(). Non-2xx responses will cause the JSON parsing to fail with unclear errors.

🔧 Proposed fix
  const response = await fetch('/api/dashboard/metrics')
+ if (!response.ok) {
+   throw new Error(`HTTP error! status: ${response.status}`)
+ }
  const data = await response.json()
  setMetrics(data)
📝 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
const response = await fetch('/api/dashboard/metrics')
const data = await response.json()
setMetrics(data)
setIsLoading(false)
const response = await fetch('/api/dashboard/metrics')
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
const data = await response.json()
setMetrics(data)
setIsLoading(false)
🤖 Prompt for AI Agents
In @Frontend/src/pages/DashboardPage.tsx around lines 48 - 52, The fetch in
DashboardPage.tsx does not check response.ok before calling response.json(), so
non-2xx responses will crash parsing; update the async fetch logic (the block
that calls fetch('/api/dashboard/metrics'), then awaits response.json() and
calls setMetrics) to first check if response.ok, handle non-ok by reading error
text/json and either throw a descriptive Error or set an error state, and ensure
setIsLoading(false) runs in both success and error paths (e.g., via finally) so
UI correctly stops loading.

Comment on lines +53 to +56
} catch (error) {
console.error('Failed to fetch dashboard data:', error)
setIsLoading(false)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Major: No user-facing error feedback.

When the fetch fails, the error is only logged to console. Users are left with a perpetually loading state or empty dashboard with no explanation.

💡 Suggested improvement

Consider adding an error state and displaying it to users:

  const [isLoading, setIsLoading] = useState(true)
  const [metrics, setMetrics] = useState<any>(null)
+ const [error, setError] = useState<string | null>(null)
  
  useEffect(() => {
    const fetchDashboardData = async () => {
      try {
        setIsLoading(true)
+       setError(null)
        
        const response = await fetch('/api/dashboard/metrics')
        if (!response.ok) {
          throw new Error(`Failed to load dashboard data`)
        }
        const data = await response.json()
        setMetrics(data)
        
        setIsLoading(false)
      } catch (error) {
        console.error('Failed to fetch dashboard data:', error)
+       setError(error instanceof Error ? error.message : 'An error occurred')
        setIsLoading(false)
      }
    }
    fetchDashboardData()
  }, [])

Then render the error state in your UI:

{error && (
  <div className="rounded-lg bg-red-50 dark:bg-red-900/20 p-4 text-red-600 dark:text-red-400">
    <p className="font-medium">Error loading dashboard</p>
    <p className="text-sm">{error}</p>
  </div>
)}

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @Frontend/src/pages/DashboardPage.tsx around lines 53 - 56, The catch block
in DashboardPage.tsx currently only logs errors and leaves the UI without
feedback; add a component-level error state (e.g., const [error, setError] =
useState<string | null>(null)) and update the fetch error handler in the
try/catch inside the effect or fetch function to call setError(error?.message ??
String(error)) and setIsLoading(false); clear the error on a successful fetch
(setError(null)). Then render the provided error UI snippet conditionally in the
DashboardPage JSX (e.g., {error && (...)}) so users see a friendly error message
when loading fails.

Comment on lines +233 to 242
<Card className="col-span-3 bg-white dark:bg-slate-950 border-[hsl(214.3,31.8%,91.4%)] dark:border-slate-800">
<CardHeader>
<CardTitle className="text-[hsl(222.2,84%,4.9%)]">Creator Collaborations</CardTitle>
<CardDescription className="text-[hsl(215.4,16.3%,46.9%)]">Creators with complementary audiences</CardDescription>
<CardTitle>Creator Collaborations</CardTitle>
<CardDescription>Creators with complementary audiences</CardDescription>
</CardHeader>
<CardContent>
<CollaborationsPage />
</CardContent>
</Card>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Major: CollaborationsPage embedded in Card causes layout issues.

CollaborationsPage is a full-page component with its own layout structure (header, main sections, grid layouts). Embedding it within a Card on line 239 creates nested, conflicting layouts.

Additionally, line 257 already renders CollaborationsPage in a dedicated tab, making this embedded instance redundant.

🔧 Proposed fix

Consider creating a dedicated mini-component for the collaborations overview instead of embedding the full page:

  <Card className="col-span-3 bg-white dark:bg-slate-950 border-[hsl(214.3,31.8%,91.4%)] dark:border-slate-800">
    <CardHeader>
      <CardTitle>Creator Collaborations</CardTitle>
      <CardDescription>Creators with complementary audiences</CardDescription>
    </CardHeader>
    <CardContent>
-     <CollaborationsPage />
+     {isLoading ? (
+       <Skeleton className="h-40 w-full" />
+     ) : (
+       <EmptyState
+         icon={Users}
+         title="Explore Collaborations"
+         description="Find and connect with creators in your niche"
+         actionText="View All Collaborations"
+         onAction={() => navigate("/dashboard/collaborations")}
+       />
+     )}
    </CardContent>
  </Card>

Or extract a reusable CollaborationsWidget component that shows a summary without the full page structure.

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +247 to +253
<EmptyState
icon={Briefcase}
title="No active sponsorships found"
description="Our AI is looking for brands that align with your content. Check back in a few hours or update your profile to speed up the process."
actionText="Update Profile"
onAction={() => navigate("/profile")}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for profile route definitions
rg -n "path.*['\"]/?profile['\"]" --type=tsx --type=ts --type=jsx --type=js

Repository: AOSSIE-Org/InPactAI

Length of output: 90


🏁 Script executed:

#!/bin/bash
# Search for profile route definitions using valid ripgrep types
rg -n "path.*['\"]/?profile['\"]" --type=ts --type=js

Repository: AOSSIE-Org/InPactAI

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Find router/route configuration files
echo "=== Looking for route configuration files ==="
fd -e ts -e js -e tsx -e jsx | grep -i route | head -20

echo -e "\n=== Searching for 'profile' in route-like files ==="
rg -l "profile" --type=ts --type=js | head -20

echo -e "\n=== Checking DashboardPage imports ==="
head -30 Frontend/src/pages/DashboardPage.tsx

Repository: AOSSIE-Org/InPactAI

Length of output: 1854


🏁 Script executed:

#!/bin/bash
# Find the main App/router configuration
echo "=== Looking for App.tsx or similar root files ==="
fd -name "App.tsx" -o -name "App.jsx" -o -name "main.tsx" -o -name "main.jsx"

echo -e "\n=== Search for route configuration with 'profile' ==="
rg -n "profile" Frontend/src/pages/DashboardPage.tsx | head -5

echo -e "\n=== Check if there's a routes file ==="
fd -name "*route*" -type f Frontend/src/

echo -e "\n=== Look at App.tsx if it exists ==="
if [ -f "Frontend/src/App.tsx" ]; then
  cat -n Frontend/src/App.tsx
fi

Repository: AOSSIE-Org/InPactAI

Length of output: 6453


Add the missing /profile route or update the navigation path.

The EmptyState navigates to /profile when users click "Update Profile" (line 252), but this route is not defined in App.tsx. Either add the /profile route to your router configuration or update the navigation to an existing route (e.g., /dashboard or /onboarding).

🤖 Prompt for AI Agents
In @Frontend/src/pages/DashboardPage.tsx around lines 247 - 253, The EmptyState
component is calling navigate("/profile") in DashboardPage (onAction={() =>
navigate("/profile")}) but there is no /profile route registered in the router;
either add a new route for the profile page in App.tsx (e.g., <Route
path="/profile" element={<ProfilePage/>} /> and implement ProfilePage) or change
the navigation target in DashboardPage to an existing route (for example replace
navigate("/profile") with navigate("/onboarding") or navigate("/dashboard")) so
the button points to a valid route.

Comment on lines +262 to +268
<EmptyState
icon={TrendingUp}
title="Analytics Data Pending"
description="We need at least 24 hours of data to generate your first growth report. Keep creating content!"
actionText="Connect YouTube/Instagram"
onAction={() => navigate("/settings/connections")}
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for /settings/connections route definitions
rg -n "settings/connections" --type=tsx --type=ts --type=jsx --type=js -i

echo "---"
echo "Searching for common router/route files:"
fd -e ts -e tsx -e js -e jsx | grep -iE "(route|router|routing)" | head -20

Repository: AOSSIE-Org/InPactAI

Length of output: 235


🏁 Script executed:

#!/bin/bash
# Search for settings/connections with proper file types
echo "=== Searching for settings/connections route ==="
rg -n "settings/connections" --type typescript --type javascript

echo ""
echo "=== Searching for /settings routes ==="
rg -n "/settings|settings:" --type typescript --type javascript | grep -i "route\|path" | head -20

echo ""
echo "=== Looking for main router/App file ==="
fd "App\.(tsx|ts|jsx|js)$" Frontend/src/

echo ""
echo "=== Checking router configuration files ==="
fd -e ts -e tsx -e js -e jsx Frontend/src | grep -iE "router|route|routing" | head -20

Repository: AOSSIE-Org/InPactAI

Length of output: 700


🏁 Script executed:

#!/bin/bash
# Read App.tsx to check router configuration
echo "=== Contents of App.tsx ==="
cat -n "Frontend/src/App.tsx"

echo ""
echo "=== Searching for route definitions (broader pattern) ==="
grep -r "settings\|connections" Frontend/src --include="*.tsx" --include="*.ts" -n | head -30

Repository: AOSSIE-Org/InPactAI

Length of output: 5763


Add /settings/connections route or update navigation target.

The EmptyState navigates to /settings/connections on line 267, but this route is not defined in App.tsx. Either create this route in your router configuration or update the navigation to an existing route like /dashboard.

🤖 Prompt for AI Agents
In @Frontend/src/pages/DashboardPage.tsx around lines 262 - 268, The
DashboardPage EmptyState uses navigate("/settings/connections") but that route
isn't defined in the app router; either add a matching route in App.tsx (create
a route for "/settings/connections" that renders the appropriate Connections or
Integrations component) or change the navigation target in DashboardPage (the
onAction callback inside the EmptyState) to an existing route such as
"/dashboard" or "/settings" so the navigate call resolves correctly; update
references to the path string in the navigate call and ensure App.tsx
exports/handles the same route name.

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.

[UX/ENHANCEMENT] : Implement Centralized Loading States and Empty State Components

2 participants