72 lines
2.3 KiB
TypeScript
72 lines
2.3 KiB
TypeScript
import { CSSProperties, useEffect, useMemo, useState } from 'react';
|
||
import './TVMode.css';
|
||
import { ButtonType, buttonTypeList, WGPPState } from './types';
|
||
|
||
const TVMode = () => {
|
||
|
||
const [state, setState] = useState<Partial<WGPPState>>({});
|
||
const [socket, setSocket] = useState<WebSocket>();
|
||
|
||
useEffect(() => {
|
||
const url = new URL(`api/client`, window.location.href);
|
||
url.protocol = url.protocol.replace("http", "ws");
|
||
const sock = new WebSocket(url.href);
|
||
|
||
sock.onmessage = (e) => {
|
||
const newState = JSON.parse(e.data) as Partial<WGPPState>;
|
||
// Merge old and new state
|
||
setState(oldState => ({ ...oldState , ...newState }));
|
||
}
|
||
setSocket(sock);
|
||
|
||
return () => {
|
||
sock.close();
|
||
setSocket(undefined);
|
||
};
|
||
}, [])
|
||
|
||
const totalCount = useMemo(() => buttonTypeList.reduce((acc, v) => (state?.votes?.[v] ?? 0) + acc, 0), [state]);
|
||
const voteList = useMemo(() =>
|
||
buttonTypeList
|
||
.map(b => [b, state?.votes?.[b] ?? 0] as [ButtonType, number])
|
||
//.sort((a, b) => b[1] - a[1])
|
||
, [state]);
|
||
|
||
return <div className="stream">
|
||
{state === undefined ?
|
||
<span>Loading...</span> :
|
||
<div>
|
||
<span className={`mode mode-${state.mode}`}>{state.mode}</span>
|
||
<div className="row">
|
||
<div>
|
||
<span>
|
||
next:
|
||
</span>
|
||
<span className={`subtitle mode-${state.nextMode}`}>{state.nextMode}</span>
|
||
</div>
|
||
<span className="timer">{Math.round(state.timeUntilNextMode ?? 0)}s ⏱️</span>
|
||
</div>
|
||
<div className="voting">
|
||
{voteList.flatMap(([b, numVotes], index) => {
|
||
const percentage = numVotes === 0 ? 0 : Math.round(numVotes / totalCount * 100);
|
||
return <div className="vote" style={{ "--vote-percentage": percentage + "%" } as CSSProperties} key={index}>
|
||
<div className="bar-wrap">
|
||
<div className="bar" style={{ "--vote-percentage": percentage + "%" } as CSSProperties} >{b}</div>
|
||
</div>
|
||
<span className="percentage">{percentage === 0 ? "" : `${percentage}%`}</span>
|
||
</div>;
|
||
})}
|
||
</div>
|
||
<div>
|
||
Current state: <pre>
|
||
{JSON.stringify(state, null, 4)}
|
||
</pre>
|
||
</div>
|
||
|
||
</div>
|
||
}
|
||
</div>;
|
||
}
|
||
|
||
export default TVMode;
|