1
0

Migrating to useWebSocket

This commit is contained in:
James Ketr 2025-09-27 15:21:51 -07:00
parent d4f34cd43f
commit 3874519a87
17 changed files with 179 additions and 216 deletions

View File

@ -11,6 +11,7 @@ type LocalGlobalContext = {
ws?: WebSocket | null; ws?: WebSocket | null;
gameId?: string | null; gameId?: string | null;
name?: string | undefined; name?: string | undefined;
sendJsonMessage?: (message: any) => void;
}; };
type PrivateData = { type PrivateData = {
@ -105,31 +106,31 @@ const Actions: React.FC<ActionsProps> = ({
refWsMessage.current = onWsMessage; refWsMessage.current = onWsMessage;
}); });
useEffect(() => { useEffect(() => {
if (!ws) { if (!ctx.ws) {
return; return;
} }
const cbMessage = (e: MessageEvent) => refWsMessage.current(e); const cbMessage = (e: MessageEvent) => refWsMessage.current(e);
ws.addEventListener("message", cbMessage as EventListener); ctx.ws.addEventListener("message", cbMessage as EventListener);
return () => { return () => {
ws.removeEventListener("message", cbMessage as EventListener); ctx.ws.removeEventListener("message", cbMessage as EventListener);
}; };
}, [ws, refWsMessage]); }, [ctx.ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!ctx.sendJsonMessage) {
return; return;
} }
ws.send(JSON.stringify({ type: "get", fields })); ctx.sendJsonMessage({ type: "get", fields });
}, [ws, fields]); }, [ctx.sendJsonMessage, fields]);
const sendMessage = useCallback( const sendMessage = useCallback(
(data: Record<string, unknown>) => { (data: Record<string, unknown>) => {
if (!ws) { if (!ctx.sendJsonMessage) {
console.warn(`No socket`); console.warn(`No sendJsonMessage`);
} else { } else {
ws.send(JSON.stringify(data)); ctx.sendJsonMessage(data);
} }
}, },
[ws] [ctx.sendJsonMessage]
); );
const buildClicked = () => { const buildClicked = () => {

View File

@ -87,7 +87,7 @@ const Activity: React.FC<ActivityProps> = ({ keep, activity }) => {
}; };
const Activities: React.FC = () => { const Activities: React.FC = () => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [activities, setActivities] = useState<ActivityData[]>([]); const [activities, setActivities] = useState<ActivityData[]>([]);
const [turn, setTurn] = useState<TurnData | undefined>(undefined); const [turn, setTurn] = useState<TurnData | undefined>(undefined);
const [color, setColor] = useState<string | undefined>(undefined); const [color, setColor] = useState<string | undefined>(undefined);
@ -169,16 +169,14 @@ const Activities: React.FC = () => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
if (!timestamp) { if (!timestamp) {
return <></>; return <></>;

View File

@ -82,7 +82,7 @@ const Table: React.FC = () => {
const protocol = loc.protocol === "https:" ? "wss" : "ws"; const protocol = loc.protocol === "https:" ? "wss" : "ws";
const socketUrl = gameId ? `${protocol}://${loc.host}${base}/api/v1/games/ws/${gameId}` : null; const socketUrl = gameId ? `${protocol}://${loc.host}${base}/api/v1/games/ws/${gameId}` : null;
const { sendJsonMessage, lastJsonMessage, readyState } = useWebSocket(socketUrl, { const { sendJsonMessage, lastJsonMessage, readyState, getWebSocket } = useWebSocket(socketUrl, {
shouldReconnect: (closeEvent) => true, shouldReconnect: (closeEvent) => true,
reconnectInterval: 5000, reconnectInterval: 5000,
onOpen: () => { onOpen: () => {
@ -181,10 +181,11 @@ const Table: React.FC = () => {
}, [lastJsonMessage]); }, [lastJsonMessage]);
const globalValue = useMemo(() => ({ const globalValue = useMemo(() => ({
ws: readyState === ReadyState.OPEN ? {} : undefined, ws: getWebSocket(),
name, name,
gameId, gameId,
}), [readyState, name, gameId]); sendJsonMessage,
}), [getWebSocket, name, gameId, sendJsonMessage]);
useEffect(() => { useEffect(() => {
setGlobal(globalValue); setGlobal(globalValue);
@ -504,7 +505,13 @@ const App: React.FC = () => {
} }
return ( return (
<Router basename={base}> <Router
basename={base}
future={{
v7_startTransition: true,
v7_relativeSplatPath: true,
}}
>
<Routes> <Routes>
<Route element={<Table />} path="/" /> <Route element={<Table />} path="/" />
<Route element={<Table />} path="/:gameId" /> <Route element={<Table />} path="/:gameId" />

View File

@ -95,7 +95,7 @@ const clearTooltip = () => {
}; };
const Board: React.FC<BoardProps> = ({ animations }) => { const Board: React.FC<BoardProps> = ({ animations }) => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const board = useRef(); const board = useRef();
const [transform, setTransform] = useState(1); const [transform, setTransform] = useState(1);
const [pipElements, setPipElements] = useState<React.ReactElement[]>([]); const [pipElements, setPipElements] = useState<React.ReactElement[]>([]);
@ -252,16 +252,14 @@ const Board: React.FC<BoardProps> = ({ animations }) => {
}; };
}, [ws]); }, [ws]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
useEffect(() => { useEffect(() => {
const boardBox = board.current.querySelector(".BoardBox"); const boardBox = board.current.querySelector(".BoardBox");

View File

@ -34,7 +34,7 @@ const Chat: React.FC = () => {
return () => clearInterval(timer); return () => clearInterval(timer);
}, []); }, []);
const { ws, name } = useContext(GlobalContext); const { ws, name, sendJsonMessage } = useContext(GlobalContext);
const fields = useMemo(() => ["chat", "startTime"], []); const fields = useMemo(() => ["chat", "startTime"], []);
const onWsMessage = (event: MessageEvent) => { const onWsMessage = (event: MessageEvent) => {
const data = JSON.parse(event.data); const data = JSON.parse(event.data);
@ -71,13 +71,11 @@ const Chat: React.FC = () => {
if (!ws) { if (!ws) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [ws, fields, sendJsonMessage]);
}, [ws, fields]);
const chatKeyPress = useCallback( const chatKeyPress = useCallback(
(event: React.KeyboardEvent<HTMLInputElement>) => { (event: React.KeyboardEvent<HTMLInputElement>) => {
@ -87,7 +85,7 @@ const Chat: React.FC = () => {
} }
if (ws) { if (ws) {
ws.send(JSON.stringify({ type: "chat", message: (event.target as HTMLInputElement).value })); sendJsonMessage({ type: "chat", message: (event.target as HTMLInputElement).value });
(event.target as HTMLInputElement).value = ""; (event.target as HTMLInputElement).value = "";
} }
} }

View File

@ -12,7 +12,7 @@ import { GlobalContext } from "./GlobalContext";
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
const ChooseCard: React.FC = () => { const ChooseCard: React.FC = () => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [turn, setTurn] = useState<any>(undefined); const [turn, setTurn] = useState<any>(undefined);
const [color, setColor] = useState<string | undefined>(undefined); const [color, setColor] = useState<string | undefined>(undefined);
const [state, setState] = useState<string | undefined>(undefined); const [state, setState] = useState<string | undefined>(undefined);
@ -53,26 +53,22 @@ const ChooseCard: React.FC = () => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const selectResources = useCallback(() => { const selectResources = useCallback(() => {
if (!ws) return; if (!sendJsonMessage) return;
ws.send( sendJsonMessage({
JSON.stringify({
type: "select-resources", type: "select-resources",
cards, cards,
}) });
); }, [sendJsonMessage, cards]);
}, [ws, cards]);
let count = 0; let count = 0;
if (turn && turn.actions && turn.actions.indexOf("select-resources") !== -1) { if (turn && turn.actions && turn.actions.indexOf("select-resources") !== -1) {

View File

@ -21,7 +21,7 @@ interface PlayerItem {
} }
const GameOrder: React.FC = () => { const GameOrder: React.FC = () => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [players, setPlayers] = useState<{ [key: string]: any }>({}); const [players, setPlayers] = useState<{ [key: string]: any }>({});
const [color, setColor] = useState<string | undefined>(undefined); const [color, setColor] = useState<string | undefined>(undefined);
const fields = useMemo(() => ["players", "color"], []); const fields = useMemo(() => ["players", "color"], []);
@ -57,16 +57,14 @@ const GameOrder: React.FC = () => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const sendMessage = (data: any) => { const sendMessage = (data: any) => {
ws!.send(JSON.stringify(data)); ws!.send(JSON.stringify(data));

View File

@ -2,8 +2,9 @@ import { createContext } from 'react';
export type GlobalContextType = { export type GlobalContextType = {
gameId?: string | undefined; gameId?: string | undefined;
ws?: WebSocket | undefined; ws?: WebSocket | null | undefined;
name?: string; name?: string;
sendJsonMessage?: (message: any) => void;
chat?: Array<unknown>; chat?: Array<unknown>;
}; };

View File

@ -34,7 +34,7 @@ interface HandProps {
} }
const Hand: React.FC<HandProps> = ({ buildActive, setBuildActive, setCardActive }) => { const Hand: React.FC<HandProps> = ({ buildActive, setBuildActive, setCardActive }) => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [priv, setPriv] = useState<any>(undefined); const [priv, setPriv] = useState<any>(undefined);
const [color, setColor] = useState<string | undefined>(undefined); const [color, setColor] = useState<string | undefined>(undefined);
const [turn, setTurn] = useState<any>(undefined); const [turn, setTurn] = useState<any>(undefined);
@ -95,16 +95,14 @@ const Hand: React.FC<HandProps> = ({ buildActive, setBuildActive, setCardActive
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
useEffect(() => { useEffect(() => {
if (!priv) { if (!priv) {

View File

@ -44,14 +44,14 @@ const categoryImages: { [key: string]: string } = {
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
interface VolcanoProps { interface VolcanoProps {
ws: WebSocket | null; sendJsonMessage: (message: any) => void;
rules: any; rules: any;
field: string; field: string;
disabled: boolean; disabled: boolean;
} }
/* Volcano based on https://www.ultraboardgames.com/catan/the-volcano.php */ /* Volcano based on https://www.ultraboardgames.com/catan/the-volcano.php */
const Volcano: React.FC<VolcanoProps> = ({ ws, rules, field, disabled }) => { const Volcano: React.FC<VolcanoProps> = ({ sendJsonMessage, rules, field, disabled }) => {
const init = const init =
Math.random() > 0.5 Math.random() > 0.5
? Math.floor(8 + Math.random() * 5) /* Do not include 7 */ ? Math.floor(8 + Math.random() * 5) /* Do not include 7 */
@ -79,33 +79,29 @@ const Volcano: React.FC<VolcanoProps> = ({ ws, rules, field, disabled }) => {
update = true; update = true;
} }
if (update && ws) { if (update && sendJsonMessage) {
ws.send( sendJsonMessage({
JSON.stringify({
type: "rules", type: "rules",
rules: rules, rules: rules,
}) });
);
} }
} }
}, [rules, field, init, ws]); }, [rules, field, init, sendJsonMessage]);
const toggleGold = () => { const toggleGold = () => {
if (!ws) return; if (!sendJsonMessage) return;
rules[field].gold = !gold; rules[field].gold = !gold;
rules[field].number = number; rules[field].number = number;
setGold(rules[field].gold); setGold(rules[field].gold);
ws.send( sendJsonMessage({
JSON.stringify({
type: "rules", type: "rules",
rules: rules, rules: rules,
}) });
);
}; };
const update = (delta: number) => { const update = (delta: number) => {
if (!ws) return; if (!sendJsonMessage) return;
let value = number + delta; let value = number + delta;
if (value < 2 || value > 12) { if (value < 2 || value > 12) {
return; return;
@ -117,12 +113,10 @@ const Volcano: React.FC<VolcanoProps> = ({ ws, rules, field, disabled }) => {
setNumber(value); setNumber(value);
rules[field].gold = gold; rules[field].gold = gold;
rules[field].number = value; rules[field].number = value;
ws.send( sendJsonMessage({
JSON.stringify({
type: "rules", type: "rules",
rules: rules, rules: rules,
}) });
);
}; };
return ( return (
@ -218,12 +212,12 @@ const Volcano: React.FC<VolcanoProps> = ({ ws, rules, field, disabled }) => {
}; };
interface VictoryPointsProps { interface VictoryPointsProps {
ws: WebSocket | null; sendJsonMessage: (message: any) => void;
rules: any; rules: any;
field: string; field: string;
} }
const VictoryPoints: React.FC<VictoryPointsProps> = ({ ws, rules, field }) => { const VictoryPoints: React.FC<VictoryPointsProps> = ({ sendJsonMessage, rules, field }) => {
const minVP = 10; const minVP = 10;
const [points, setPoints] = useState<number>(rules[field].points || minVP); const [points, setPoints] = useState<number>(rules[field].points || minVP);
console.log(`house-rules - ${field} - `, rules[field]); console.log(`house-rules - ${field} - `, rules[field]);
@ -239,7 +233,7 @@ const VictoryPoints: React.FC<VictoryPointsProps> = ({ ws, rules, field }) => {
} }
const update = (value: number) => { const update = (value: number) => {
if (!ws) return; if (!sendJsonMessage) return;
const points = (rules[field].points || minVP) + value; const points = (rules[field].points || minVP) + value;
if (points < minVP) { if (points < minVP) {
return; return;
@ -247,12 +241,10 @@ const VictoryPoints: React.FC<VictoryPointsProps> = ({ ws, rules, field }) => {
if (points !== rules[field].points) { if (points !== rules[field].points) {
setPoints(points); setPoints(points);
rules[field].points = points; rules[field].points = points;
ws.send( sendJsonMessage({
JSON.stringify({
type: "rules", type: "rules",
rules: rules, rules: rules,
}) });
);
} }
}; };
@ -279,7 +271,7 @@ const HouseRules: React.FC<HouseRulesProps> = ({
houseRulesActive, houseRulesActive,
setHouseRulesActive, setHouseRulesActive,
}) => { }) => {
const { ws, name } = useContext(GlobalContext); const { ws, name, sendJsonMessage } = useContext(GlobalContext);
const [rules, setRules] = useState<any>({}); const [rules, setRules] = useState<any>({});
const [state, setState] = useState<any>({}); const [state, setState] = useState<any>({});
const [gameState, setGameState] = useState<string>(""); const [gameState, setGameState] = useState<string>("");
@ -316,16 +308,14 @@ const HouseRules: React.FC<HouseRulesProps> = ({
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const dismissClicked = useCallback(() => { const dismissClicked = useCallback(() => {
setHouseRulesActive(false); setHouseRulesActive(false);
@ -333,19 +323,17 @@ const HouseRules: React.FC<HouseRulesProps> = ({
const setRule = useCallback( const setRule = useCallback(
(event: React.ChangeEvent<HTMLInputElement>, key: string) => { (event: React.ChangeEvent<HTMLInputElement>, key: string) => {
if (!ws) return; if (!sendJsonMessage) return;
const checked = event.target.checked; const checked = event.target.checked;
console.log(`house-rules - set rule ${key} to ${checked}`); console.log(`house-rules - set rule ${key} to ${checked}`);
rules[key].enabled = checked; rules[key].enabled = checked;
setRules({ ...rules }); setRules({ ...rules });
ws.send( sendJsonMessage({
JSON.stringify({
type: "rules", type: "rules",
rules: rules, rules: rules,
}) });
);
}, },
[rules, ws] [rules, sendJsonMessage]
); );
const ruleList = useMemo( const ruleList = useMemo(
@ -359,7 +347,7 @@ const HouseRules: React.FC<HouseRulesProps> = ({
defaultChecked: false, defaultChecked: false,
element: ( element: (
<Volcano <Volcano
ws={ws} sendJsonMessage={sendJsonMessage}
rules={rules} rules={rules}
field={"volcano"} field={"volcano"}
disabled={gameState !== "lobby"} disabled={gameState !== "lobby"}
@ -373,7 +361,7 @@ const HouseRules: React.FC<HouseRulesProps> = ({
category: "rules", category: "rules",
defaultChecked: false, defaultChecked: false,
element: ( element: (
<VictoryPoints ws={ws} rules={rules} field={"victory-points"} /> <VictoryPoints sendJsonMessage={sendJsonMessage} rules={rules} field={"victory-points"} />
), ),
}, },
{ {

View File

@ -16,12 +16,12 @@ type PlacardProps = {
}; };
const Placard: React.FC<PlacardProps> = ({ type, disabled, count, buildActive, setBuildActive, className, sx }) => { const Placard: React.FC<PlacardProps> = ({ type, disabled, count, buildActive, setBuildActive, className, sx }) => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const sendMessage = useCallback( const sendMessage = useCallback(
(data: Record<string, unknown>) => { (data: Record<string, unknown>) => {
ws.send(JSON.stringify(data)); sendJsonMessage(data);
}, },
[ws] [sendJsonMessage]
); );
const dismissClicked = () => { const dismissClicked = () => {

View File

@ -11,7 +11,7 @@ import { GlobalContext } from "./GlobalContext";
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
const PlayerList: React.FC = () => { const PlayerList: React.FC = () => {
const { ws, name } = useContext(GlobalContext); const { ws, name, sendJsonMessage } = useContext(GlobalContext);
const [players, setPlayers] = useState<{ [key: string]: any }>({}); const [players, setPlayers] = useState<{ [key: string]: any }>({});
const [unselected, setUneslected] = useState<string[]>([]); const [unselected, setUneslected] = useState<string[]>([]);
const [state, setState] = useState<string>("lobby"); const [state, setState] = useState<string>("lobby");
@ -69,15 +69,13 @@ const PlayerList: React.FC = () => {
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields: ["state", "players", "unselected"], fields: ["state", "players", "unselected"],
}) });
);
}, [ws]); }, [ws]);
const toggleSelected = (key: string) => { const toggleSelected = (key: string) => {

View File

@ -133,7 +133,7 @@ interface PlayersStatusProps {
} }
const PlayersStatus: React.FC<PlayersStatusProps> = ({ active }) => { const PlayersStatus: React.FC<PlayersStatusProps> = ({ active }) => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [players, setPlayers] = useState<any>(undefined); const [players, setPlayers] = useState<any>(undefined);
const [color, setColor] = useState<string | undefined>(undefined); const [color, setColor] = useState<string | undefined>(undefined);
const [largestArmy, setLargestArmy] = useState<string | undefined>(undefined); const [largestArmy, setLargestArmy] = useState<string | undefined>(undefined);
@ -184,16 +184,14 @@ const PlayersStatus: React.FC<PlayersStatusProps> = ({ active }) => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
if (!players) { if (!players) {
return <></>; return <></>;

View File

@ -11,7 +11,7 @@ import { GlobalContext } from "./GlobalContext";
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */
const SelectPlayer: React.FC = () => { const SelectPlayer: React.FC = () => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [turn, setTurn] = useState<any>(undefined); const [turn, setTurn] = useState<any>(undefined);
const [color, setColor] = useState<string | undefined>(undefined); const [color, setColor] = useState<string | undefined>(undefined);
const fields = useMemo(() => ["turn", "color"], []); const fields = useMemo(() => ["turn", "color"], []);
@ -47,27 +47,23 @@ const SelectPlayer: React.FC = () => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const playerClick = useCallback( const playerClick = useCallback(
(event: React.MouseEvent<HTMLDivElement>) => { (event: React.MouseEvent<HTMLDivElement>) => {
ws!.send( sendJsonMessage({
JSON.stringify({
type: "steal-resource", type: "steal-resource",
color: event.currentTarget.getAttribute("data-color"), color: event.currentTarget.getAttribute("data-color"),
}) });
);
}, },
[ws] [sendJsonMessage]
); );
if (!color || !turn || turn.color !== color || !turn.limits || !turn.limits.players) { if (!color || !turn || turn.color !== color || !turn.limits || !turn.limits.players) {

View File

@ -43,7 +43,7 @@ const empty: Resources = {
}; };
const Trade: React.FC = () => { const Trade: React.FC = () => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [gives, setGives] = useState<Resources>(Object.assign({}, empty)); const [gives, setGives] = useState<Resources>(Object.assign({}, empty));
const [gets, setGets] = useState<Resources>(Object.assign({}, empty)); const [gets, setGets] = useState<Resources>(Object.assign({}, empty));
const [turn, setTurn] = useState<any>(undefined); const [turn, setTurn] = useState<any>(undefined);
@ -90,16 +90,14 @@ const Trade: React.FC = () => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const transfer = useCallback( const transfer = useCallback(
(type: string, direction: string) => { (type: string, direction: string) => {
if (direction === "give") { if (direction === "give") {
@ -168,17 +166,15 @@ const Trade: React.FC = () => {
const sendTrade = useCallback( const sendTrade = useCallback(
(action: string, offer: any) => { (action: string, offer: any) => {
if (ws) { if (sendJsonMessage) {
ws.send( sendJsonMessage({
JSON.stringify({
type: "trade", type: "trade",
action, action,
offer, offer,
}) });
);
} }
}, },
[ws] [sendJsonMessage]
); );
useEffect(() => { useEffect(() => {

View File

@ -16,7 +16,7 @@ interface ViewCardProps {
} }
const ViewCard: React.FC<ViewCardProps> = ({ cardActive, setCardActive }) => { const ViewCard: React.FC<ViewCardProps> = ({ cardActive, setCardActive }) => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [priv, setPriv] = useState<any>(undefined); const [priv, setPriv] = useState<any>(undefined);
const [turns, setTurns] = useState<number>(0); const [turns, setTurns] = useState<number>(0);
const [rules, setRules] = useState<any>({}); const [rules, setRules] = useState<any>({});
@ -55,28 +55,24 @@ const ViewCard: React.FC<ViewCardProps> = ({ cardActive, setCardActive }) => {
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const playCard = useCallback(() => { const playCard = useCallback(() => {
if (ws) { if (sendJsonMessage) {
ws.send( sendJsonMessage({
JSON.stringify({
type: "play-card", type: "play-card",
card: cardActive, card: cardActive,
}) });
);
} }
setCardActive(undefined); setCardActive(undefined);
}, [ws, cardActive, setCardActive]); }, [sendJsonMessage, cardActive, setCardActive]);
const close = () => { const close = () => {
setCardActive(undefined); setCardActive(undefined);

View File

@ -17,7 +17,7 @@ interface WinnerProps {
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
const Winner: React.FC<WinnerProps> = ({ winnerDismissed, setWinnerDismissed }) => { const Winner: React.FC<WinnerProps> = ({ winnerDismissed, setWinnerDismissed }) => {
const { ws } = useContext(GlobalContext); const { ws, sendJsonMessage } = useContext(GlobalContext);
const [winner, setWinner] = useState<any>(undefined); const [winner, setWinner] = useState<any>(undefined);
const [state, setState] = useState<string | undefined>(undefined); const [state, setState] = useState<string | undefined>(undefined);
const fields = useMemo(() => ["winner", "state"], []); const fields = useMemo(() => ["winner", "state"], []);
@ -56,27 +56,23 @@ const Winner: React.FC<WinnerProps> = ({ winnerDismissed, setWinnerDismissed })
}; };
}, [ws, refWsMessage]); }, [ws, refWsMessage]);
useEffect(() => { useEffect(() => {
if (!ws) { if (!sendJsonMessage) {
return; return;
} }
ws.send( sendJsonMessage({
JSON.stringify({
type: "get", type: "get",
fields, fields,
}) });
); }, [sendJsonMessage, fields]);
}, [ws, fields]);
const quitClicked = useCallback(() => { const quitClicked = useCallback(() => {
if (!winnerDismissed) { if (!winnerDismissed) {
setWinnerDismissed(true); setWinnerDismissed(true);
ws.send( sendJsonMessage({
JSON.stringify({
type: "goto-lobby", type: "goto-lobby",
}) });
);
} }
}, [ws, winnerDismissed, setWinnerDismissed]); }, [sendJsonMessage, winnerDismissed, setWinnerDismissed]);
if (!winner || winnerDismissed) { if (!winner || winnerDismissed) {
return <></>; return <></>;