1
0
peddlers-of-ketran/client/src/PlayerList.tsx

188 lines
4.9 KiB
TypeScript

import React, { useState, useEffect, useContext, useRef } from "react";
import Paper from "@mui/material/Paper";
import List from "@mui/material/List";
import "./PlayerList.css";
import { PlayerColor } from "./PlayerColor";
import { MediaAgent, MediaControl } from "./MediaControl";
import { GlobalContext } from "./GlobalContext";
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
const PlayerList: React.FC = () => {
const { ws, name, sendJsonMessage } = useContext(GlobalContext);
const [players, setPlayers] = useState<{ [key: string]: any }>({});
const [unselected, setUneslected] = useState<string[]>([]);
const [state, setState] = useState<string>("lobby");
const [color, setColor] = useState<string | undefined>(undefined);
const [peers, setPeers] = useState<{ [key: string]: any }>({});
const onWsMessage = (event: MessageEvent) => {
const data = JSON.parse(event.data);
switch (data.type) {
case "game-update":
console.log(`player-list - game update`, data.update);
if ("unselected" in data.update) {
setUneslected(data.update.unselected);
}
if ("players" in data.update) {
let found = false;
for (const key in data.update.players) {
if (data.update.players[key].name === name) {
found = true;
setColor(key);
break;
}
}
if (!found) {
setColor(undefined);
}
setPlayers(data.update.players);
}
if ("state" in data.update && data.update.state !== state) {
setState(data.update.state);
}
break;
default:
break;
}
};
const refWsMessage = useRef(onWsMessage);
useEffect(() => {
refWsMessage.current = onWsMessage;
});
useEffect(() => {
if (!ws) {
return;
}
const cbMessage = (e: MessageEvent) => refWsMessage.current(e);
ws.addEventListener("message", cbMessage);
return () => {
ws.removeEventListener("message", cbMessage);
};
}, [ws, refWsMessage]);
useEffect(() => {
if (!sendJsonMessage) {
return;
}
sendJsonMessage({
type: "get",
fields: ["state", "players", "unselected"],
});
}, [ws]);
const toggleSelected = (key: string) => {
ws!.send(
JSON.stringify({
type: "set",
field: "color",
value: color === key ? "" : key,
})
);
};
const playerElements: React.ReactElement[] = [];
const inLobby = state === "lobby";
const sortedPlayers: any[] = [];
for (const key in players) {
sortedPlayers.push(players[key]);
}
const sortPlayers = (A: any, B: any) => {
/* active player first */
if (A.name === name) {
return -1;
}
if (B.name === name) {
return +1;
}
/* Sort active players first */
if (A.name && !B.name) {
return -1;
}
if (B.name && !A.name) {
return +1;
}
/* Ohterwise, sort by color */
return A.color.localeCompare(B.color);
};
sortedPlayers.sort(sortPlayers);
/* Array of just names... */
unselected.sort((A, B) => {
/* active player first */
if (A === name) {
return -1;
}
if (B === name) {
return +1;
}
/* Then sort alphabetically */
return A.localeCompare(B);
});
const videoClass = sortedPlayers.length <= 2 ? "Medium" : "Small";
sortedPlayers.forEach((player) => {
const playerName = player.name;
const selectable = inLobby && (player.status === "Not active" || color === player.color);
playerElements.push(
<div
data-selectable={selectable}
data-selected={player.color === color}
className="PlayerEntry"
onClick={() => {
inLobby && selectable && toggleSelected(player.color);
}}
key={`player-${player.color}`}
>
<div>
<PlayerColor color={player.color} />
<div className="Name">{playerName ? playerName : "Available"}</div>
{playerName && !player.live && <div className="NoNetwork"></div>}
</div>
{playerName && player.live && (
<MediaControl className={videoClass} peer={peers[playerName]} isSelf={player.color === color} />
)}
{!playerName && <div></div>}
</div>
);
});
const waiting = unselected.map((player) => {
return (
<div className={player === name ? "Self" : ""} key={player}>
<div>{player}</div>
<MediaControl className={"Small"} peer={peers[player]} isSelf={name === player} />
</div>
);
});
return (
<Paper className={`PlayerList ${videoClass}`}>
<MediaAgent setPeers={setPeers} />
<List className="PlayerSelector">{playerElements}</List>
{unselected && unselected.length !== 0 && (
<div className="Unselected">
<div>In lobby</div>
<div>{waiting}</div>
</div>
)}
</Paper>
);
};
export { PlayerList };