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 { supabase } from "@/lib/supabase"; 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 ContractsWidget from "@/components/ContractsWidget"; import ApplicationsWidget from "@/components/ApplicationsWidget"; import PostedOpportunitiesWidget from "@/components/PostedOpportunitiesWidget"; import ApplicantTrackerWidget from "@/components/ApplicantTrackerWidget"; import { Briefcase, DollarSign, FileText, CheckCircle, AlertCircle, Clock, TrendingUp, Users, ArrowRight, Heart, Star, ExternalLink, ToggleLeft, ToggleRight, } from "lucide-react"; const API_BASE = import.meta.env.VITE_API_BASE || ""; type ViewMode = "creator" | "client"; export default function NexusDashboard() { const navigate = useNavigate(); const { user, loading: authLoading } = useAuth(); const [viewMode, setViewMode] = useState("creator"); const [activeTab, setActiveTab] = useState("overview"); const [creatorProfile, setCreatorProfile] = useState(null); const [applications, setApplications] = useState([]); const [contracts, setContracts] = useState([]); const [payoutInfo, setPayoutInfo] = useState(null); const [postedOpportunities, setPostedOpportunities] = useState([]); const [applicants, setApplicants] = useState([]); const [paymentHistory, setPaymentHistory] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { if (!authLoading && user) { loadDashboardData(); } }, [user, authLoading]); const loadDashboardData = async () => { try { setLoading(true); const { data: { session } } = await supabase.auth.getSession(); const token = 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); } // Load client data (posted opportunities) const oppRes = await fetch(`${API_BASE}/api/nexus/client/opportunities?limit=10`, { headers: { Authorization: `Bearer ${token}` }, }); if (oppRes.ok) { const data = await oppRes.json(); setPostedOpportunities(data.opportunities || []); } // Load applicants const appliRes = await fetch(`${API_BASE}/api/nexus/client/applicants?limit=50`, { headers: { Authorization: `Bearer ${token}` }, }); if (appliRes.ok) { const data = await appliRes.json(); setApplicants(data.applicants || []); } // Load payment history const payHistRes = await fetch(`${API_BASE}/api/nexus/client/payment-history?limit=10`, { headers: { Authorization: `Bearer ${token}` }, }); if (payHistRes.ok) { const data = await payHistRes.json(); setPaymentHistory(data.payments || []); } } 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; const openOpportunities = postedOpportunities.filter((o) => o.status === "open").length; const applicantStats = { applied: applicants.filter((a) => a.status === "applied").length, interviewing: applicants.filter((a) => a.status === "interviewing").length, hired: applicants.filter((a) => a.status === "hired").length, }; return (
{/* Header with View Toggle */}

NEXUS Marketplace

{viewMode === "creator" ? "Showcase your skills and land paid opportunities" : "Hire talent and manage your team"}

{/* View Toggle */}
{/* Setup Banner (Creator View) */} {viewMode === "creator" && !isProfileComplete && (

Complete Your NEXUS Profile

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

)}
{/* Creator View */} {viewMode === "creator" && ( <> {/* 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 */}

Maximize Your Earnings

Complete your profile and start bidding on opportunities

{/* Applications Tab */} ({ id: a.id, opportunity: a.opportunity, status: a.status || "submitted", proposed_rate: a.proposed_rate, proposed_rate_type: a.proposed_rate_type || "hourly", cover_letter: a.cover_letter, created_at: a.created_at, }))} title="My Job Applications" description="Track all your bids and applications" accentColor="purple" onViewDetails={(app) => { if (app.opportunity?.id) { navigate(`/opportunities/${app.opportunity.id}`); } }} showCTA={applications.length < 5} ctaText="Browse More Opportunities" onCTA={() => navigate("/nexus")} /> {/* Contracts Tab */} ({ id: c.id, title: c.title || "Untitled Contract", client_name: c.client?.full_name || "Client", status: c.status || "active", total_amount: c.total_amount || 0, paid_amount: c.payments?.reduce((sum: number, p: any) => sum + (p.amount || 0), 0) || 0, start_date: c.start_date, end_date: c.end_date, description: c.description, milestones: c.milestones || [], }))} title="My Active Contracts" description="Manage your ongoing work and track payments" type="creator" accentColor="purple" /> {/* 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

)} {/* Client View */} {viewMode === "client" && ( <> Overview Opportunities Applicants Contracts {/* Overview Tab */}
{/* Stat: Open Opportunities */}

Open Opportunities

{openOpportunities}

{/* Stat: Total Applicants */}

Total Applicants

{applicants.length}

{/* Stat: Active Contracts */}

Active Contracts

{contracts.filter(c => c.status === "active").length}

{/* Stat: Total Spent */}

Total Spent

${(paymentHistory.reduce((acc, p) => acc + (p.amount || 0), 0)).toLocaleString('en-US', { minimumFractionDigits: 2 })}

{/* Quick Stats */}

Reviewing

{applicantStats.applied}

Interviewing

{applicantStats.interviewing}

Hired

{applicantStats.hired}

{/* CTA Section */}

Hire Top Talent

Post opportunities and find the perfect creators for your projects

{/* Opportunities Tab */} ({ id: o.id, title: o.title, description: o.description, category: o.category, budget: o.budget, status: o.status || "open", applications_count: o.applications_count, created_at: o.created_at, deadline: o.deadline, required_skills: o.required_skills, experience_level: o.experience_level, }))} title="My Posted Opportunities" description="Manage your job postings and track applications" accentColor="blue" onViewApplications={(oppId) => { navigate(`/opportunities/${oppId}/applications`); }} onViewDetails={(oppId) => { navigate(`/opportunities/${oppId}`); }} onEdit={(oppId) => { navigate(`/opportunities/${oppId}/edit`); }} /> {postedOpportunities.length === 0 && (

Start Hiring Talent

Post opportunities and find the perfect creators for your projects

)}
{/* Applicants Tab - Kanban Style */} ({ id: a.id, user: a.user, opportunity: a.opportunity, status: a.status || "applied", rating: a.rating, notes: a.notes, applied_at: a.created_at, }))} title="Applicant Tracker" description="Manage applicants and track them through your hiring pipeline" onViewProfile={(applicantId) => { navigate(`/applicants/${applicantId}`); }} onMessage={(applicantId) => { navigate(`/applicants/${applicantId}/message`); }} onUpdateStatus={(applicantId, newStatus) => { aethexToast({ message: `Updated applicant status to ${newStatus}`, type: "success", }); }} accentColor="blue" /> {/* Contracts Tab */} ({ id: c.id, title: c.title || "Untitled Contract", creator_name: c.creator?.full_name || "Creator", status: c.status || "active", total_amount: c.total_amount || 0, paid_amount: c.payments?.reduce((sum: number, p: any) => sum + (p.amount || 0), 0) || 0, start_date: c.start_date, end_date: c.end_date, description: c.description, milestones: c.milestones || [], }))} title="My Active Contracts" description="Track all active contracts with creators" type="client" accentColor="blue" /> {/* Payment History */} {paymentHistory.length > 0 && ( Payment History Recent payments made to creators
{paymentHistory.map((payment: any) => (

{payment.description}

{new Date(payment.created_at).toLocaleDateString()}

${payment.amount?.toLocaleString()}

))}
)}
)}
); }