Files

159 lines
7.9 KiB
TypeScript

"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import Link from "next/link";
import { getSocket } from "../lib/socket-client";
import { writeSession } from "../lib/store";
const AVATARS = ["🦄","🦊","🐼","🐸","🐱","🐶","🦁","🐯","🐰","🐻","🐨","🦝"];
export default function CreateRoomPage() {
const router = useRouter();
const [nickname, setNickname] = useState("");
const [avatar, setAvatar] = useState("🦊");
const [mode, setMode] = useState<"skribbl"|"gartic"|"color">("skribbl");
const [rounds, setRounds] = useState(4);
const [drawTime, setDrawTime] = useState(80);
const [canvasType, setCanvasType] = useState<"blank"|"template">("blank");
const [templateId, setTemplateId] = useState("mandala");
const [busy, setBusy] = useState(false);
const [err, setErr] = useState("");
const submit = async (e: React.FormEvent) => {
e.preventDefault();
setErr("");
if (!nickname.trim()) { setErr("Pick a nickname"); return; }
setBusy(true);
const settings: any = {};
if (mode === "skribbl") { settings.rounds = rounds; settings.drawTimeSec = drawTime; settings.language = "en"; }
if (mode === "color") { settings.canvasType = canvasType; settings.templateId = templateId; }
const socket = getSocket();
const finish = () => {
socket.emit("room:create", { nickname: nickname.trim(), avatar, mode, settings }, (resp: any) => {
if (!resp || !resp.ok) { setErr(resp?.error || "failed"); setBusy(false); return; }
writeSession(resp.code, { token: resp.sessionToken, nickname: nickname.trim(), avatar, playerId: resp.playerId });
router.push(`/room/${resp.code}`);
});
};
if (socket.connected) finish();
else socket.once("connect", finish);
};
return (
<div>
<header className="flex items-center justify-between max-w-[1280px] mx-auto px-7 py-5">
<Link href="/" className="flex items-center gap-2.5 font-bold text-2xl no-underline text-dark">
<span className="logo-mark sm">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2.5" strokeLinecap="round"><path d="M12 19l7-7 3 3-7 7-3-3z"/><path d="M18 13l-1.5-7.5L2 2l3.5 14.5L13 18l5-5z"/></svg>
</span>
DrawTogether
</Link>
<Link href="/join" className="btn btn-ghost" style={{padding:"10px 18px",fontSize:14}}>Join Instead</Link>
</header>
<main className="max-w-[760px] mx-auto px-6 pb-16">
<div className="text-center mb-8">
<h1 className="text-4xl font-bold">Create your room</h1>
<p className="font-medium mt-2" style={{color:"rgba(45,45,45,0.7)"}}>Pick a mode and customise the rules</p>
</div>
<form className="panel flex flex-col gap-6" onSubmit={submit}>
<div>
<label className="field-label">Your nickname</label>
<input data-testid="nickname-input" className="input-text" maxLength={20} value={nickname} onChange={(e)=>setNickname(e.target.value)} placeholder="Doodle Master"/>
</div>
<div>
<label className="field-label">Pick avatar</label>
<div className="flex flex-wrap gap-2">
{AVATARS.map(a => (
<button type="button" key={a} onClick={()=>setAvatar(a)}
className="w-12 h-12 rounded-xl border-[3px] grid place-items-center text-2xl shadow-chunky transition-transform hover:-translate-y-0.5"
style={{background: avatar===a?"var(--yellow)":"var(--cream)", borderColor: avatar===a?"var(--dark)":"rgba(45,45,45,0.3)"}}
data-testid={`avatar-${a}`}
>{a}</button>
))}
</div>
</div>
<div>
<label className="field-label">Choose game mode</label>
<div className="grid grid-cols-3 gap-3 max-[640px]:grid-cols-1">
{([
{id:"skribbl", label:"Skribbl Race", desc:"Draw & guess", color:"var(--coral)", testid:"mode-skribbl"},
{id:"gartic", label:"Gartic Phone", desc:"Pass it on", color:"var(--mint)", testid:"mode-gartic"},
{id:"color", label:"Color Together", desc:"Chill paint", color:"var(--lavender)", testid:"mode-color"},
] as const).map(m => (
<button type="button" key={m.id} onClick={()=>setMode(m.id as any)} data-testid={m.testid}
className="rounded-2xl border-[3px] p-4 text-left flex flex-col gap-1 transition-transform hover:-translate-y-1"
style={{
background: mode===m.id ? m.color : "var(--cream)",
color: mode===m.id ? "white" : "var(--dark)",
borderColor: mode===m.id ? "var(--dark)" : "rgba(45,45,45,0.2)",
boxShadow: mode===m.id ? "0 5px 0 rgba(0,0,0,0.18)" : "none",
}}>
<div className="font-bold text-lg">{m.label}</div>
<div className="text-sm opacity-90 font-medium">{m.desc}</div>
</button>
))}
</div>
</div>
{mode === "skribbl" && (
<div className="grid grid-cols-2 gap-4 max-[640px]:grid-cols-1">
<div>
<label className="field-label">Rounds</label>
<div className="flex gap-2">
{[2,4,8].map(r => (
<button type="button" key={r} onClick={()=>setRounds(r)}
data-testid={`rounds-${r}`}
className="flex-1 py-3 rounded-xl border-[3px] font-bold"
style={{background: rounds===r ? "var(--yellow)" : "var(--cream)", borderColor:"var(--dark)"}}>{r}</button>
))}
</div>
</div>
<div>
<label className="field-label">Draw time</label>
<div className="flex gap-2">
{[60,80,120].map(t => (
<button type="button" key={t} onClick={()=>setDrawTime(t)}
data-testid={`time-${t}`}
className="flex-1 py-3 rounded-xl border-[3px] font-bold"
style={{background: drawTime===t ? "var(--mint)" : "var(--cream)", borderColor:"var(--dark)"}}>{t}s</button>
))}
</div>
</div>
</div>
)}
{mode === "color" && (
<div className="grid grid-cols-2 gap-4 max-[640px]:grid-cols-1">
<div>
<label className="field-label">Canvas</label>
<div className="flex gap-2">
<button type="button" onClick={()=>setCanvasType("blank")} className="flex-1 py-3 rounded-xl border-[3px] font-bold" style={{background: canvasType==="blank"?"var(--yellow)":"var(--cream)",borderColor:"var(--dark)"}}>Blank</button>
<button type="button" onClick={()=>setCanvasType("template")} className="flex-1 py-3 rounded-xl border-[3px] font-bold" style={{background: canvasType==="template"?"var(--yellow)":"var(--cream)",borderColor:"var(--dark)"}}>Template</button>
</div>
</div>
{canvasType === "template" && (
<div>
<label className="field-label">Template</label>
<select className="input-text" value={templateId} onChange={(e)=>setTemplateId(e.target.value)}>
{["mandala","cat","tree","fish","butterfly","house","flower","sun"].map(t => <option key={t} value={t}>{t}</option>)}
</select>
</div>
)}
</div>
)}
{err && <div className="text-coral font-bold text-sm">{err}</div>}
<button type="submit" disabled={busy} data-testid="create-submit" className="btn btn-primary self-end" style={{padding:"16px 32px", fontSize:18}}>
{busy ? "Creating..." : "Create Room"}
</button>
</form>
</main>
</div>
);
}