diff --git a/frontend/src/components/dashboard/RecordingSummaryCard.jsx b/frontend/src/components/dashboard/RecordingSummaryCard.jsx
new file mode 100644
index 0000000..8a3ff14
--- /dev/null
+++ b/frontend/src/components/dashboard/RecordingSummaryCard.jsx
@@ -0,0 +1,163 @@
+import { useNavigate } from 'react-router-dom';
+import { Video, Clock, CheckCircle, XCircle, ChevronRight } from 'lucide-react';
+import Avatar from '../common/Avatar';
+
+/**
+ * Recording summary card for dashboard - shows recording assignments for an event
+ */
+const RecordingSummaryCard = ({ event }) => {
+ const navigate = useNavigate();
+
+ const { toBeRecorded, toRecord } = event.recordingSuggestions || { toBeRecorded: [], toRecord: [] };
+
+ // Count by status
+ const toBeRecordedPending = toBeRecorded.filter(s => s.status === 'pending').length;
+ const toBeRecordedAccepted = toBeRecorded.filter(s => s.status === 'accepted').length;
+ const toRecordPending = toRecord.filter(s => s.status === 'pending').length;
+ const toRecordAccepted = toRecord.filter(s => s.status === 'accepted').length;
+
+ // If no recording suggestions, don't render
+ if (toBeRecorded.length === 0 && toRecord.length === 0) {
+ return null;
+ }
+
+ const getStatusIcon = (status) => {
+ switch (status) {
+ case 'pending':
+ return ;
+ case 'accepted':
+ return ;
+ case 'rejected':
+ return ;
+ default:
+ return null;
+ }
+ };
+
+ const formatHeat = (heat) => {
+ return `${heat.division} ${heat.competitionType} H${heat.heatNumber}`;
+ };
+
+ return (
+
+
+
+
{event.name}
+
{event.location}
+
+
+
+
+ {/* Heats to be recorded */}
+ {toBeRecorded.length > 0 && (
+
+
+
+ Your heats ({toBeRecorded.length})
+
+
+ {toBeRecorded.slice(0, 2).map((suggestion) => (
+
+
+
{formatHeat(suggestion.heat)}
+ {suggestion.recorder ? (
+
+
+
@{suggestion.recorder.username}
+
+ ) : (
+
No recorder
+ )}
+
+
+ {getStatusIcon(suggestion.status)}
+
+
+ ))}
+ {toBeRecorded.length > 2 && (
+
+ +{toBeRecorded.length - 2} more
+
+ )}
+
+
+ {toBeRecordedPending > 0 && (
+
+
+ {toBeRecordedPending} pending
+
+ )}
+ {toBeRecordedAccepted > 0 && (
+
+
+ {toBeRecordedAccepted} accepted
+
+ )}
+
+
+ )}
+
+ {/* Recording others */}
+ {toRecord.length > 0 && (
+
+
+
+ You record ({toRecord.length})
+
+
+ {toRecord.slice(0, 2).map((suggestion) => (
+
+
+
{formatHeat(suggestion.heat)}
+
+
+
@{suggestion.dancer.username}
+
+
+
+ {getStatusIcon(suggestion.status)}
+
+
+ ))}
+ {toRecord.length > 2 && (
+
+ +{toRecord.length - 2} more
+
+ )}
+
+
+ {toRecordPending > 0 && (
+
+
+ {toRecordPending} pending
+
+ )}
+ {toRecordAccepted > 0 && (
+
+
+ {toRecordAccepted} accepted
+
+ )}
+
+
+ )}
+
+
+
+
+ );
+};
+
+export default RecordingSummaryCard;
diff --git a/frontend/src/pages/EventChatPage.jsx b/frontend/src/pages/EventChatPage.jsx
index 29d0fdf..1bd4744 100644
--- a/frontend/src/pages/EventChatPage.jsx
+++ b/frontend/src/pages/EventChatPage.jsx
@@ -1,5 +1,5 @@
import { useState, useRef, useEffect } from 'react';
-import { useParams, useNavigate, Link } from 'react-router-dom';
+import { useParams, useNavigate, useSearchParams, Link } from 'react-router-dom';
import Layout from '../components/layout/Layout';
import { useAuth } from '../contexts/AuthContext';
import { Send, UserPlus, Loader2, LogOut, AlertTriangle, QrCode, Edit2, Filter, X, MessageSquare, Users, Video } from 'lucide-react';
@@ -20,6 +20,7 @@ const EventChatPage = () => {
const { slug } = useParams();
const { user } = useAuth();
const navigate = useNavigate();
+ const [searchParams] = useSearchParams();
const [event, setEvent] = useState(null);
const [isParticipant, setIsParticipant] = useState(false);
const [loading, setLoading] = useState(true);
@@ -56,6 +57,24 @@ const EventChatPage = () => {
// Tab state: 'chat' | 'participants' | 'recording'
const [activeTab, setActiveTab] = useState('chat');
+ // Read tab from URL query parameter
+ useEffect(() => {
+ const tabParam = searchParams.get('tab');
+ if (tabParam) {
+ // Map 'records' to 'recording' for backwards compatibility
+ const tabMapping = {
+ 'chat': 'chat',
+ 'participants': 'participants',
+ 'records': 'recording',
+ 'recording': 'recording'
+ };
+ const mappedTab = tabMapping[tabParam];
+ if (mappedTab) {
+ setActiveTab(mappedTab);
+ }
+ }
+ }, [searchParams]);
+
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
};