← back to Dw Boardroom V2
frontend/src/components/MeetingRoom.tsx
87 lines
import { useState, useEffect, useRef } from 'react';
import { api } from '../api';
import type { Meeting, MeetingMessage, WSEvent } from '../types';
import PhaseBar from './PhaseBar';
import MeetingControls from './MeetingControls';
import LiveFeed from './LiveFeed';
interface Props {
events: WSEvent[];
}
export default function MeetingRoom({ events }: Props) {
const [meeting, setMeeting] = useState<Meeting | null>(null);
const [messages, setMessages] = useState<MeetingMessage[]>([]);
const [loading, setLoading] = useState(true);
function fetchActive() {
api.getActiveMeeting().then(data => {
setMeeting(data.meeting);
setMessages(data.messages || []);
setLoading(false);
}).catch(() => setLoading(false));
}
useEffect(() => { fetchActive(); }, []);
// Listen for WS events
useEffect(() => {
const latest = events[events.length - 1];
if (!latest) return;
if (latest.type === 'meeting_started' || latest.type === 'meeting_completed' || latest.type === 'meeting_halted') {
fetchActive();
} else if (latest.type === 'meeting_phase' && meeting) {
setMeeting(prev => prev ? { ...prev, phase: latest.payload.phase } : null);
} else if (latest.type === 'meeting_message') {
setMessages(prev => [...prev, latest.payload]);
}
}, [events]);
async function handleStart(type: string) {
try {
await api.startMeeting(type);
fetchActive();
} catch (err: any) {
alert(err.message);
}
}
async function handleHalt() {
if (!meeting) return;
await api.haltMeeting(meeting.id);
fetchActive();
}
async function handleAdvance() {
if (!meeting) return;
await api.advanceMeeting(meeting.id);
fetchActive();
}
if (loading) return <div style={styles.card}><div style={styles.empty}>Loading...</div></div>;
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
{/* Phase Bar */}
<PhaseBar currentPhase={meeting?.phase || null} status={meeting?.status || null} />
{/* Controls */}
<MeetingControls
activeMeeting={meeting}
onStart={handleStart}
onHalt={handleHalt}
onAdvance={handleAdvance}
/>
{/* Live Feed */}
<LiveFeed messages={messages} meetingActive={!!meeting && meeting.status === 'in_progress'} />
</div>
);
}
const styles: Record<string, React.CSSProperties> = {
card: { background: '#1a1a2e', borderRadius: 12, padding: 20, border: '1px solid #252540' },
empty: { color: '#7a7f96', fontSize: 13, textAlign: 'center' as const, padding: 40 },
};