1import {useEffect, useState} from 'react'
2import {useRoom} from './useRoom'
3import {getRoomFromUrl} from './config'
4import {Header} from './components/Header'
5import {PeerList} from './components/PeerList'
6import {Composer} from './components/Composer'
7import {TransferList} from './components/TransferList'
8import {MessageLog} from './components/MessageLog'
10export default function App() {
11 const [roomId, setRoomId] = useState<string>(getRoomFromUrl)
13 // keep room in sync with the URL hash so #room links work and are shareable
14 useEffect(() => {
15 const onHashChange = () => setRoomId(getRoomFromUrl())
16 window.addEventListener('hashchange', onHashChange)
17 return () => window.removeEventListener('hashchange', onHashChange)
18 }, [])
20 const room = useRoom(roomId)
22 // The currently selected message target: a peer id, or null for "everyone".
23 const [target, setTarget] = useState<string | null>(null)
25 // If the selected target leaves, fall back to broadcast.
26 useEffect(() => {
27 if (target && !room.others.some(p => p.id === target)) {
28 setTarget(null)
29 }
30 }, [room.others, target])
32 return (
33 <div className="app">
34 <Header
35 roomId={roomId}
36 selfId={room.selfId}
37 selfName={room.selfName}
38 onChangeName={room.setSelfName}
39 peerCount={room.others.length}
40 relayCount={room.relayCount}
41 />
43 <main className="layout">
44 <aside className="col-peers">
45 <PeerList
46 others={room.others}
47 target={target}
48 onSelectTarget={setTarget}
49 />
50 </aside>
52 <section className="col-main">
53 <Composer
54 target={target}
55 targetName={
56 target
57 ? room.others.find(p => p.id === target)?.name ?? target
58 : 'Everyone'
59 }
60 onSendText={room.sendText}
61 onSendBinary={room.sendBinary}
62 />
63 <TransferList transfers={room.transfers} />
64 <MessageLog log={room.log} onClear={room.clearLog} />
65 </section>
66 </main>
67 </div>
68 )
69}