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 getApiBase = () => typeof window !== "undefined" ? window.location.origin : ""; 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); const [savingProfile, setSavingProfile] = useState(false); const [profileFormData, setProfileFormData] = useState({ headline: "", bio: "", experience_level: "intermediate", hourly_rate: "", availability_status: "available", availability_hours_per_week: "", skills: [] as string[], }); const [newSkill, setNewSkill] = useState(""); useEffect(() => { if (!authLoading && user) { loadDashboardData(); } }, [user, authLoading]); useEffect(() => { if (creatorProfile) { setProfileFormData({ headline: creatorProfile.headline || "", bio: creatorProfile.bio || "", experience_level: creatorProfile.experience_level || "intermediate", hourly_rate: creatorProfile.hourly_rate?.toString() || "", availability_status: creatorProfile.availability_status || "available", availability_hours_per_week: creatorProfile.availability_hours_per_week?.toString() || "", skills: Array.isArray(creatorProfile.skills) ? creatorProfile.skills : [], }); } }, [creatorProfile]); const loadDashboardData = async () => { try { setLoading(true); const apiBase = getApiBase(); if (!apiBase) { throw new Error("No API base available"); } 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(`${apiBase}/api/nexus/creator/profile`, { headers: { Authorization: `Bearer ${token}` }, }); if (profileRes.ok) { setCreatorProfile(await profileRes.json()); } // Load applications const appRes = await fetch( `${apiBase}/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( `${apiBase}/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( `${apiBase}/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( `${apiBase}/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( `${apiBase}/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( `${apiBase}/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); } }; const handleSaveNexusProfile = async () => { if (!user) return; setSavingProfile(true); try { const apiBase = getApiBase(); if (!apiBase) { throw new Error("No API base available"); } const { data: { session }, } = await supabase.auth.getSession(); const token = session?.access_token; if (!token) throw new Error("No auth token"); const profileRes = await fetch(`${apiBase}/api/nexus/creator/profile`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ headline: profileFormData.headline, bio: profileFormData.bio, experience_level: profileFormData.experience_level, hourly_rate: profileFormData.hourly_rate ? parseFloat(profileFormData.hourly_rate) : null, availability_status: profileFormData.availability_status, availability_hours_per_week: profileFormData.availability_hours_per_week ? parseFloat(profileFormData.availability_hours_per_week) : null, skills: profileFormData.skills, }), }); if (!profileRes.ok) { throw new Error("Failed to save Nexus profile"); } const updatedProfile = await profileRes.json(); setCreatorProfile(updatedProfile); // Update user profile to mark Nexus as complete const userProfileRes = await fetch(`${apiBase}/api/user/profile-update`, { method: "POST", headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, body: JSON.stringify({ nexus_profile_complete: true, nexus_headline: profileFormData.headline, }), }); if (userProfileRes.ok) { aethexToast({ message: "NEXUS profile saved successfully!", type: "success", }); } } catch (error: any) { aethexToast({ message: error?.message || "Failed to save profile", type: "error", }); } finally { setSavingProfile(false); } }; const addSkill = () => { if (newSkill.trim()) { setProfileFormData({ ...profileFormData, skills: [...profileFormData.skills, newSkill.trim()], }); setNewSkill(""); } }; const removeSkill = (index: number) => { setProfileFormData({ ...profileFormData, skills: profileFormData.skills.filter((_, i) => i !== index), }); }; 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
setProfileFormData({ ...profileFormData, headline: e.target.value, }) } placeholder="E.g., Senior Game Developer | Unreal Engine Specialist" className="w-full px-4 py-2 bg-black/30 border border-purple-500/20 rounded-lg text-white placeholder-gray-500" />