initial find & create game functionality
and restructure homepage components
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
import PublicGames from "@/components/PublicGames";
|
import PublicGames from "@/components/home/PublicGames";
|
||||||
|
import JoinGame from "@/components/home/JoinGame";
|
||||||
|
import CreateGame from "@/components/home/CreateGame";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
||||||
@@ -8,39 +10,14 @@ export default function Home() {
|
|||||||
<div className="flex flex-col items-center gap-4">
|
<div className="flex flex-col items-center gap-4">
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<h2 className="mb-4 text-xl font-bold leading-tight">Join from invite</h2>
|
<h2 className="mb-4 text-xl font-bold leading-tight">Join from invite</h2>
|
||||||
<div className="form-control">
|
<JoinGame />
|
||||||
<div className="input-group">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
placeholder="Invite link or code"
|
|
||||||
className="input input-bordered"
|
|
||||||
/>
|
|
||||||
<button className="btn btn-square">Join</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="divider divider-vertical">or</div>
|
<div className="divider divider-vertical">or</div>
|
||||||
|
|
||||||
<div className="flex flex-col items-center">
|
<div className="flex flex-col items-center">
|
||||||
<h2 className="mb-4 text-xl font-bold leading-tight">Create game</h2>
|
<h2 className="mb-4 text-xl font-bold leading-tight">Create game</h2>
|
||||||
<div className="form-control">
|
<CreateGame />
|
||||||
<label className="label cursor-pointer">
|
|
||||||
<span className="label-text">Unlisted/invite-only</span>
|
|
||||||
<input type="checkbox" className="checkbox" />
|
|
||||||
</label>
|
|
||||||
<label className="label">
|
|
||||||
<span className="label-text">Select your side</span>
|
|
||||||
</label>
|
|
||||||
<div className="input-group">
|
|
||||||
<select className="select select-bordered">
|
|
||||||
<option value="random">Random</option>
|
|
||||||
<option value="white">White</option>
|
|
||||||
<option value="black">Black</option>
|
|
||||||
</select>
|
|
||||||
<button className="btn">Create</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
59
client/src/components/home/CreateGame.tsx
Normal file
59
client/src/components/home/CreateGame.tsx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import type { FormEvent } from "react";
|
||||||
|
import { useState, useContext } from "react";
|
||||||
|
import { SessionContext } from "@/context/session";
|
||||||
|
import { createGame } from "@/lib/game";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function CreateGame() {
|
||||||
|
const session = useContext(SessionContext);
|
||||||
|
const [buttonLoading, setButtonLoading] = useState(false);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
async function submitCreateGame(e: FormEvent<HTMLFormElement>) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!session?.user?.id) return;
|
||||||
|
setButtonLoading(true);
|
||||||
|
|
||||||
|
const target = e.target as HTMLFormElement;
|
||||||
|
const unlisted = target.elements.namedItem("createUnlisted") as HTMLInputElement;
|
||||||
|
const startingSide = (target.elements.namedItem("createStartingSide") as HTMLSelectElement)
|
||||||
|
.value;
|
||||||
|
|
||||||
|
const game = await createGame(startingSide, unlisted.checked);
|
||||||
|
|
||||||
|
if (game) {
|
||||||
|
router.push(`/game/${game.code}`);
|
||||||
|
} else {
|
||||||
|
setButtonLoading(false);
|
||||||
|
// TODO: Show error message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className="form-control" onSubmit={submitCreateGame}>
|
||||||
|
<label className="label cursor-pointer">
|
||||||
|
<span className="label-text">Unlisted/invite-only</span>
|
||||||
|
<input type="checkbox" className="checkbox" name="createUnlisted" id="createUnlisted" />
|
||||||
|
</label>
|
||||||
|
<label className="label" htmlFor="createStartingSide">
|
||||||
|
<span className="label-text">Select your side</span>
|
||||||
|
</label>
|
||||||
|
<div className="input-group">
|
||||||
|
<select
|
||||||
|
className="select select-bordered"
|
||||||
|
name="createStartingSide"
|
||||||
|
id="createStartingSide"
|
||||||
|
>
|
||||||
|
<option value="random">Random</option>
|
||||||
|
<option value="white">White</option>
|
||||||
|
<option value="black">Black</option>
|
||||||
|
</select>
|
||||||
|
<button className={"btn" + (buttonLoading ? " loading" : "")} type="submit">
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
52
client/src/components/home/JoinGame.tsx
Normal file
52
client/src/components/home/JoinGame.tsx
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import type { FormEvent } from "react";
|
||||||
|
import { useState, useContext } from "react";
|
||||||
|
import { SessionContext } from "@/context/session";
|
||||||
|
import { findGame } from "@/lib/game";
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
|
||||||
|
export default function JoinGame() {
|
||||||
|
const session = useContext(SessionContext);
|
||||||
|
const [buttonLoading, setButtonLoading] = useState(false);
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
async function submitJoinGame(e: FormEvent<HTMLFormElement>) {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!session?.user?.id) return;
|
||||||
|
setButtonLoading(true);
|
||||||
|
|
||||||
|
const target = e.target as HTMLFormElement;
|
||||||
|
const codeEl = target.elements.namedItem("joinGameCode") as HTMLInputElement;
|
||||||
|
|
||||||
|
let code = codeEl.value;
|
||||||
|
if (code.startsWith("http") || code.startsWith("ches.su")) {
|
||||||
|
code = new URL(code).pathname.split("/")[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
const game = await findGame(code);
|
||||||
|
|
||||||
|
if (game) {
|
||||||
|
router.push(`/game/${game.code}`);
|
||||||
|
} else {
|
||||||
|
setButtonLoading(false);
|
||||||
|
codeEl.value = "";
|
||||||
|
// TODO: Show error message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<form className="input-group" onSubmit={submitJoinGame}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Invite link or code"
|
||||||
|
className="input input-bordered"
|
||||||
|
name="joinGameCode"
|
||||||
|
id="joinGameCode"
|
||||||
|
/>
|
||||||
|
<button className={"btn btn-square" + (buttonLoading ? " loading" : "")} type="submit">
|
||||||
|
Join
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user