231 lines
7.1 KiB
TypeScript
231 lines
7.1 KiB
TypeScript
import BurgerMenu from "@components/BurgerMenu"
|
|
import Logo from "@components/Logo"
|
|
import OptionButton from "@components/OptionButton"
|
|
import { faEye, faLeftLong } from "@fortawesome/pro-regular-svg-icons"
|
|
import { faPlus, faUserPlus } from "@fortawesome/pro-solid-svg-icons"
|
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
|
import { useGameProps } from "@hooks/useGameProps"
|
|
import { GamePropsSchema } from "@lib/zodSchemas"
|
|
import status from "http-status"
|
|
import { useSession } from "next-auth/react"
|
|
import { useRouter } from "next/router"
|
|
import { useCallback, useEffect, useMemo, useState } from "react"
|
|
import OtpInput from "react-otp-input"
|
|
import { Icons, toast } from "react-toastify"
|
|
|
|
export function isAuthenticated(res: Response) {
|
|
switch (status[`${res.status}_CLASS`]) {
|
|
case status.classes.SUCCESSFUL:
|
|
case status.classes.REDIRECTION:
|
|
return res.json()
|
|
}
|
|
|
|
const resStatus = status[`${res.status}_CLASS`]
|
|
if (typeof resStatus !== "string") return
|
|
|
|
toast(status[res.status], {
|
|
position: "top-center",
|
|
type: "info",
|
|
theme: "colored",
|
|
})
|
|
}
|
|
|
|
const handleConfirmation = () => {
|
|
const toastId = "confirm"
|
|
toast.warn(
|
|
<div id="toast-confirm">
|
|
<h4>You are already in another round, do you want to:</h4>
|
|
<button onClick={() => toast.dismiss(toastId)}>Join</button>
|
|
or
|
|
<button onClick={() => toast.dismiss(toastId)}>Leave</button>
|
|
</div>,
|
|
{ autoClose: false, toastId },
|
|
)
|
|
}
|
|
|
|
export default function Start() {
|
|
const [otp, setOtp] = useState("")
|
|
const { full } = useGameProps()
|
|
const router = useRouter()
|
|
const { data: session } = useSession()
|
|
|
|
const query = useMemo((): { join?: boolean; watch?: boolean } => {
|
|
switch (router.query.q) {
|
|
case "join":
|
|
return { join: true }
|
|
case "watch":
|
|
return { watch: true }
|
|
default:
|
|
return {}
|
|
}
|
|
}, [router])
|
|
|
|
const gameFetch = useCallback(
|
|
async (pin?: string) => {
|
|
const gameRequestPromise = fetch(
|
|
"/api/game/" + (!pin ? "create" : "join"),
|
|
{
|
|
method: "POST",
|
|
body: JSON.stringify({ pin }),
|
|
},
|
|
)
|
|
.then(isAuthenticated)
|
|
.then((game) => GamePropsSchema.parse(game))
|
|
|
|
const move = !pin ? "erstellt" : "angefragt"
|
|
const toastId = "pageLoad"
|
|
toast("Raum wird " + move, {
|
|
icon: Icons.spinner(),
|
|
toastId,
|
|
autoClose: false,
|
|
hideProgressBar: true,
|
|
closeButton: false,
|
|
})
|
|
const res = await gameRequestPromise.catch(() =>
|
|
toast.update(toastId, {
|
|
render: "Es ist ein Fehler aufgetreten bei der Anfrage 🤯",
|
|
type: "error",
|
|
icon: Icons.error,
|
|
theme: "colored",
|
|
autoClose: 5000,
|
|
hideProgressBar: false,
|
|
closeButton: true,
|
|
}),
|
|
)
|
|
if (!res) return
|
|
full(res)
|
|
|
|
toast.update(toastId, {
|
|
render: "Weiterleitung",
|
|
})
|
|
|
|
router
|
|
.push("/lobby")
|
|
.then(() =>
|
|
toast.update(toastId, {
|
|
render: "Raum begetreten 👌",
|
|
type: "info",
|
|
icon: Icons.success,
|
|
autoClose: 5000,
|
|
hideProgressBar: false,
|
|
closeButton: true,
|
|
}),
|
|
)
|
|
.catch(() =>
|
|
toast.update(toastId, {
|
|
render: "Es ist ein Fehler aufgetreten beim Seiten wechsel 🤯",
|
|
type: "error",
|
|
icon: Icons.error,
|
|
theme: "colored",
|
|
autoClose: 5000,
|
|
hideProgressBar: false,
|
|
closeButton: true,
|
|
}),
|
|
)
|
|
},
|
|
[router, full],
|
|
)
|
|
|
|
useEffect(() => {
|
|
if (otp.length !== 4) return
|
|
gameFetch(otp)
|
|
}, [otp, gameFetch])
|
|
|
|
return (
|
|
<div className="h-full bg-theme">
|
|
<div className="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
|
|
<Logo />
|
|
<BurgerMenu />
|
|
<div className="flex flex-col items-center rounded-xl border-4 border-black bg-grayish px-4 py-6 shadow-lg sm:mx-8 sm:p-12 md:w-full">
|
|
<div className="flex w-full justify-between">
|
|
<button
|
|
id="back"
|
|
className="-mt-2 h-14 w-20 self-start rounded-xl border-b-4 border-shield-gray bg-voidDark text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-5xl"
|
|
onClick={() =>
|
|
setTimeout(() => {
|
|
router.push("/")
|
|
}, 200)
|
|
}
|
|
>
|
|
<FontAwesomeIcon icon={faLeftLong} />
|
|
</button>
|
|
{!session?.user.id && (
|
|
<button
|
|
id="login"
|
|
className="-mt-2 h-14 w-20 self-start rounded-xl border-b-4 border-orange-500 bg-yellow-500 text-2xl active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-4xl"
|
|
onClick={() =>
|
|
setTimeout(() => {
|
|
router.push("/signin")
|
|
}, 200)
|
|
}
|
|
>
|
|
Login
|
|
</button>
|
|
)}
|
|
</div>
|
|
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
|
<OptionButton
|
|
id="Raum erstellen"
|
|
callback={() => gameFetch()}
|
|
icon={faPlus}
|
|
disabled={!session}
|
|
/>
|
|
<OptionButton
|
|
id="Raum beitreten"
|
|
callback={() => {
|
|
router.push({
|
|
pathname: router.pathname,
|
|
query: { q: "join" },
|
|
})
|
|
}}
|
|
icon={faUserPlus}
|
|
disabled={!session}
|
|
node={
|
|
query.join && session ? (
|
|
<OtpInput
|
|
shouldAutoFocus
|
|
containerStyle={{ color: "initial" }}
|
|
value={otp}
|
|
onChange={setOtp}
|
|
numInputs={4}
|
|
inputType="number"
|
|
inputStyle="inputStyle"
|
|
placeholder="0000"
|
|
renderSeparator={<span>-</span>}
|
|
renderInput={(props) => <input {...props} />}
|
|
/>
|
|
) : undefined
|
|
}
|
|
/>
|
|
<OptionButton
|
|
id="Zuschauen"
|
|
icon={faEye}
|
|
callback={() => {
|
|
router.push({
|
|
pathname: router.pathname,
|
|
query: { q: "watch" },
|
|
})
|
|
}}
|
|
node={
|
|
query.watch ? (
|
|
<OtpInput
|
|
shouldAutoFocus
|
|
containerStyle={{ color: "initial" }}
|
|
value={otp}
|
|
onChange={setOtp}
|
|
numInputs={4}
|
|
inputType="number"
|
|
inputStyle="inputStyle"
|
|
placeholder="0000"
|
|
renderSeparator={<span>-</span>}
|
|
renderInput={(props) => <input {...props} />}
|
|
/>
|
|
) : undefined
|
|
}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|