import { useState, useEffect } from 'react'; import { 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 { DashboardSkeleton } from '../components/common/Skeleton'; import EmptyState from '../components/common/EmptyState'; import ConfirmationModal from '../components/modals/ConfirmationModal'; import { DashboardEventCard, DashboardMatchCard, RecordingSummaryCard, IncomingRequestCard, OutgoingRequestCard, } from '../components/dashboard'; import { Calendar, Users, MessageCircle, ChevronRight, Inbox, Send, Video, } from 'lucide-react'; const DashboardPage = () => { const { user } = useAuth(); const [data, setData] = useState(null); const [loading, setLoading] = useState(true); const [showDeclineModal, setShowDeclineModal] = useState(false); const [showCancelModal, setShowCancelModal] = useState(false); const [matchToProcess, setMatchToProcess] = useState(null); 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 = (matchSlug) => { setMatchToProcess(matchSlug); setShowDeclineModal(true); }; const confirmRejectMatch = async () => { if (!matchToProcess) return; try { setProcessingMatchId(matchToProcess); await matchesAPI.deleteMatch(matchToProcess); 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); setShowDeclineModal(false); setMatchToProcess(null); } }; const handleCancelRequest = (matchSlug) => { setMatchToProcess(matchSlug); setShowCancelModal(true); }; const confirmCancelRequest = async () => { if (!matchToProcess) return; try { setProcessingMatchId(matchToProcess); await matchesAPI.deleteMatch(matchToProcess); 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); setShowCancelModal(false); setMatchToProcess(null); } }; if (loading) { return ( ); } if (error) { return (
{error}
); } const { activeEvents, activeMatches, matchRequests } = data || {}; const hasIncoming = matchRequests?.incoming?.length > 0; const hasOutgoing = matchRequests?.outgoing?.length > 0; // Filter events with recording suggestions const eventsWithRecordings = activeEvents?.filter( (event) => event.recordingSuggestions && (event.recordingSuggestions.toBeRecorded.length > 0 || event.recordingSuggestions.toRecord.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 } /> )}
{/* Recording Assignments Section */} {eventsWithRecordings.length > 0 && (

{eventsWithRecordings.map((event) => ( ))}
)} {/* 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) => ( ))}
)}
)}
{/* Decline Confirmation Modal */} { setShowDeclineModal(false); setMatchToProcess(null); }} onConfirm={confirmRejectMatch} title="Decline Match Request" message="Are you sure you want to decline this request? This action cannot be undone." confirmText="Decline" cancelText="Cancel" isLoading={processingMatchId === matchToProcess} loadingText="Declining..." /> {/* Cancel Confirmation Modal */} { setShowCancelModal(false); setMatchToProcess(null); }} onConfirm={confirmCancelRequest} title="Cancel Match Request" message="Are you sure you want to cancel this request? This action cannot be undone." confirmText="Cancel Request" cancelText="Keep Request" isLoading={processingMatchId === matchToProcess} loadingText="Cancelling..." />
); }; export default DashboardPage;