Using next-auth
This commit is contained in:
parent
b9e72b2a32
commit
dab3abdda2
50 changed files with 656 additions and 1525 deletions
168
leaky-ships/pages/start.tsx
Normal file
168
leaky-ships/pages/start.tsx
Normal file
|
@ -0,0 +1,168 @@
|
|||
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 useGameState from "@lib/hooks/useGameState"
|
||||
import { createSchema } from "@lib/zodSchemas"
|
||||
import status from "http-status"
|
||||
import { GetServerSideProps } from "next"
|
||||
import { useRouter } from "next/router"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
import OtpInput from "react-otp-input"
|
||||
import { toast } from "react-toastify"
|
||||
|
||||
interface Props {
|
||||
q: string | string[] | undefined
|
||||
}
|
||||
function isInputOnlyNumbers(input: string) {
|
||||
return /^\d+$/.test(input)
|
||||
}
|
||||
|
||||
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: "error",
|
||||
theme: "colored",
|
||||
})
|
||||
return Promise.reject()
|
||||
}
|
||||
|
||||
export default function Home({ q }: Props) {
|
||||
const [otp, setOtp] = useState("")
|
||||
const { gameProps, setGameProps } = useGameState()
|
||||
const router = useRouter()
|
||||
const { session } = useGameState()
|
||||
|
||||
const gameFetch = useCallback(
|
||||
async (pin?: string) => {
|
||||
const gamePromise = fetch("/api/game/" + (!pin ? "create" : "join"), {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ pin }),
|
||||
})
|
||||
.then(isAuthenticated)
|
||||
.then((game) => createSchema.parse(game))
|
||||
|
||||
const res = await toast.promise(gamePromise, {
|
||||
pending: {
|
||||
render: "Raum wird " + (!pin ? "erstellt" : "angefragt"),
|
||||
},
|
||||
success: {
|
||||
render: "Raum " + (!pin ? "erstellt" : "angefragt") + " 👌",
|
||||
type: "info",
|
||||
theme: "colored",
|
||||
},
|
||||
error: {
|
||||
render: "Es ist ein Fehler aufgetreten 🤯",
|
||||
type: "error",
|
||||
theme: "colored",
|
||||
},
|
||||
})
|
||||
|
||||
console.log(res)
|
||||
setGameProps(res)
|
||||
|
||||
await toast.promise(router.push("/lobby"), {
|
||||
pending: {
|
||||
render: "Raum wird beigetreten",
|
||||
},
|
||||
success: {
|
||||
render: "Raum begetreten 👌",
|
||||
type: "info",
|
||||
},
|
||||
error: {
|
||||
render: "Es ist ein Fehler aufgetreten 🤯",
|
||||
type: "error",
|
||||
},
|
||||
})
|
||||
},
|
||||
[router, setGameProps]
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (otp.length !== 4) return
|
||||
if (!isInputOnlyNumbers(otp)) {
|
||||
toast("Der Code darf nur Zahlen beinhalten!", {
|
||||
type: "warning",
|
||||
theme: "dark",
|
||||
})
|
||||
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(() => {
|
||||
// Navigate to the same page with the `start` query parameter set to `false`
|
||||
router.push({
|
||||
pathname: router.pathname,
|
||||
query: null,
|
||||
})
|
||||
}, 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}
|
||||
>
|
||||
{q === "join" ? (
|
||||
"Raum beitreten"
|
||||
) : (
|
||||
<OtpInput
|
||||
shouldAutoFocus
|
||||
containerStyle={{ color: "initial" }}
|
||||
value={otp}
|
||||
onChange={setOtp}
|
||||
numInputs={4}
|
||||
placeholder="0000"
|
||||
renderSeparator={<span>-</span>}
|
||||
renderInput={(props) => <input {...props} />}
|
||||
/>
|
||||
)}
|
||||
</OptionButton>
|
||||
<OptionButton icon={faEye}>Zuschauen</OptionButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||
context
|
||||
) => {
|
||||
const { q } = context.query
|
||||
|
||||
return { props: { q: q ? q : "" } }
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue