diff --git a/App.tsx b/App.tsx
index a0096ac..8f0e380 100644
--- a/App.tsx
+++ b/App.tsx
@@ -13,6 +13,9 @@ import { RevealScreen } from './components/RevealScreen';
import { SaveQuizPrompt } from './components/SaveQuizPrompt';
import { QuizEditor } from './components/QuizEditor';
import { SaveOptionsModal } from './components/SaveOptionsModal';
+import { DisconnectedScreen } from './components/DisconnectedScreen';
+import { WaitingToRejoin } from './components/WaitingToRejoin';
+import { HostReconnected } from './components/HostReconnected';
import type { Quiz, GameConfig } from './types';
const seededRandom = (seed: number) => {
@@ -64,6 +67,7 @@ function App() {
handleAnswer,
hasAnswered,
lastPointsEarned,
+ lastAnswerCorrect,
nextQuestion,
showScoreboard,
currentCorrectShape,
@@ -77,7 +81,13 @@ function App() {
updateQuizFromEditor,
startGameFromEditor,
backFromEditor,
- gameConfig
+ gameConfig,
+ isReconnecting,
+ currentPlayerName,
+ attemptReconnect,
+ goHomeFromDisconnected,
+ endGame,
+ resumeGame
} = useGame();
const handleSaveQuiz = async () => {
@@ -168,6 +178,7 @@ function App() {
gamePin={gamePin}
role={role}
onStart={startGame}
+ onEndGame={role === 'HOST' ? endGame : undefined}
/>
{auth.isAuthenticated && pendingQuizToSave && (
) : null}
- {(gameState === 'COUNTDOWN' || gameState === 'QUESTION') && quiz ? (
+ {(gameState === 'COUNTDOWN' || gameState === 'QUESTION') ? (
gameState === 'COUNTDOWN' ? (
Get Ready!
@@ -188,7 +199,7 @@ function App() {
{timeLeft}
- ) : (
+ ) : quiz?.questions[currentQuestionIndex] ? (
- )
+ ) : role === 'CLIENT' && hasAnswered ? (
+
+
+
🚀
+
Answer Sent!
+
Cross your fingers...
+
+
+ ) : currentPlayerName ? (
+
+ ) : null
) : null}
- {gameState === 'REVEAL' && correctOpt ? (
+ {gameState === 'REVEAL' ? (
+ correctOpt ? (
0}
+ isCorrect={lastAnswerCorrect === true}
pointsEarned={lastPointsEarned || 0}
newScore={currentPlayerScore}
streak={currentStreak}
@@ -215,6 +240,12 @@ function App() {
role={role}
onNext={showScoreboard}
/>
+ ) : currentPlayerName ? (
+
+ ) : null
) : null}
{gameState === 'SCOREBOARD' ? (
@@ -232,6 +263,34 @@ function App() {
onRestart={() => window.location.reload()}
/>
) : null}
+
+ {gameState === 'DISCONNECTED' && currentPlayerName && gamePin ? (
+
+ ) : null}
+
+ {gameState === 'WAITING_TO_REJOIN' && currentPlayerName ? (
+
+ ) : null}
+
+ {gameState === 'HOST_RECONNECTED' && quiz ? (
+ p.id !== 'host').length}
+ onResume={resumeGame}
+ onEndGame={endGame}
+ />
+ ) : null}
void;
+ onGoHome: () => void;
+}
+
+export const DisconnectedScreen: React.FC = ({
+ playerName,
+ gamePin,
+ isReconnecting,
+ onReconnect,
+ onGoHome,
+}) => {
+ return (
+
+
+
+
+
+
+ Connection Lost
+
+
+ Hey {playerName}!
+
+
+ You got disconnected from game {gamePin}
+
+
+
+
+ {isReconnecting ? (
+ <>
+
+ Reconnecting...
+ >
+ ) : (
+ <>
+
+ Reconnect
+ >
+ )}
+
+
+
+
+ Abandon Game
+
+
+
+
+ Your score will be preserved if you reconnect
+
+
+
+ );
+};
diff --git a/components/HostReconnected.tsx b/components/HostReconnected.tsx
new file mode 100644
index 0000000..3069ac0
--- /dev/null
+++ b/components/HostReconnected.tsx
@@ -0,0 +1,82 @@
+import React from 'react';
+import { motion } from 'framer-motion';
+import { Play, Users, X } from 'lucide-react';
+
+interface HostReconnectedProps {
+ quizTitle: string;
+ currentQuestionIndex: number;
+ totalQuestions: number;
+ playerCount: number;
+ onResume: () => void;
+ onEndGame: () => void;
+}
+
+export const HostReconnected: React.FC = ({
+ quizTitle,
+ currentQuestionIndex,
+ totalQuestions,
+ playerCount,
+ onResume,
+ onEndGame,
+}) => {
+ return (
+
+
+
+
+
+
+ Game Restored
+ {quizTitle}
+
+
+
+
Question
+
{currentQuestionIndex + 1} / {totalQuestions}
+
+
+
Players
+
+
+ {playerCount}
+
+
+
+
+
+ Players will rejoin automatically when they reconnect
+
+
+
+
+
+ Resume Game
+
+
+
+
+ End Game
+
+
+
+
+ );
+};
diff --git a/components/Lobby.tsx b/components/Lobby.tsx
index 3a860a1..972f783 100644
--- a/components/Lobby.tsx
+++ b/components/Lobby.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { Player } from '../types';
import { motion, AnimatePresence } from 'framer-motion';
-import { Sparkles, User } from 'lucide-react';
+import { Sparkles, User, X } from 'lucide-react';
import { PlayerAvatar } from './PlayerAvatar';
interface LobbyProps {
@@ -10,9 +10,10 @@ interface LobbyProps {
gamePin: string | null;
role: 'HOST' | 'CLIENT';
onStart: () => void;
+ onEndGame?: () => void;
}
-export const Lobby: React.FC = ({ quizTitle, players, gamePin, role, onStart }) => {
+export const Lobby: React.FC = ({ quizTitle, players, gamePin, role, onStart, onEndGame }) => {
const isHost = role === 'HOST';
const realPlayers = players.filter(p => p.id !== 'host');
@@ -71,8 +72,17 @@ export const Lobby: React.FC = ({ quizTitle, players, gamePin, role,
+ {onEndGame && (
+
+ )}