From cb219e1f02a1829b8f4f539136110c5083ac8258 Mon Sep 17 00:00:00 2001 From: Kalpana Chavhan Date: Tue, 6 Jan 2026 19:51:45 +0530 Subject: [PATCH 1/3] feat: enhance dashboard UX and fix backend dependencies --- Backend/app/schemas/schema.py | 20 +- Frontend/src/components/ui/EmptyState.tsx | 38 +++ Frontend/src/components/ui/Skeleton.tsx | 29 ++ Frontend/src/pages/DashboardPage.tsx | 345 ++++++++++++---------- 4 files changed, 264 insertions(+), 168 deletions(-) create mode 100644 Frontend/src/components/ui/EmptyState.tsx create mode 100644 Frontend/src/components/ui/Skeleton.tsx diff --git a/Backend/app/schemas/schema.py b/Backend/app/schemas/schema.py index 7389488..97c798d 100644 --- a/Backend/app/schemas/schema.py +++ b/Backend/app/schemas/schema.py @@ -1,10 +1,22 @@ -from pydantic import BaseModel -from typing import Optional, Dict +from pydantic import BaseModel, EmailStr +from typing import Optional, Dict, Any, List from datetime import datetime + +class LoginResponse(BaseModel): + message: str + user_id: str + email: str + name: Optional[str] = None + role: Optional[str] = None + onboarding_completed: bool = False + # The session object from Supabase contains access_token, refresh_token, etc. + session: Optional[Dict[str, Any]] = None +# --- FIX FOR ISSUE #258 END --- + class UserCreate(BaseModel): username: str - email: str + email: EmailStr # Uses EmailStr for better validation role: str profile_image: Optional[str] = None bio: Optional[str] = None @@ -50,4 +62,4 @@ class SponsorshipPaymentCreate(BaseModel): class CollaborationCreate(BaseModel): creator_1_id: str creator_2_id: str - collaboration_details: str + collaboration_details: str \ No newline at end of file diff --git a/Frontend/src/components/ui/EmptyState.tsx b/Frontend/src/components/ui/EmptyState.tsx new file mode 100644 index 0000000..6d532d4 --- /dev/null +++ b/Frontend/src/components/ui/EmptyState.tsx @@ -0,0 +1,38 @@ +import React from 'react'; +import { LucideIcon } from 'lucide-react'; + +interface EmptyStateProps { + icon?: LucideIcon; + title: string; + description: string; + actionText?: string; + onAction?: () => void; +} + +const EmptyState: React.FC = ({ + icon: Icon, + title, + description, + actionText, + onAction +}) => { + return ( +
+ {Icon && } +

{title}

+

+ {description} +

+ {actionText && onAction && ( + + )} +
+ ); +}; + +export default EmptyState; \ No newline at end of file diff --git a/Frontend/src/components/ui/Skeleton.tsx b/Frontend/src/components/ui/Skeleton.tsx new file mode 100644 index 0000000..63fbc9f --- /dev/null +++ b/Frontend/src/components/ui/Skeleton.tsx @@ -0,0 +1,29 @@ +import React from "react"; + +interface SkeletonProps extends React.HTMLAttributes +{ + className?: string; + variant?: "rect" | "circle"; +} + + +const Skeleton: React.FC = ({ + 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 ( +
+ ); +}; + +export default Skeleton; \ No newline at end of file diff --git a/Frontend/src/pages/DashboardPage.tsx b/Frontend/src/pages/DashboardPage.tsx index e5a8fc2..742e692 100644 --- a/Frontend/src/pages/DashboardPage.tsx +++ b/Frontend/src/pages/DashboardPage.tsx @@ -1,3 +1,4 @@ +import React, { useState, useEffect } from "react" import { Link } from "react-router-dom" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../components/ui/card" import { Tabs, TabsContent, TabsList, TabsTrigger } from "../components/ui/tabs" @@ -10,184 +11,209 @@ import { Briefcase, DollarSign, FileText, - Icon, LayoutDashboard, LogOut, MessageSquare, Rocket, Search, Users, + PlusCircle, + TrendingUp, } from "lucide-react" import { PerformanceMetrics } from "../components/dashboard/performance-metrics" import { RecentActivity } from "../components/dashboard/recent-activity" import { SponsorshipMatches } from "../components/dashboard/sponsorship-matches" import { useAuth } from "../context/AuthContext" -import CollaborationsPage from "./Collaborations"; +import CollaborationsPage from "./Collaborations" + +// New UX Component Imports +import Skeleton from "../components/ui/Skeleton" +import EmptyState from "../components/ui/EmptyState" export default function DashboardPage() { - const {logout, user} = useAuth(); + const { logout, user } = useAuth() + const [isLoading, setIsLoading] = useState(true) + + // Simulate data fetching on mount + useEffect(() => { + const timer = setTimeout(() => setIsLoading(false), 1500) + return () => clearTimeout(timer) + }, []) return ( -
-
+
+
- + Inpact
- {[ - { to: "/dashboard", icon: LayoutDashboard, label: "Dashboard" }, - { to: "/dashboard/sponsorships", icon: Briefcase, label: "Sponsorships" }, - { to: "/dashboard/collaborations", icon: Users, label: "Collaborations" }, - { to: "/dashboard/contracts", icon: FileText, label: "Contracts" }, - { to: "/dashboard/analytics", icon: BarChart3, label: "Analytics" }, - { to: "/dashboard/messages", icon: MessageSquare, label: "Messages" }, - ].map(({ to, icon: Icon, label }) => ( - - ))} -
-
-
- - -
- - - -
-
+ {[ + { to: "/dashboard", icon: LayoutDashboard, label: "Dashboard" }, + { to: "/dashboard/sponsorships", icon: Briefcase, label: "Sponsorships" }, + { to: "/dashboard/collaborations", icon: Users, label: "Collaborations" }, + { to: "/dashboard/contracts", icon: FileText, label: "Contracts" }, + { to: "/dashboard/analytics", icon: BarChart3, label: "Analytics" }, + { to: "/dashboard/messages", icon: MessageSquare, label: "Messages" }, + ].map(({ to, icon: Icon, label }) => ( + + ))} +
+
+
+ + +
+ + + +
+
+

Dashboard

-
+ - - - Overview - - - Sponsorships - - - Collaborations - - - Analytics - + + Overview + Sponsorships + Collaborations + Analytics + + {/* --- METRICS SECTION WITH SKELETONS --- */}
- - - Total Revenue - - - -
$45,231.89
-

+20.1% from last month

-
-
- - - Active Sponsorships - - - -
12
-

+3 from last month

-
-
- - - Collaborations - - - -
8
-

+2 from last month

-
-
- - - Audience Growth - - - -
+12.5%
-

+2.1% from last month

-
-
+ {isLoading ? ( + Array.from({ length: 4 }).map((_, i) => ( + + + + + + + + + + + )) + ) : ( + <> + + + Total Revenue + + + +
$45,231.89
+

+20.1% from last month

+
+
+ + + Active Sponsorships + + + +
12
+

+3 from last month

+
+
+ + + Collaborations + + + +
8
+

+2 from last month

+
+
+ + + Audience Growth + + + +
+12.5%
+

+2.1% from last month

+
+
+ + )}
+ + {/* --- ACTIVITY & METRICS --- */}
- + - Performance Metrics + Performance Metrics - + {isLoading ? : } - + - Recent Activity - Your latest interactions and updates + Recent Activity + Your latest interactions and updates - + {isLoading ? ( +
+ + + +
+ ) : ( + + )}
+ + {/* --- AI MATCHES & COLLABORATIONS --- */}
- + - AI-Matched Sponsorships - Brands that match your audience and content + AI-Matched Sponsorships + Brands that match your audience and content - + {isLoading ? : } - + - Creator Collaborations - Creators with complementary audiences + Creator Collaborations + Creators with complementary audiences @@ -195,43 +221,34 @@ export default function DashboardPage() {
+ + {/* --- SPONSORSHIPS TAB WITH EMPTY STATE --- */} - - - AI-Driven Sponsorship Matchmaking - Discover brands that align with your audience and content style - - -
-

Coming Soon

-

- The full sponsorship matchmaking interface will be available here. -

-
-
-
-
- - - - - - - Performance Analytics & ROI Tracking - Track sponsorship performance and campaign success - - -
-

Coming Soon

-

- The full analytics dashboard will be available here. -

-
-
-
-
-
-
-
- ) - } \ No newline at end of file + console.log("Navigate to profile")} + /> + + + + + + + {/* --- ANALYTICS TAB WITH EMPTY STATE --- */} + + console.log("Navigate to connections")} + /> + + + + + ) +} \ No newline at end of file From f5f7564387195ed2ab878f49ef67da76fe6c36d0 Mon Sep 17 00:00:00 2001 From: Kalpana Chavhan Date: Fri, 9 Jan 2026 21:35:27 +0530 Subject: [PATCH 2/3] solved issues in dashboard-ux-refinement --- Backend/app/schemas/schema.py | 2 +- Frontend/src/pages/DashboardPage.tsx | 30 ++++++++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/Backend/app/schemas/schema.py b/Backend/app/schemas/schema.py index 97c798d..63df1cb 100644 --- a/Backend/app/schemas/schema.py +++ b/Backend/app/schemas/schema.py @@ -6,7 +6,7 @@ class LoginResponse(BaseModel): message: str user_id: str - email: str + email: EmailStr name: Optional[str] = None role: Optional[str] = None onboarding_completed: bool = False diff --git a/Frontend/src/pages/DashboardPage.tsx b/Frontend/src/pages/DashboardPage.tsx index 742e692..ec0f039 100644 --- a/Frontend/src/pages/DashboardPage.tsx +++ b/Frontend/src/pages/DashboardPage.tsx @@ -25,6 +25,7 @@ import { RecentActivity } from "../components/dashboard/recent-activity" import { SponsorshipMatches } from "../components/dashboard/sponsorship-matches" import { useAuth } from "../context/AuthContext" import CollaborationsPage from "./Collaborations" +import { useNavigate } from "react-router-dom" // New UX Component Imports import Skeleton from "../components/ui/Skeleton" @@ -33,12 +34,28 @@ import EmptyState from "../components/ui/EmptyState" export default function DashboardPage() { const { logout, user } = useAuth() const [isLoading, setIsLoading] = useState(true) + const navigate = useNavigate() - // Simulate data fetching on mount + + useEffect(() => { - const timer = setTimeout(() => setIsLoading(false), 1500) - return () => clearTimeout(timer) - }, []) + 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() + } , []) + + return (
@@ -230,6 +247,7 @@ export default function DashboardPage() { 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={() => console.log("Navigate to profile")} + onAction={() => navigate("/profile")} /> @@ -237,14 +255,14 @@ export default function DashboardPage() { - {/* --- ANALYTICS TAB WITH EMPTY STATE --- */} + console.log("Navigate to connections")} + onAction={() => navigate("/settings/connections")} /> From 4a3936cbf1d8615247c51a8d5099f55530b764d4 Mon Sep 17 00:00:00 2001 From: Kalpana Chavhan Date: Fri, 9 Jan 2026 21:58:30 +0530 Subject: [PATCH 3/3] solved issues in dashboard-ux-refinements --- Frontend/src/pages/DashboardPage.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Frontend/src/pages/DashboardPage.tsx b/Frontend/src/pages/DashboardPage.tsx index ec0f039..1311079 100644 --- a/Frontend/src/pages/DashboardPage.tsx +++ b/Frontend/src/pages/DashboardPage.tsx @@ -25,6 +25,7 @@ import { RecentActivity } from "../components/dashboard/recent-activity" import { SponsorshipMatches } from "../components/dashboard/sponsorship-matches" import { useAuth } from "../context/AuthContext" import CollaborationsPage from "./Collaborations" + import { useNavigate } from "react-router-dom" // New UX Component Imports @@ -34,6 +35,7 @@ import EmptyState from "../components/ui/EmptyState" export default function DashboardPage() { const { logout, user } = useAuth() const [isLoading, setIsLoading] = useState(true) + const [metrics, setMetrics] = useState(null) const navigate = useNavigate() @@ -45,6 +47,7 @@ export default function DashboardPage() { const response = await fetch('/api/dashboard/metrics') const data = await response.json() + setMetrics(data) setIsLoading(false) } catch (error) { @@ -53,7 +56,7 @@ export default function DashboardPage() { } } fetchDashboardData() - } , []) + }, []) @@ -246,7 +249,6 @@ export default function DashboardPage() { 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={() => console.log("Navigate to profile")} onAction={() => navigate("/profile")} />