Keep improving
This commit is contained in:
parent
d3e8a43b34
commit
da53662d6e
8 changed files with 165 additions and 60 deletions
|
@ -20,14 +20,13 @@ function OptionButton({
|
||||||
<button
|
<button
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"flex w-full flex-row items-center justify-between rounded-xl py-2 pl-8 pr-4 text-lg text-grayish duration-100 first:mt-4 last:mt-4 sm:py-4 sm:pl-16 sm:pr-8 sm:text-4xl sm:first:mt-8 sm:last:mt-8",
|
"flex w-full flex-row items-center justify-between rounded-xl py-2 pl-8 pr-4 text-lg text-grayish duration-100 first:mt-4 last:mt-4 sm:py-4 sm:pl-16 sm:pr-8 sm:text-4xl sm:first:mt-8 sm:last:mt-8",
|
||||||
{
|
!disabled
|
||||||
"bg-voidDark border-shield-gray border-b-4 active:border-b-0 active:border-t-4":
|
? "bg-voidDark border-shield-gray border-b-4 active:border-b-0 active:border-t-4"
|
||||||
!disabled,
|
: "bg-red-950 border-slate-600 border-4 border-dashed"
|
||||||
"bg-red-950 border-slate-600 border-4 border-dashed": disabled,
|
|
||||||
}
|
|
||||||
)}
|
)}
|
||||||
onClick={() => action && setTimeout(action, 200)}
|
onClick={() => action && setTimeout(action, 200)}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
title={!disabled ? "" : "Please login"}
|
||||||
>
|
>
|
||||||
<span className="mx-auto">{children}</span>
|
<span className="mx-auto">{children}</span>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
|
@ -6,19 +6,27 @@ import { toast } from "react-toastify"
|
||||||
function useGameState() {
|
function useGameState() {
|
||||||
const [gameProps, setGameProps] = useContext(gameContext)
|
const [gameProps, setGameProps] = useContext(gameContext)
|
||||||
const { data: session, status } = useSession()
|
const { data: session, status } = useSession()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!session) return
|
if (status === "loading") return
|
||||||
toast(session.user.email, {
|
if (!session)
|
||||||
toastId: "user",
|
toast("Nicht angemeldet.", {
|
||||||
position: "top-center",
|
toastId: "user",
|
||||||
icon: session.user.image ? (
|
position: "top-center",
|
||||||
<img
|
})
|
||||||
style={{ transform: "scale(1.5)", borderRadius: "100%" }}
|
else
|
||||||
src={session.user.image}
|
toast(session.user.email, {
|
||||||
/>
|
toastId: "user",
|
||||||
) : undefined,
|
position: "top-center",
|
||||||
})
|
icon: session.user.image ? (
|
||||||
|
<img
|
||||||
|
style={{ transform: "scale(1.5)", borderRadius: "100%" }}
|
||||||
|
src={session.user.image}
|
||||||
|
/>
|
||||||
|
) : undefined,
|
||||||
|
})
|
||||||
}, [session])
|
}, [session])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
gameProps,
|
gameProps,
|
||||||
setGameProps,
|
setGameProps,
|
||||||
|
|
46
leaky-ships/pages/api/game/[id].ts
Normal file
46
leaky-ships/pages/api/game/[id].ts
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
|
import { rejectionErrors } from "@lib/backend/errors"
|
||||||
|
import sendResponse from "@lib/backend/sendResponse"
|
||||||
|
import prisma from "@lib/prisma"
|
||||||
|
import { Game } from "@prisma/client"
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import { getServerSession } from "next-auth"
|
||||||
|
|
||||||
|
interface Data {
|
||||||
|
game: Game
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function id(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<Data>
|
||||||
|
) {
|
||||||
|
const gameId = req.query.id
|
||||||
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
|
if (!session?.user || typeof gameId !== "string") {
|
||||||
|
return sendResponse(req, res, rejectionErrors.unauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
let game: Game | null
|
||||||
|
switch (req.method) {
|
||||||
|
case "DELETE":
|
||||||
|
game = await prisma.game.delete({
|
||||||
|
where: { id: gameId },
|
||||||
|
})
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
game = await prisma.game.findFirst({
|
||||||
|
where: { id: gameId },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!game) {
|
||||||
|
return sendResponse(req, res, rejectionErrors.gameNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
sendResponse(req, res, {
|
||||||
|
message: "Here is the game.",
|
||||||
|
body: { game },
|
||||||
|
})
|
||||||
|
}
|
|
@ -28,10 +28,10 @@ export default async function create(
|
||||||
|
|
||||||
let created = false
|
let created = false
|
||||||
|
|
||||||
let game = await getAnyRunningGame(id)
|
let gameDB = await getAnyRunningGame(id)
|
||||||
if (!game) {
|
if (!gameDB) {
|
||||||
created = true
|
created = true
|
||||||
game = await prisma.game.create({
|
gameDB = await prisma.game.create({
|
||||||
data: {
|
data: {
|
||||||
gamePin: {
|
gamePin: {
|
||||||
create: {
|
create: {
|
||||||
|
@ -52,12 +52,14 @@ export default async function create(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { users, gamePin, ...game } = gameDB
|
||||||
|
|
||||||
return sendResponse(req, res, {
|
return sendResponse(req, res, {
|
||||||
message: `User <${email}> created game: ${game.id}`,
|
message: `User <${email}> created game: ${game.id}`,
|
||||||
statusCode: created ? 201 : 200,
|
statusCode: created ? 201 : 200,
|
||||||
body: {
|
body: {
|
||||||
game,
|
game,
|
||||||
pin: game.gamePin?.pin,
|
pin: gamePin?.pin,
|
||||||
player: {
|
player: {
|
||||||
id,
|
id,
|
||||||
name: name ?? undefined,
|
name: name ?? undefined,
|
||||||
|
|
|
@ -38,15 +38,17 @@ export default async function create(
|
||||||
|
|
||||||
const { email, id } = session.user
|
const { email, id } = session.user
|
||||||
|
|
||||||
const game = await getAnyRunningGame(id)
|
const gameDB = await getAnyRunningGame(id)
|
||||||
|
|
||||||
if (!game)
|
if (!gameDB)
|
||||||
return sendResponse(req, res, {
|
return sendResponse(req, res, {
|
||||||
message: `User <${email}> is in no game.`,
|
message: `User <${email}> is in no game.`,
|
||||||
statusCode: 204,
|
statusCode: 204,
|
||||||
type: ["debug", "infoCyan"],
|
type: ["debug", "infoCyan"],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const { users, gamePin, ...game } = gameDB
|
||||||
|
|
||||||
return sendResponse(req, res, {
|
return sendResponse(req, res, {
|
||||||
message: `User <${email}> asked for game: ${game.id}`,
|
message: `User <${email}> asked for game: ${game.id}`,
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
|
|
60
leaky-ships/pages/game/index.tsx
Normal file
60
leaky-ships/pages/game/index.tsx
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
import { authOptions } from "../api/auth/[...nextauth]"
|
||||||
|
import { getAnyRunningGame } from "../api/game/running"
|
||||||
|
import { GetServerSideProps } from "next"
|
||||||
|
import { Session, getServerSession } from "next-auth"
|
||||||
|
import { useRouter } from "next/router"
|
||||||
|
import React, { useEffect } from "react"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
gameId: string
|
||||||
|
session: Session | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Game({ gameId, session }: Props) {
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const path = gameId ? "/game/" + gameId : "/start"
|
||||||
|
toast.promise(router.push(path), {
|
||||||
|
pending: {
|
||||||
|
render: "Wird weitergeleitet...",
|
||||||
|
toastId: "redirect",
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
render: gameId
|
||||||
|
? "Spiel gefunden!"
|
||||||
|
: session?.user
|
||||||
|
? "Kein laufendes Spiel."
|
||||||
|
: "Kein laufendes Spiel. Bitte anmelden.",
|
||||||
|
toastId: session?.user ? "postRedirect" : "user",
|
||||||
|
theme: session?.user ? "dark" : undefined,
|
||||||
|
type: gameId ? "success" : "info",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
render: "Es ist ein Fehler aufgetreten 🤯",
|
||||||
|
type: "error",
|
||||||
|
theme: "colored",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full bg-theme">
|
||||||
|
<div className="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly"></div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
|
context
|
||||||
|
) => {
|
||||||
|
const session = await getServerSession(context.req, context.res, authOptions)
|
||||||
|
let gameId = ""
|
||||||
|
if (session?.user.id) {
|
||||||
|
const game = await getAnyRunningGame(session?.user.id)
|
||||||
|
if (game && game.id) gameId = game?.id
|
||||||
|
}
|
||||||
|
|
||||||
|
return { props: { gameId, session } }
|
||||||
|
}
|
|
@ -79,7 +79,6 @@ export default function Home({ q }: Props) {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(res)
|
|
||||||
setGameProps(res)
|
setGameProps(res)
|
||||||
|
|
||||||
await toast.promise(router.push("/lobby"), {
|
await toast.promise(router.push("/lobby"), {
|
||||||
|
@ -101,14 +100,12 @@ export default function Home({ q }: Props) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (otp.length !== 4) return
|
if (otp.length !== 4) return
|
||||||
if (!isInputOnlyNumbers(otp)) {
|
if (!isInputOnlyNumbers(otp))
|
||||||
toast("Der Code darf nur Zahlen beinhalten!", {
|
toast("Der Code darf nur Zahlen beinhalten!", {
|
||||||
type: "warning",
|
type: "warning",
|
||||||
theme: "dark",
|
theme: "dark",
|
||||||
})
|
})
|
||||||
return
|
else gameFetch(otp)
|
||||||
}
|
|
||||||
gameFetch(otp)
|
|
||||||
}, [otp, gameFetch])
|
}, [otp, gameFetch])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -121,11 +118,7 @@ export default function Home({ q }: Props) {
|
||||||
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"
|
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={() =>
|
onClick={() =>
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// Navigate to the same page with the `start` query parameter set to `false`
|
router.push("/")
|
||||||
router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: null,
|
|
||||||
})
|
|
||||||
}, 200)
|
}, 200)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
@ -149,9 +142,7 @@ export default function Home({ q }: Props) {
|
||||||
icon={faUserPlus}
|
icon={faUserPlus}
|
||||||
disabled={!session}
|
disabled={!session}
|
||||||
>
|
>
|
||||||
{q === "join" ? (
|
{q === "join" && session?.user ? (
|
||||||
"Raum beitreten"
|
|
||||||
) : (
|
|
||||||
<OtpInput
|
<OtpInput
|
||||||
shouldAutoFocus
|
shouldAutoFocus
|
||||||
containerStyle={{ color: "initial" }}
|
containerStyle={{ color: "initial" }}
|
||||||
|
@ -162,6 +153,8 @@ export default function Home({ q }: Props) {
|
||||||
renderSeparator={<span>-</span>}
|
renderSeparator={<span>-</span>}
|
||||||
renderInput={(props) => <input {...props} />}
|
renderInput={(props) => <input {...props} />}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
"Raum beitreten"
|
||||||
)}
|
)}
|
||||||
</OptionButton>
|
</OptionButton>
|
||||||
<OptionButton icon={faEye}>Zuschauen</OptionButton>
|
<OptionButton icon={faEye}>Zuschauen</OptionButton>
|
||||||
|
|
|
@ -68,11 +68,6 @@ model VerificationToken {
|
||||||
@@map("verificationtokens")
|
@@map("verificationtokens")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TokenType {
|
|
||||||
REFRESH
|
|
||||||
ACCESS
|
|
||||||
}
|
|
||||||
|
|
||||||
enum GameState {
|
enum GameState {
|
||||||
launching
|
launching
|
||||||
running
|
running
|
||||||
|
@ -88,6 +83,14 @@ model Game {
|
||||||
users User_Game[]
|
users User_Game[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
model Gamepin {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
pin String @unique
|
||||||
|
gameId String @unique
|
||||||
|
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
|
||||||
|
}
|
||||||
|
|
||||||
model User_Game {
|
model User_Game {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
@ -96,33 +99,25 @@ model User_Game {
|
||||||
isOwner Boolean
|
isOwner Boolean
|
||||||
moves Move[]
|
moves Move[]
|
||||||
chats Chat[]
|
chats Chat[]
|
||||||
game Game @relation(fields: [gameId], references: [id])
|
game Game @relation(fields: [gameId], references: [id], onDelete: Cascade)
|
||||||
user User @relation(fields: [userId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
|
||||||
@@unique([gameId, userId])
|
@@unique([gameId, userId])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Move {
|
model Move {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
index Int
|
index Int
|
||||||
gameId String
|
user_game_id String
|
||||||
game User_Game @relation(fields: [gameId], references: [id])
|
user_game User_Game @relation(fields: [user_game_id], references: [id], onDelete: Cascade)
|
||||||
}
|
|
||||||
|
|
||||||
model Gamepin {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
pin String @unique
|
|
||||||
gameId String @unique
|
|
||||||
game Game @relation(fields: [gameId], references: [id])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
model Chat {
|
model Chat {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
message String?
|
message String?
|
||||||
event String?
|
event String?
|
||||||
gameId String
|
user_game_id String
|
||||||
game User_Game @relation(fields: [gameId], references: [id])
|
user_game User_Game @relation(fields: [user_game_id], references: [id], onDelete: Cascade)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue