leaky-ships/leaky-ships/pages/start.tsx
2023-05-13 15:21:24 +02:00

211 lines
6.3 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 { toast } from "react-toastify"
import { Icons } from "react-toastify"
export function isAuthenticated(res: Response) {
if (status[`${res.status}_CLASS`] === status.classes.SUCCESSFUL)
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 gamePromise = fetch("/api/game/" + (!pin ? "create" : "join"), {
method: "POST",
body: JSON.stringify({ pin }),
})
.then(isAuthenticated)
.then((game) => GamePropsSchema.parse(game))
const action = !pin ? "erstellt" : "angefragt"
const toastId = "pageLoad"
toast("Raum wird " + action, {
icon: Icons.spinner(),
toastId,
autoClose: false,
hideProgressBar: true,
closeButton: false,
})
const res = await gamePromise.catch(() =>
toast.update(toastId, {
render: "Es ist ein Fehler aufgetreten 🤯",
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 🤯",
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">
<button
className="-mt-2 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>
<div className="flex flex-col items-center gap-6 sm:gap-12">
<OptionButton
action={() => gameFetch()}
icon={faPlus}
disabled={!session}
>
Raum erstellen
</OptionButton>
<OptionButton
action={() => {
router.push({
pathname: router.pathname,
query: { q: "join" },
})
}}
icon={faUserPlus}
disabled={!session}
>
{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} />}
/>
) : (
"Raum beitreten"
)}
</OptionButton>
<OptionButton
icon={faEye}
action={() => {
router.push({
pathname: router.pathname,
query: { q: "watch" },
})
}}
>
{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} />}
/>
) : (
"Zuschauen"
)}
</OptionButton>
</div>
</div>
</div>
</div>
)
}