Moved to simple peer
This commit is contained in:
+3
-8
@@ -1,7 +1,6 @@
|
||||
import React from "react";
|
||||
import { useRoutes } from "hookrouter";
|
||||
import { ThemeProvider } from "theme-ui";
|
||||
import { GameProvider } from "./contexts/GameContext";
|
||||
|
||||
import theme from "./theme.js";
|
||||
import Home from "./routes/Home";
|
||||
@@ -10,17 +9,13 @@ import Join from "./routes/Join";
|
||||
|
||||
const routes = {
|
||||
"/": () => <Home />,
|
||||
"/game": () => <Game />,
|
||||
"/join": () => <Join />
|
||||
"/game/:id": ({ id }) => <Game gameId={id} />,
|
||||
"/join": () => <Join />,
|
||||
};
|
||||
|
||||
function App() {
|
||||
const route = useRoutes(routes);
|
||||
return (
|
||||
<ThemeProvider theme={theme}>
|
||||
<GameProvider>{route}</GameProvider>
|
||||
</ThemeProvider>
|
||||
);
|
||||
return <ThemeProvider theme={theme}>{route}</ThemeProvider>;
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { IconButton, Flex, Box, Label, Text } from "theme-ui";
|
||||
|
||||
import Modal from "./Modal";
|
||||
|
||||
function AddPartyMemberButton({ peerId }) {
|
||||
function AddPartyMemberButton({ gameId }) {
|
||||
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
|
||||
function openModal() {
|
||||
setIsAddModalOpen(true);
|
||||
@@ -32,7 +32,7 @@ function AddPartyMemberButton({ peerId }) {
|
||||
<Box>
|
||||
<Label p={2}>Other people can join using your ID › ʕ•ᴥ•ʔ</Label>
|
||||
<Box p={2} bg="hsla(230, 20%, 0%, 20%)">
|
||||
<Text>{peerId}</Text>
|
||||
<Text>{gameId}</Text>
|
||||
</Box>
|
||||
</Box>
|
||||
</Modal>
|
||||
|
||||
+10
-7
@@ -3,7 +3,7 @@ import { Flex, Box, Text } from "theme-ui";
|
||||
|
||||
import AddPartyMemberButton from "./AddPartyMemberButton";
|
||||
|
||||
function Party({ nicknames, peerId, onNicknameChange }) {
|
||||
function Party({ nickname, partyNicknames, gameId, onNicknameChange }) {
|
||||
return (
|
||||
<Flex
|
||||
p={3}
|
||||
@@ -13,12 +13,12 @@ function Party({ nicknames, peerId, onNicknameChange }) {
|
||||
width: "96px",
|
||||
minWidth: "96px",
|
||||
overflowY: "auto",
|
||||
alignItems: "center"
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
sx={{
|
||||
width: "100%"
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
<Text mb={1} variant="heading">
|
||||
@@ -28,17 +28,20 @@ function Party({ nicknames, peerId, onNicknameChange }) {
|
||||
<Box
|
||||
sx={{
|
||||
flexGrow: 1,
|
||||
width: "100%"
|
||||
width: "100%",
|
||||
}}
|
||||
>
|
||||
{Object.entries(nicknames).map(([id, nickname]) => (
|
||||
<Text my={1} variant="caption" sx={{ fontSize: 10 }}>
|
||||
{nickname || ""} (you)
|
||||
</Text>
|
||||
{Object.entries(partyNicknames).map(([id, partyNickname]) => (
|
||||
<Text my={1} variant="caption" sx={{ fontSize: 10 }} key={id}>
|
||||
{nickname} {id === peerId ? "(you)" : ""}
|
||||
{partyNickname}
|
||||
</Text>
|
||||
))}
|
||||
</Box>
|
||||
<Box>
|
||||
<AddPartyMemberButton peerId={peerId} />
|
||||
<AddPartyMemberButton gameId={gameId} />
|
||||
</Box>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
|
||||
const GameContext = React.createContext();
|
||||
|
||||
export function GameProvider({ children }) {
|
||||
const [gameId, setGameId] = useState(null);
|
||||
const value = { gameId, setGameId };
|
||||
return <GameContext.Provider value={value}>{children}</GameContext.Provider>;
|
||||
}
|
||||
|
||||
export default GameContext;
|
||||
@@ -0,0 +1,97 @@
|
||||
import SimplePeer from "simple-peer";
|
||||
import BinaryPack from "js-binarypack";
|
||||
import toBuffer from "blob-to-buffer";
|
||||
import shortid from "shortid";
|
||||
|
||||
// Limit buffer size to 16kb to avoid issues with chrome packet size
|
||||
// http://viblast.com/blog/2015/2/5/webrtc-data-channel-message-size/
|
||||
const MAX_BUFFER_SIZE = 16000;
|
||||
|
||||
class Peer extends SimplePeer {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.currentChunks = {};
|
||||
|
||||
this.on("data", (packed) => {
|
||||
const unpacked = BinaryPack.unpack(packed);
|
||||
// If the special property __chunked is set and true
|
||||
// The data is a partial chunk of the a larger file
|
||||
// So wait until all chunks are collected and assembled
|
||||
// before emitting the dataComplete event
|
||||
if (unpacked.__chunked) {
|
||||
let chunk = this.currentChunks[unpacked.id] || {
|
||||
data: [],
|
||||
count: 0,
|
||||
total: unpacked.total,
|
||||
};
|
||||
chunk.data[unpacked.index] = unpacked.data;
|
||||
chunk.count++;
|
||||
this.currentChunks[unpacked.id] = chunk;
|
||||
|
||||
// All chunks have been loaded
|
||||
if (chunk.count === chunk.total) {
|
||||
const merged = BinaryPack.unpack(Buffer.concat(chunk.data));
|
||||
this.emit("dataComplete", merged);
|
||||
delete this.currentChunks[unpacked.id];
|
||||
}
|
||||
} else {
|
||||
this.emit("dataComplete", unpacked);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
sendPackedData(packedData) {
|
||||
toBuffer(packedData, (error, buffer) => {
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
super.send(buffer);
|
||||
});
|
||||
}
|
||||
|
||||
send(data) {
|
||||
const packedData = BinaryPack.pack(data);
|
||||
|
||||
if (packedData.size > MAX_BUFFER_SIZE) {
|
||||
const chunks = this.chunk(packedData);
|
||||
for (let chunk of chunks) {
|
||||
this.sendPackedData(BinaryPack.pack(chunk));
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
this.sendPackedData(packedData);
|
||||
}
|
||||
}
|
||||
|
||||
// Converted from https://github.com/peers/peerjs/
|
||||
chunk(blob) {
|
||||
const chunks = [];
|
||||
const size = blob.size;
|
||||
const total = Math.ceil(size / MAX_BUFFER_SIZE);
|
||||
const id = shortid.generate();
|
||||
|
||||
let index = 0;
|
||||
let start = 0;
|
||||
|
||||
while (start < size) {
|
||||
const end = Math.min(size, start + MAX_BUFFER_SIZE);
|
||||
const slice = blob.slice(start, end);
|
||||
|
||||
const chunk = {
|
||||
__chunked: true,
|
||||
data: slice,
|
||||
id,
|
||||
index,
|
||||
total,
|
||||
};
|
||||
|
||||
chunks.push(chunk);
|
||||
start = end;
|
||||
index++;
|
||||
}
|
||||
|
||||
return chunks;
|
||||
}
|
||||
}
|
||||
|
||||
export default Peer;
|
||||
+64
-110
@@ -1,132 +1,86 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import Peer from "peerjs";
|
||||
import io from "socket.io-client";
|
||||
|
||||
function useSession(onConnectionOpen, onConnectionSync) {
|
||||
const [peerId, setPeerId] = useState(null);
|
||||
const [peer, setPeer] = useState(null);
|
||||
const [connections, setConnections] = useState({});
|
||||
import { omit } from "../helpers/shared";
|
||||
import Peer from "../helpers/Peer";
|
||||
|
||||
function addConnection(connection) {
|
||||
console.log("Adding connection", connection.peer);
|
||||
setConnections(prevConnnections => {
|
||||
console.log("Connections", {
|
||||
...prevConnnections,
|
||||
[connection.peer]: connection
|
||||
const socket = io("http://localhost:9000");
|
||||
|
||||
function useSession(partyId, onPeerConnected, onPeerDisconnected, onPeerData) {
|
||||
useEffect(() => {
|
||||
socket.emit("join party", partyId);
|
||||
}, [partyId]);
|
||||
|
||||
const [peers, setPeers] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
function addPeer(id, initiator) {
|
||||
const peer = new Peer({ initiator, trickle: false });
|
||||
|
||||
peer.on("signal", (signal) => {
|
||||
socket.emit("signal", JSON.stringify({ to: id, signal }));
|
||||
});
|
||||
return {
|
||||
...prevConnnections,
|
||||
[connection.peer]: connection
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Creating peer");
|
||||
setPeer(new Peer());
|
||||
}, []);
|
||||
peer.on("connect", () => {
|
||||
onPeerConnected && onPeerConnected({ id, peer, initiator });
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
function handleOpen(id) {
|
||||
console.log("Peer open", id);
|
||||
setPeerId(id);
|
||||
peer.on("dataComplete", (data) => {
|
||||
onPeerData && onPeerData({ id, peer, data });
|
||||
});
|
||||
|
||||
peer.on("close", () => {
|
||||
onPeerDisconnected && onPeerDisconnected(id);
|
||||
});
|
||||
|
||||
peer.on("error", (err) => {
|
||||
onPeerDisconnected && onPeerDisconnected(id);
|
||||
console.error("error", err);
|
||||
});
|
||||
|
||||
setPeers((prevPeers) => ({
|
||||
...prevPeers,
|
||||
[id]: peer,
|
||||
}));
|
||||
}
|
||||
|
||||
function handleConnection(connection) {
|
||||
connection.on("open", () => {
|
||||
console.log("incoming connection added", connection.peer);
|
||||
const metadata = connection.metadata;
|
||||
if (metadata.sync) {
|
||||
connection.send({
|
||||
id: "sync",
|
||||
data: { connections: Object.keys(connections) }
|
||||
});
|
||||
if (onConnectionSync) {
|
||||
onConnectionSync(connection);
|
||||
}
|
||||
}
|
||||
function handlePartyMemberJoined(id) {
|
||||
addPeer(id, false);
|
||||
}
|
||||
|
||||
addConnection(connection);
|
||||
|
||||
if (onConnectionOpen) {
|
||||
onConnectionOpen(connection);
|
||||
}
|
||||
});
|
||||
|
||||
function removeConnection() {
|
||||
console.log("removing connection", connection.peer);
|
||||
setConnections(prevConnections => {
|
||||
const { [connection.peer]: old, ...rest } = prevConnections;
|
||||
return rest;
|
||||
});
|
||||
function handlePartyMemberLeft(id) {
|
||||
if (id in peers) {
|
||||
peers[id].destroy();
|
||||
}
|
||||
connection.on("close", removeConnection);
|
||||
connection.on("error", error => {
|
||||
console.error("Data Connection error", error);
|
||||
removeConnection();
|
||||
});
|
||||
setPeers((prevPeers) => omit(prevPeers, [id]));
|
||||
}
|
||||
|
||||
function handleError(error) {
|
||||
console.error("Peer error", error);
|
||||
function handleJoinedParty(otherIds) {
|
||||
for (let id of otherIds) {
|
||||
addPeer(id, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!peer) {
|
||||
return;
|
||||
function handleSignal(data) {
|
||||
const { from, signal } = JSON.parse(data);
|
||||
if (from in peers) {
|
||||
peers[from].signal(signal);
|
||||
}
|
||||
}
|
||||
|
||||
peer.on("open", handleOpen);
|
||||
peer.on("connection", handleConnection);
|
||||
peer.on("error", handleError);
|
||||
socket.on("party member joined", handlePartyMemberJoined);
|
||||
socket.on("party member left", handlePartyMemberLeft);
|
||||
socket.on("joined party", handleJoinedParty);
|
||||
socket.on("signal", handleSignal);
|
||||
return () => {
|
||||
peer.removeListener("open", handleOpen);
|
||||
peer.removeListener("connection", handleConnection);
|
||||
peer.removeListener("error", handleError);
|
||||
socket.removeListener("party member joined", handlePartyMemberJoined);
|
||||
socket.removeListener("party member left", handlePartyMemberLeft);
|
||||
socket.removeListener("joined party", handleJoinedParty);
|
||||
socket.removeListener("signal", handleSignal);
|
||||
};
|
||||
}, [peer, peerId, connections, onConnectionOpen, onConnectionSync]);
|
||||
}, [peers, onPeerConnected, onPeerDisconnected, onPeerData]);
|
||||
|
||||
function connectTo(connectionId, payload) {
|
||||
console.log("Connecting to", connectionId);
|
||||
if (connectionId in connections) {
|
||||
return;
|
||||
}
|
||||
const connection = peer.connect(connectionId, {
|
||||
metadata: { sync: true }
|
||||
});
|
||||
addConnection(connection);
|
||||
connection.on("open", () => {
|
||||
connection.on("data", data => {
|
||||
if (data.id === "sync") {
|
||||
const { connections: syncConnections } = data.data;
|
||||
for (let syncId of syncConnections) {
|
||||
console.log("Syncing to", syncId);
|
||||
if (connectionId === syncId || syncId in connections) {
|
||||
continue;
|
||||
}
|
||||
const syncConnection = peer.connect(syncId, {
|
||||
metadata: { sync: false }
|
||||
});
|
||||
addConnection(syncConnection);
|
||||
syncConnection.on("open", () => {
|
||||
if (onConnectionOpen) {
|
||||
onConnectionOpen(syncConnection);
|
||||
}
|
||||
if (payload) {
|
||||
syncConnection.send(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
if (onConnectionOpen) {
|
||||
onConnectionOpen(connection);
|
||||
}
|
||||
if (payload) {
|
||||
connection.send(payload);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return { peer, peerId, connections, connectTo };
|
||||
return { peers, id: socket.id };
|
||||
}
|
||||
|
||||
export default useSession;
|
||||
|
||||
+59
-83
@@ -1,15 +1,8 @@
|
||||
import React, {
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
useRef,
|
||||
useCallback
|
||||
} from "react";
|
||||
import React, { useState, useRef } from "react";
|
||||
import { Flex } from "theme-ui";
|
||||
|
||||
import { omit } from "../helpers/shared";
|
||||
|
||||
import GameContext from "../contexts/GameContext";
|
||||
import useSession from "../helpers/useSession";
|
||||
import { getRandomMonster } from "../helpers/monsters";
|
||||
|
||||
@@ -17,40 +10,22 @@ import Party from "../components/Party";
|
||||
import Tokens from "../components/Tokens";
|
||||
import Map from "../components/Map";
|
||||
|
||||
const defaultNickname = getRandomMonster();
|
||||
|
||||
function Game() {
|
||||
const { gameId } = useContext(GameContext);
|
||||
const handleConnectionOpenCallback = useCallback(handleConnectionOpen);
|
||||
const handleConnectionSyncCallback = useCallback(handleConnectionSync);
|
||||
const { peerId, connections, connectTo } = useSession(
|
||||
handleConnectionOpenCallback,
|
||||
handleConnectionSyncCallback
|
||||
function Game({ gameId }) {
|
||||
const { peers, id } = useSession(
|
||||
gameId,
|
||||
handlePeerConnected,
|
||||
handlePeerDisconnected,
|
||||
handlePeerData
|
||||
);
|
||||
|
||||
const [nicknames, setNicknames] = useState({});
|
||||
|
||||
useEffect(() => {
|
||||
// Initialize nickname state
|
||||
if (peerId !== null && !(peerId in nicknames)) {
|
||||
setNicknames({ [peerId]: defaultNickname });
|
||||
}
|
||||
if (gameId !== null && peerId !== null && !(gameId in connections)) {
|
||||
connectTo(gameId, {
|
||||
id: "nickname",
|
||||
data: { [peerId]: nicknames[peerId] || defaultNickname }
|
||||
});
|
||||
}
|
||||
}, [gameId, peerId, connectTo, connections, nicknames]);
|
||||
|
||||
const [mapSource, setMapSource] = useState(null);
|
||||
const mapDataRef = useRef(null);
|
||||
|
||||
function handleMapChanged(mapData, mapSource) {
|
||||
mapDataRef.current = mapData;
|
||||
setMapSource(mapSource);
|
||||
for (let connection of Object.values(connections)) {
|
||||
connection.send({ id: "map", data: mapDataRef.current });
|
||||
for (let peer of Object.values(peers)) {
|
||||
peer.send({ id: "map", data: mapDataRef.current });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,75 +35,75 @@ function Game() {
|
||||
if (!mapSource) {
|
||||
return;
|
||||
}
|
||||
setMapTokens(prevMapTokens => ({
|
||||
setMapTokens((prevMapTokens) => ({
|
||||
...prevMapTokens,
|
||||
[token.id]: token
|
||||
[token.id]: token,
|
||||
}));
|
||||
for (let connection of Object.values(connections)) {
|
||||
for (let peer of Object.values(peers)) {
|
||||
const data = { [token.id]: token };
|
||||
connection.send({ id: "tokenEdit", data });
|
||||
peer.send({ id: "tokenEdit", data });
|
||||
}
|
||||
}
|
||||
|
||||
function handleRemoveMapToken(token) {
|
||||
setMapTokens(prevMapTokens => {
|
||||
setMapTokens((prevMapTokens) => {
|
||||
const { [token.id]: old, ...rest } = prevMapTokens;
|
||||
return rest;
|
||||
});
|
||||
for (let connection of Object.values(connections)) {
|
||||
for (let peer of Object.values(peers)) {
|
||||
const data = { [token.id]: token };
|
||||
connection.send({ id: "tokenRemove", data });
|
||||
peer.send({ id: "tokenRemove", data });
|
||||
}
|
||||
}
|
||||
|
||||
const [nickname, setNickname] = useState(getRandomMonster());
|
||||
const [partyNicknames, setPartyNicknames] = useState({});
|
||||
|
||||
function handleNicknameChange(nickname) {
|
||||
setNicknames(prevNicknames => ({
|
||||
...prevNicknames,
|
||||
[peerId]: nickname
|
||||
}));
|
||||
for (let connection of Object.values(connections)) {
|
||||
const data = { [peerId]: nickname };
|
||||
connection.send({ id: "nickname", data });
|
||||
setNickname(nickname);
|
||||
for (let peer of Object.values(peers)) {
|
||||
const data = { [id]: nickname };
|
||||
peer.send({ id: "nickname", data });
|
||||
}
|
||||
}
|
||||
|
||||
function handleConnectionOpen(connection) {
|
||||
connection.on("data", data => {
|
||||
if (data.id === "map") {
|
||||
const blob = new Blob([data.data.file]);
|
||||
mapDataRef.current = { ...data.data, file: blob };
|
||||
setMapSource(URL.createObjectURL(mapDataRef.current.file));
|
||||
function handlePeerConnected({ id, peer, initiator }) {
|
||||
if (!initiator) {
|
||||
if (mapSource) {
|
||||
peer.send({ id: "map", data: mapDataRef.current });
|
||||
}
|
||||
if (data.id === "tokenEdit") {
|
||||
setMapTokens(prevMapTokens => ({
|
||||
...prevMapTokens,
|
||||
...data.data
|
||||
}));
|
||||
}
|
||||
if (data.id === "tokenRemove") {
|
||||
setMapTokens(prevMapTokens =>
|
||||
omit(prevMapTokens, Object.keys(data.data))
|
||||
);
|
||||
}
|
||||
if (data.id === "nickname") {
|
||||
setNicknames(prevNicknames => ({
|
||||
...prevNicknames,
|
||||
...data.data
|
||||
}));
|
||||
}
|
||||
});
|
||||
connection.on("error", error => {
|
||||
console.error("Data Connection error", error);
|
||||
setNicknames(prevNicknames => omit(prevNicknames, [connection.peer]));
|
||||
});
|
||||
peer.send({ id: "tokenEdit", data: mapTokens });
|
||||
}
|
||||
peer.send({ id: "nickname", data: { [id]: nickname } });
|
||||
}
|
||||
|
||||
function handleConnectionSync(connection) {
|
||||
if (mapSource) {
|
||||
connection.send({ id: "map", data: mapDataRef.current });
|
||||
function handlePeerData({ id, peer, data }) {
|
||||
if (data.id === "map") {
|
||||
const blob = new Blob([data.data.file]);
|
||||
mapDataRef.current = { ...data.data, file: blob };
|
||||
setMapSource(URL.createObjectURL(mapDataRef.current.file));
|
||||
}
|
||||
connection.send({ id: "tokenEdit", data: mapTokens });
|
||||
connection.send({ id: "nickname", data: nicknames });
|
||||
if (data.id === "tokenEdit") {
|
||||
setMapTokens((prevMapTokens) => ({
|
||||
...prevMapTokens,
|
||||
...data.data,
|
||||
}));
|
||||
}
|
||||
if (data.id === "tokenRemove") {
|
||||
setMapTokens((prevMapTokens) =>
|
||||
omit(prevMapTokens, Object.keys(data.data))
|
||||
);
|
||||
}
|
||||
if (data.id === "nickname") {
|
||||
setPartyNicknames((prevNicknames) => ({
|
||||
...prevNicknames,
|
||||
...data.data,
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function handlePeerDisconnected(disconnectedId) {
|
||||
setPartyNicknames((prevNicknames) => omit(prevNicknames, [disconnectedId]));
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -137,8 +112,9 @@ function Game() {
|
||||
sx={{ justifyContent: "space-between", flexGrow: 1, height: "100%" }}
|
||||
>
|
||||
<Party
|
||||
nicknames={nicknames}
|
||||
peerId={peerId}
|
||||
nickname={nickname}
|
||||
partyNicknames={partyNicknames}
|
||||
gameId={gameId}
|
||||
onNicknameChange={handleNicknameChange}
|
||||
/>
|
||||
<Map
|
||||
|
||||
+4
-8
@@ -1,17 +1,13 @@
|
||||
import React, { useContext } from "react";
|
||||
import React from "react";
|
||||
import { navigate } from "hookrouter";
|
||||
import { Container, Flex, Button, Image, Text } from "theme-ui";
|
||||
|
||||
import GameContext from "../contexts/GameContext";
|
||||
import shortid from "shortid";
|
||||
|
||||
import owlington from "../images/Owlington.png";
|
||||
|
||||
function Home() {
|
||||
const { setGameId } = useContext(GameContext);
|
||||
|
||||
function handleStartGame() {
|
||||
setGameId(null);
|
||||
navigate("/game");
|
||||
navigate(`/game/${shortid.generate()}`);
|
||||
}
|
||||
|
||||
function handleJoinGame() {
|
||||
@@ -24,7 +20,7 @@ function Home() {
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
justifyContent: "center"
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Text variant="display" sx={{ textAlign: "center" }}>
|
||||
|
||||
+4
-6
@@ -1,11 +1,9 @@
|
||||
import React, { useContext } from "react";
|
||||
import React, { useState } from "react";
|
||||
import { navigate } from "hookrouter";
|
||||
import { Container, Box, Label, Input, Button, Flex } from "theme-ui";
|
||||
|
||||
import GameContext from "../contexts/GameContext";
|
||||
|
||||
function Join() {
|
||||
const { gameId, setGameId } = useContext(GameContext);
|
||||
const [gameId, setGameId] = useState("");
|
||||
|
||||
function handleChange(event) {
|
||||
setGameId(event.target.value);
|
||||
@@ -13,7 +11,7 @@ function Join() {
|
||||
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
navigate("/game");
|
||||
navigate(`/game/${gameId}`);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -22,7 +20,7 @@ function Join() {
|
||||
sx={{
|
||||
flexDirection: "column",
|
||||
height: "100%",
|
||||
justifyContent: "center"
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<Box as="form" onSubmit={handleSubmit}>
|
||||
|
||||
Reference in New Issue
Block a user