description-improv / src /components /HighScoreBoard.tsx
Felix Zieger
app update
8725cc4
raw
history blame
4.28 kB
import { useState } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { supabase } from "@/integrations/supabase/client";
import { useQuery } from "@tanstack/react-query";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { useToast } from "@/components/ui/use-toast";
interface HighScore {
id: string;
player_name: string;
score: number;
avg_words_per_round: number;
created_at: string;
}
interface HighScoreBoardProps {
currentScore: number;
avgWordsPerRound: number;
onClose: () => void;
onPlayAgain: () => void;
}
export const HighScoreBoard = ({
currentScore,
avgWordsPerRound,
onClose,
onPlayAgain,
}: HighScoreBoardProps) => {
const [playerName, setPlayerName] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const { toast } = useToast();
const { data: highScores, refetch } = useQuery({
queryKey: ["highScores"],
queryFn: async () => {
const { data, error } = await supabase
.from("high_scores")
.select("*")
.order("score", { ascending: false })
.order("avg_words_per_round", { ascending: true });
if (error) throw error;
return data as HighScore[];
},
});
const handleSubmitScore = async () => {
if (!playerName.trim()) {
toast({
title: "Error",
description: "Please enter your name",
variant: "destructive",
});
return;
}
setIsSubmitting(true);
try {
const { error } = await supabase.from("high_scores").insert({
player_name: playerName.trim(),
score: currentScore,
avg_words_per_round: avgWordsPerRound,
});
if (error) throw error;
toast({
title: "Success!",
description: "Your score has been recorded",
});
await refetch();
setPlayerName("");
} catch (error) {
console.error("Error submitting score:", error);
toast({
title: "Error",
description: "Failed to submit score. Please try again.",
variant: "destructive",
});
} finally {
setIsSubmitting(false);
}
};
return (
<div className="space-y-6">
<div className="text-center">
<h2 className="text-2xl font-bold mb-2">High Scores</h2>
<p className="text-gray-600">
Your score: {currentScore} rounds
{currentScore > 0 && ` (${avgWordsPerRound.toFixed(1)} words/round)`}
</p>
</div>
<div className="flex gap-4 mb-6">
<Input
placeholder="Enter your name"
value={playerName}
onChange={(e) => setPlayerName(e.target.value)}
className="flex-1"
/>
<Button
onClick={handleSubmitScore}
disabled={isSubmitting || !playerName.trim()}
>
{isSubmitting ? "Submitting..." : "Submit Score"}
</Button>
</div>
<div className="rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead>Rank</TableHead>
<TableHead>Player</TableHead>
<TableHead>Rounds</TableHead>
<TableHead>Avg Words/Round</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{highScores?.map((score, index) => (
<TableRow key={score.id}>
<TableCell>{index + 1}</TableCell>
<TableCell>{score.player_name}</TableCell>
<TableCell>{score.score}</TableCell>
<TableCell>{score.avg_words_per_round.toFixed(1)}</TableCell>
</TableRow>
))}
{!highScores?.length && (
<TableRow>
<TableCell colSpan={4} className="text-center">
No high scores yet. Be the first!
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
<div className="flex justify-end gap-4">
<Button variant="outline" onClick={onClose}>
Close
</Button>
<Button onClick={onPlayAgain}>Play Again</Button>
</div>
</div>
);
};