143 lines
4.2 KiB
TypeScript
143 lines
4.2 KiB
TypeScript
import Button from "./Button"
|
|
import Icon from "./Icon"
|
|
import Player from "./Player"
|
|
import {
|
|
faRightFromBracket,
|
|
faSpinnerThird,
|
|
} from "@fortawesome/pro-solid-svg-icons"
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
|
import { useGameProps } from "@hooks/useGameProps"
|
|
import useSocket from "@hooks/useSocket"
|
|
import { socket } from "@lib/socket"
|
|
import { useSession } from "next-auth/react"
|
|
import { useRouter } from "next/router"
|
|
import { Fragment, ReactNode, useEffect, useMemo, useState } from "react"
|
|
|
|
function WithDots({ children }: { children: ReactNode }) {
|
|
const [dots, setDots] = useState(1)
|
|
|
|
useEffect(() => {
|
|
const interval = setInterval(() => setDots((e) => (e % 3) + 1), 1000)
|
|
return () => clearInterval(interval)
|
|
}, [])
|
|
|
|
return (
|
|
<>
|
|
{children + " "}
|
|
{Array.from(Array(dots), () => ".").join("")}
|
|
{Array.from(Array(3 - dots), (_, i) => (
|
|
<Fragment key={i}> </Fragment>
|
|
))}
|
|
</>
|
|
)
|
|
}
|
|
|
|
function LobbyFrame({ openSettings }: { openSettings: () => void }) {
|
|
const { payload, userStates, full, leave, reset } = useGameProps()
|
|
const { isConnected } = useSocket()
|
|
const router = useRouter()
|
|
const { data: session } = useSession()
|
|
const [launchTime, setLaunchTime] = useState(3)
|
|
|
|
const launching = useMemo(
|
|
() =>
|
|
payload?.users.length === 2 &&
|
|
!userStates.filter((user) => !user.isReady).length,
|
|
[payload?.users.length, userStates]
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (!launching || launchTime > 0) return
|
|
socket.emit("starting")
|
|
}, [launching, launchTime, router])
|
|
|
|
useEffect(() => {
|
|
if (!launching) return setLaunchTime(3)
|
|
if (launchTime < 0) return
|
|
|
|
const timeout = setTimeout(() => {
|
|
setLaunchTime((e) => e - 1)
|
|
}, 1000)
|
|
|
|
return () => clearTimeout(timeout)
|
|
}, [launching, launchTime])
|
|
|
|
useEffect(() => {
|
|
if (payload?.game?.id || !isConnected) return
|
|
socket.emit("update", full)
|
|
}, [full, payload?.game?.id, isConnected])
|
|
|
|
useEffect(() => {
|
|
if (
|
|
typeof payload?.game?.state !== "string" ||
|
|
payload?.game?.state === "lobby"
|
|
)
|
|
return
|
|
router.push("gamefield")
|
|
})
|
|
|
|
return (
|
|
<div className="mx-32 flex flex-col self-stretch rounded-3xl bg-gray-400">
|
|
<div className="flex items-center justify-between border-b-2 border-slate-900">
|
|
<Icon src="speech_bubble.png">Chat</Icon>
|
|
<h1 className="font-farro text-5xl font-medium">
|
|
{launching ? (
|
|
<WithDots>
|
|
{launchTime < 0
|
|
? "Game starts"
|
|
: "Game is starting in " + launchTime}
|
|
</WithDots>
|
|
) : (
|
|
<>
|
|
{"Game-PIN: "}
|
|
{isConnected ? (
|
|
<span className="underline">{payload?.gamePin ?? "----"}</span>
|
|
) : (
|
|
<FontAwesomeIcon icon={faSpinnerThird} spin={true} />
|
|
)}
|
|
</>
|
|
)}
|
|
</h1>
|
|
<Icon src="gear.png" onClick={openSettings}>
|
|
Settings
|
|
</Icon>
|
|
</div>
|
|
<div className="flex items-center justify-around">
|
|
{isConnected ? (
|
|
<>
|
|
<Player src="player_blue.png" i={0} userId={session?.user.id} />
|
|
<p className="font-farro m-4 text-6xl font-semibold">VS</p>
|
|
{payload?.users[1] ? (
|
|
<Player src="player_red.png" i={1} userId={session?.user.id} />
|
|
) : (
|
|
<p className="font-farro w-96 text-center text-4xl font-medium">
|
|
<WithDots>Warte auf Spieler 2</WithDots>
|
|
</p>
|
|
)}
|
|
</>
|
|
) : (
|
|
<p className="font-farro m-48 text-center text-6xl font-medium">
|
|
Warte auf Verbindung
|
|
</p>
|
|
)}
|
|
</div>
|
|
<div className="flex items-center justify-around border-t-2 border-slate-900 p-4">
|
|
<Button
|
|
type={launching ? "gray" : "red"}
|
|
disabled={launching}
|
|
onClick={() => {
|
|
leave(async () => {
|
|
reset()
|
|
await router.push("/")
|
|
})
|
|
}}
|
|
>
|
|
<span>LEAVE</span>
|
|
<FontAwesomeIcon icon={faRightFromBracket} className="ml-4 w-12" />
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default LobbyFrame
|