import { useState, useEffect } from 'react'; import { useNavigate, Link } from 'react-router-dom'; import toast from 'react-hot-toast'; import Layout from '../components/layout/Layout'; import { useAuth } from '../contexts/AuthContext'; import { dashboardAPI, matchesAPI } from '../services/api'; import { connectSocket, disconnectSocket, getSocket } from '../services/socket'; import HeatBadges from '../components/heats/HeatBadges'; import { Calendar, MapPin, Users, MessageCircle, Video, Star, Check, X, Loader2, Clock, ChevronRight, Inbox, Send, } from 'lucide-react'; const DashboardPage = () => { const { user } = useAuth(); const navigate = useNavigate(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [processingMatchId, setProcessingMatchId] = useState(null); useEffect(() => { loadDashboard(); // Connect to socket for real-time updates const token = localStorage.getItem('token'); if (token && user) { connectSocket(token, user.id); const socket = getSocket(); if (socket) { socket.on('match_request_received', handleMatchRequest); socket.on('match_accepted', handleMatchAccepted); socket.on('match_cancelled', handleRealtimeUpdate); socket.on('new_message', handleRealtimeUpdate); } } return () => { const socket = getSocket(); if (socket) { socket.off('match_request_received', handleMatchRequest); socket.off('match_accepted', handleMatchAccepted); socket.off('match_cancelled', handleRealtimeUpdate); socket.off('new_message', handleRealtimeUpdate); } disconnectSocket(); }; }, [user]); const handleMatchRequest = (data) => { toast.success(`New match request from ${data.requesterUsername || 'someone'}!`, { icon: '📨', }); loadDashboard(); }; const handleMatchAccepted = (data) => { toast.success('Match accepted! You can now chat.', { icon: '🎉', }); loadDashboard(); }; const loadDashboard = async () => { try { setLoading(true); const result = await dashboardAPI.getData(); setData(result); } catch (err) { console.error('Failed to load dashboard:', err); setError('Failed to load dashboard'); } finally { setLoading(false); } }; const handleRealtimeUpdate = () => { loadDashboard(); }; const handleAcceptMatch = async (matchSlug) => { try { setProcessingMatchId(matchSlug); await matchesAPI.acceptMatch(matchSlug); toast.success('Match accepted! You can now chat.', { icon: '🎉' }); await loadDashboard(); } catch (err) { console.error('Failed to accept match:', err); toast.error('Failed to accept match. Please try again.'); } finally { setProcessingMatchId(null); } }; const handleRejectMatch = async (matchSlug) => { if (!confirm('Are you sure you want to decline this request?')) return; try { setProcessingMatchId(matchSlug); await matchesAPI.deleteMatch(matchSlug); toast.success('Request declined.'); await loadDashboard(); } catch (err) { console.error('Failed to reject match:', err); toast.error('Failed to decline request. Please try again.'); } finally { setProcessingMatchId(null); } }; const handleCancelRequest = async (matchSlug) => { if (!confirm('Are you sure you want to cancel this request?')) return; try { setProcessingMatchId(matchSlug); await matchesAPI.deleteMatch(matchSlug); toast.success('Request cancelled.'); await loadDashboard(); } catch (err) { console.error('Failed to cancel request:', err); toast.error('Failed to cancel request. Please try again.'); } finally { setProcessingMatchId(null); } }; if (loading) { return (

Loading dashboard...

); } if (error) { return (
{error}
); } const { activeEvents, activeMatches, matchRequests } = data || {}; const hasIncoming = matchRequests?.incoming?.length > 0; const hasOutgoing = matchRequests?.outgoing?.length > 0; return (

Dashboard

Welcome back, {user?.firstName || user?.username}!

{/* Active Events Section */}

Your Events

Browse all
{activeEvents?.length > 0 ? (
{activeEvents.map((event) => ( ))}
) : ( } title="No active events" description="Check in at an event to start connecting with other dancers!" action={ Browse Events } /> )}
{/* Active Matches Section */}

Active Matches

View all
{activeMatches?.length > 0 ? (
{activeMatches.map((match) => ( ))}
) : ( } title="No active matches" description="Join an event chat and send match requests to start collaborating!" /> )}
{/* Match Requests Section */} {(hasIncoming || hasOutgoing) && (

Match Requests

{/* Incoming Requests */} {hasIncoming && (

Incoming ({matchRequests.incoming.length})

{matchRequests.incoming.map((request) => ( ))}
)} {/* Outgoing Requests */} {hasOutgoing && (

Outgoing ({matchRequests.outgoing.length})

{matchRequests.outgoing.map((request) => ( ))}
)}
)}
); }; // Event Card Component const EventCard = ({ event }) => { const navigate = useNavigate(); const formatDateRange = (start, end) => { const startDate = new Date(start); const endDate = new Date(end); const options = { month: 'short', day: 'numeric' }; return `${startDate.toLocaleDateString('en-US', options)} - ${endDate.toLocaleDateString('en-US', options)}`; }; return (

{event.name}

Joined
{event.location}
{formatDateRange(event.startDate, event.endDate)}
{event.participantsCount} participants
{event.myHeats?.length > 0 && (

Your heats:

)}
); }; // Match Card Component const MatchCard = ({ match }) => { const navigate = useNavigate(); const { partner, event, videoExchange, ratings } = match; // Can rate when video exchange is complete and user hasn't rated yet const canRate = videoExchange?.sentByMe && videoExchange?.receivedFromPartner && !ratings?.ratedByMe; return (
{/* Avatar */} {partner.username} {/* Content */}

{partner.firstName && partner.lastName ? `${partner.firstName} ${partner.lastName}` : partner.username}

@{partner.username}

{event.name}

{/* Status Indicators */}
{/* Actions */}
{canRate && ( )}
); }; // Video Exchange Status const VideoStatus = ({ exchange }) => { const sent = exchange?.sentByMe; const received = exchange?.receivedFromPartner; return (
); }; // Rating Status const RatingStatus = ({ ratings }) => { const ratedByMe = ratings?.ratedByMe; const ratedByPartner = ratings?.ratedByPartner; return (
{ratedByMe ? : } You | {ratedByPartner ? : } Partner
); }; // Incoming Request Card const IncomingRequestCard = ({ request, onAccept, onReject, processing }) => { const { requester, event, requesterHeats } = request; return (
{requester.username}

{requester.firstName && requester.lastName ? `${requester.firstName} ${requester.lastName}` : requester.username}

@{requester.username}

{event.name}

{requesterHeats?.length > 0 && (
)}
); }; // Outgoing Request Card const OutgoingRequestCard = ({ request, onCancel, processing }) => { const { recipient, event } = request; return (
{recipient.username}

{recipient.firstName && recipient.lastName ? `${recipient.firstName} ${recipient.lastName}` : recipient.username}

@{recipient.username}

{event.name}

Waiting for response...

); }; // Empty State Component const EmptyState = ({ icon, title, description, action }) => { return (
{icon}

{title}

{description}

{action}
); }; export default DashboardPage;