92 lines
2.4 KiB
TypeScript
92 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
import { useAuth } from "@/components/AuthProvider";
|
|
import { BingoCard } from "@/components/BingoCard";
|
|
import { useParams, useRouter } from "next/navigation";
|
|
|
|
type Campaign = {
|
|
id: string;
|
|
name: string;
|
|
gridSize: number;
|
|
status: string;
|
|
};
|
|
|
|
type GridCell = {
|
|
index: number;
|
|
item: Item | null;
|
|
marked: boolean;
|
|
markedBy: string[];
|
|
markCount: number;
|
|
};
|
|
|
|
type Item = {
|
|
id: string;
|
|
text: string;
|
|
emoji: string;
|
|
soundCategory: string;
|
|
soundUrl?: string | null;
|
|
gridIndex: number;
|
|
};
|
|
|
|
export default function GamePage() {
|
|
const { user, loading: authLoading } = useAuth();
|
|
const params = useParams();
|
|
const router = useRouter();
|
|
const [campaign, setCampaign] = useState<Campaign | null>(null);
|
|
const [grid, setGrid] = useState<GridCell[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState("");
|
|
|
|
useEffect(() => {
|
|
if (authLoading) return;
|
|
if (!user) { router.push("/"); return; }
|
|
|
|
const campaignId = params.campaignId as string;
|
|
|
|
fetch(`/api/game/${campaignId}/state`)
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.error) { setError(data.error); return; }
|
|
setCampaign(data.campaign);
|
|
setGrid(data.grid);
|
|
})
|
|
.catch(() => setError("Failed to load game state"))
|
|
.finally(() => setLoading(false));
|
|
}, [user, authLoading, params.campaignId, router]);
|
|
|
|
if (authLoading || loading) {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-[60vh]">
|
|
<div className="text-center font-mono text-sm text-slate-600 animate-pulse">
|
|
<div className="text-3xl mb-2">🔄</div>
|
|
Loading submarine systems...
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
if (error || !campaign) {
|
|
return (
|
|
<div className="flex items-center justify-center min-h-[60vh]">
|
|
<div className="text-center">
|
|
<div className="text-4xl mb-3">💀</div>
|
|
<h2 className="text-xl font-mono text-red-400 mb-2">Campaign Lost</h2>
|
|
<p className="text-sm font-mono text-slate-500 mb-4">{error || "Campaign not found"}</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="py-4">
|
|
<BingoCard
|
|
campaign={campaign}
|
|
initialGrid={grid}
|
|
currentUserNickname={user!.nickname}
|
|
isAdmin={user!.isAdmin}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|