Files
movieloop-frontend/src/components/game/GameCompletionModal.tsx
T
2026-03-09 15:03:08 -07:00

119 lines
3.6 KiB
TypeScript

import { useState, useEffect } from 'react';
import {
Dialog,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { useGameStore } from '@/stores/game-store';
import { useAuthStore } from '@/stores/auth-store';
import { submitScore } from '@/api/leaderboards';
import ScoreDisplay from './ScoreDisplay';
import ShareableResult from './ShareableResult';
import CelebrationOverlay from './CelebrationOverlay';
import { playSound } from '@/lib/sounds';
import { useNavigate } from 'react-router';
function formatElapsed(seconds: number): string {
const m = Math.floor(seconds / 60);
const s = seconds % 60;
return `${m}:${s.toString().padStart(2, '0')}`;
}
export default function GameCompletionModal() {
const status = useGameStore((s) => s.status);
const score = useGameStore((s) => s.score);
const chain = useGameStore((s) => s.chain);
const movieA = useGameStore((s) => s.movieA);
const movieB = useGameStore((s) => s.movieB);
const hintsUsed = useGameStore((s) => s.hintsUsed);
const resetGame = useGameStore((s) => s.resetGame);
const user = useAuthStore((s) => s.user);
const navigate = useNavigate();
const [showModal, setShowModal] = useState(false);
useEffect(() => {
if (status === 'completed') {
setShowModal(true);
playSound('completion');
// Auto-submit score if logged in
if (user && score) {
submitScore(
score.totalScore,
score.chainLength,
score.elapsedSeconds,
hintsUsed,
).catch(() => {
// Silent fail — score is still shown locally
});
}
} else {
setShowModal(false);
}
}, [status]);
const handlePlayAgain = () => {
resetGame();
navigate('/');
};
const handleViewChain = () => {
setShowModal(false);
};
return (
<>
{status === 'completed' && <CelebrationOverlay />}
<Dialog open={showModal} onOpenChange={(open) => !open && setShowModal(false)}>
<DialogContent
className="sm:max-w-md"
showCloseButton={false}
>
<DialogHeader>
<DialogTitle className="text-center text-2xl">
Congratulations!
</DialogTitle>
<DialogDescription className="text-center">
You completed the movie loop!
</DialogDescription>
</DialogHeader>
<div className="py-4">
{score && (
<>
<ScoreDisplay score={score} />
<div className="mt-3 flex justify-center gap-4 text-sm text-muted-foreground">
<span>Completed in {formatElapsed(score.elapsedSeconds)}</span>
{hintsUsed > 0 && (
<span>{hintsUsed} hint{hintsUsed > 1 ? 's' : ''} used</span>
)}
</div>
</>
)}
</div>
<div className="flex flex-col items-center gap-3">
{score && movieA && movieB && (
<ShareableResult
score={score}
chain={chain}
movieATitle={movieA.title}
movieBTitle={movieB.title}
/>
)}
<div className="flex gap-3">
<Button variant="outline" onClick={handleViewChain}>
View Chain
</Button>
<Button onClick={handlePlayAgain} size="lg">
Play Again
</Button>
</div>
</div>
</DialogContent>
</Dialog>
</>
);
}