diff --git a/client/pages/dashboards/NexusDashboard.tsx b/client/pages/dashboards/NexusDashboard.tsx new file mode 100644 index 00000000..ad8c63c7 --- /dev/null +++ b/client/pages/dashboards/NexusDashboard.tsx @@ -0,0 +1,481 @@ +import { useState, useEffect } from "react"; +import { useNavigate } from "react-router-dom"; +import Layout from "@/components/Layout"; +import { Button } from "@/components/ui/button"; +import { useAuth } from "@/contexts/AuthContext"; +import { aethexToast } from "@/lib/aethex-toast"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import LoadingScreen from "@/components/LoadingScreen"; +import { + Briefcase, + DollarSign, + FileText, + CheckCircle, + AlertCircle, + Clock, + TrendingUp, + Users, + ArrowRight, + Heart, + Star, + ExternalLink, +} from "lucide-react"; + +const API_BASE = import.meta.env.VITE_API_BASE || ""; + +export default function NexusDashboard() { + const navigate = useNavigate(); + const { user, loading: authLoading } = useAuth(); + const [activeTab, setActiveTab] = useState("overview"); + const [creatorProfile, setCreatorProfile] = useState(null); + const [applications, setApplications] = useState([]); + const [contracts, setContracts] = useState([]); + const [payoutInfo, setPayoutInfo] = useState(null); + const [loading, setLoading] = useState(true); + + useEffect(() => { + if (!authLoading && user) { + loadDashboardData(); + } + }, [user, authLoading]); + + const loadDashboardData = async () => { + try { + setLoading(true); + const token = (await (window as any).supabaseClient.auth.getSession()).data?.session?.access_token; + if (!token) throw new Error("No auth token"); + + // Load creator profile + const profileRes = await fetch(`${API_BASE}/api/nexus/creator/profile`, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (profileRes.ok) { + setCreatorProfile(await profileRes.json()); + } + + // Load applications + const appRes = await fetch(`${API_BASE}/api/nexus/creator/applications?limit=10`, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (appRes.ok) { + const data = await appRes.json(); + setApplications(data.applications || []); + } + + // Load contracts + const contractRes = await fetch(`${API_BASE}/api/nexus/creator/contracts?limit=10`, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (contractRes.ok) { + const data = await contractRes.json(); + setContracts(data.contracts || []); + } + + // Load payout info + const payoutRes = await fetch(`${API_BASE}/api/nexus/creator/payouts?limit=10`, { + headers: { Authorization: `Bearer ${token}` }, + }); + if (payoutRes.ok) { + const data = await payoutRes.json(); + setPayoutInfo(data.summary); + } + } catch (error: any) { + aethexToast({ + message: "Failed to load dashboard data", + type: "error", + }); + } finally { + setLoading(false); + } + }; + + if (authLoading || loading) { + return ; + } + + if (!user) { + return ( + +
+
+

+ Sign In to NEXUS +

+

Access the marketplace and start earning

+ +
+
+
+ ); + } + + const isProfileComplete = creatorProfile?.verified || (creatorProfile?.headline && creatorProfile?.skills?.length > 0); + const pendingApplications = applications.filter((a) => a.status === "submitted").length; + const activeContracts = contracts.filter((c) => c.status === "active").length; + + return ( + +
+
+ {/* Header */} +
+
+
+

+ NEXUS Marketplace +

+

+ Showcase your skills and land paid opportunities +

+
+
+ + {/* Setup Banner */} + {!isProfileComplete && ( + + +
+
+

+ + Complete Your NEXUS Profile +

+

+ Add a headline, skills, and hourly rate to attract clients and start bidding on opportunities +

+
+ +
+
+
+ )} +
+ + {/* Tabs */} + + + Overview + Applications + Contracts + Profile + + + {/* Overview Tab */} + +
+ {/* Stat: Total Earnings */} + + +
+

Total Earnings

+ +
+

+ ${(payoutInfo?.total_earnings || 0).toLocaleString('en-US', { minimumFractionDigits: 2 })} +

+
+
+ + {/* Stat: Pending Payouts */} + + +
+

Pending Payouts

+ +
+

+ ${(payoutInfo?.pending_payouts || 0).toLocaleString('en-US', { minimumFractionDigits: 2 })} +

+
+
+ + {/* Stat: Pending Applications */} + + +
+

Pending Applications

+ +
+

{pendingApplications}

+
+
+ + {/* Stat: Active Contracts */} + + +
+

Active Contracts

+ +
+

{activeContracts}

+
+
+
+ + {/* Recent Applications */} + + + Recent Applications + Your most recent bids + + + {applications.length === 0 ? ( +
+ +

No applications yet. Browse opportunities to get started!

+ +
+ ) : ( +
+ {applications.slice(0, 5).map((app: any) => ( +
+
+

{app.opportunity?.title}

+

{app.opportunity?.category}

+
+ + {app.status} + +
+ ))} +
+ )} +
+
+ + {/* CTA Section */} + {applications.length < 3 && ( + + +

Ready to Earn?

+

+ Browse thousands of opportunities from clients looking for talented creators +

+ +
+
+ )} +
+ + {/* Applications Tab */} + + + + My Applications + Track all your bids and applications + + + {applications.length === 0 ? ( +
+ +

No applications submitted yet

+ +
+ ) : ( +
+ {applications.map((app: any) => ( +
+
+
+

{app.opportunity?.title}

+

{app.opportunity?.description?.substring(0, 100)}...

+
+ {app.status} +
+
+ Proposed: ${app.proposed_rate?.toLocaleString()}/hr + Submitted {new Date(app.created_at).toLocaleDateString()} +
+
+ ))} +
+ )} +
+
+
+ + {/* Contracts Tab */} + + + + Active Contracts + Manage your ongoing work + + + {contracts.length === 0 ? ( +
+ +

No active contracts

+
+ ) : ( +
+ {contracts.map((contract: any) => ( +
+
+
+

{contract.title}

+

Total: ${contract.total_amount?.toLocaleString()}

+
+ {contract.status} +
+ + {/* Milestones */} + {contract.milestones?.length > 0 && ( +
+

Progress

+
+ {contract.milestones.map((m: any) => ( +
+ + {m.description} + ${m.amount?.toLocaleString()} +
+ ))} +
+
+ )} +
+ ))} +
+ )} +
+
+
+ + {/* Profile Tab */} + + + + Your NEXUS Profile + Your marketplace identity + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + {/* Verification Status */} + {creatorProfile?.verified && ( +
+ + Profile Verified ✓ +
+ )} + +

+ To edit your profile, go to Dashboard → Profile Settings +

+
+
+ + {/* Payout Setup */} + + + Payout Information + Manage how you receive payments + + + +

+ Connect your Stripe account to receive payouts for completed contracts +

+
+
+
+
+
+
+
+ ); +}