Add host name
This commit is contained in:
parent
a9155de1bd
commit
0e15a586e6
3 changed files with 51 additions and 5 deletions
5
App.tsx
5
App.tsx
|
|
@ -105,7 +105,8 @@ function App() {
|
||||||
sendAdvance,
|
sendAdvance,
|
||||||
kickPlayer,
|
kickPlayer,
|
||||||
leaveGame,
|
leaveGame,
|
||||||
connectedPlayerIds
|
connectedPlayerIds,
|
||||||
|
setHostName
|
||||||
} = useGame(defaultConfig);
|
} = useGame(defaultConfig);
|
||||||
|
|
||||||
const handleSaveQuiz = async () => {
|
const handleSaveQuiz = async () => {
|
||||||
|
|
@ -240,6 +241,8 @@ function App() {
|
||||||
onSetPresenter={setPresenterPlayer}
|
onSetPresenter={setPresenterPlayer}
|
||||||
onKickPlayer={role === 'HOST' ? kickPlayer : undefined}
|
onKickPlayer={role === 'HOST' ? kickPlayer : undefined}
|
||||||
onLeaveGame={role === 'CLIENT' ? leaveGame : undefined}
|
onLeaveGame={role === 'CLIENT' ? leaveGame : undefined}
|
||||||
|
hostName={currentPlayerName}
|
||||||
|
onHostNameChange={role === 'HOST' ? setHostName : undefined}
|
||||||
/>
|
/>
|
||||||
{auth.isAuthenticated && pendingQuizToSave && (
|
{auth.isAuthenticated && pendingQuizToSave && (
|
||||||
<SaveQuizPrompt
|
<SaveQuizPrompt
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Player } from '../types';
|
import { Player } from '../types';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { Sparkles, User, X, Link, Check, QrCode, Crown, LogOut, UserX, Loader2 } from 'lucide-react';
|
import { Sparkles, User, X, Link, Check, QrCode, Crown, LogOut, UserX, Loader2, Pencil } from 'lucide-react';
|
||||||
import { QRCodeSVG } from 'qrcode.react';
|
import { QRCodeSVG } from 'qrcode.react';
|
||||||
import { PlayerAvatar } from './PlayerAvatar';
|
import { PlayerAvatar } from './PlayerAvatar';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
|
|
@ -19,9 +19,11 @@ interface LobbyProps {
|
||||||
onSetPresenter?: (playerId: string | null) => void;
|
onSetPresenter?: (playerId: string | null) => void;
|
||||||
onKickPlayer?: (playerId: string) => void;
|
onKickPlayer?: (playerId: string) => void;
|
||||||
onLeaveGame?: () => void;
|
onLeaveGame?: () => void;
|
||||||
|
hostName?: string | null;
|
||||||
|
onHostNameChange?: (name: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Lobby: React.FC<LobbyProps> = ({ quizTitle, players, gamePin, role, onStart, onEndGame, currentPlayerId, hostParticipates = false, presenterId, onSetPresenter, onKickPlayer, onLeaveGame }) => {
|
export const Lobby: React.FC<LobbyProps> = ({ quizTitle, players, gamePin, role, onStart, onEndGame, currentPlayerId, hostParticipates = false, presenterId, onSetPresenter, onKickPlayer, onLeaveGame, hostName, onHostNameChange }) => {
|
||||||
const isHost = role === 'HOST';
|
const isHost = role === 'HOST';
|
||||||
const hostPlayer = players.find(p => p.id === 'host');
|
const hostPlayer = players.find(p => p.id === 'host');
|
||||||
const realPlayers = players.filter(p => p.id !== 'host');
|
const realPlayers = players.filter(p => p.id !== 'host');
|
||||||
|
|
@ -29,11 +31,20 @@ export const Lobby: React.FC<LobbyProps> = ({ quizTitle, players, gamePin, role,
|
||||||
const [linkCopied, setLinkCopied] = useState(false);
|
const [linkCopied, setLinkCopied] = useState(false);
|
||||||
const [isQrModalOpen, setIsQrModalOpen] = useState(false);
|
const [isQrModalOpen, setIsQrModalOpen] = useState(false);
|
||||||
const [isStarting, setIsStarting] = useState(false);
|
const [isStarting, setIsStarting] = useState(false);
|
||||||
|
const [isEditingName, setIsEditingName] = useState(false);
|
||||||
|
const [editedName, setEditedName] = useState(hostName || 'Host');
|
||||||
|
|
||||||
const handleStart = () => {
|
const handleStart = () => {
|
||||||
setIsStarting(true);
|
setIsStarting(true);
|
||||||
onStart();
|
onStart();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleNameSubmit = () => {
|
||||||
|
if (onHostNameChange && editedName.trim()) {
|
||||||
|
onHostNameChange(editedName.trim());
|
||||||
|
}
|
||||||
|
setIsEditingName(false);
|
||||||
|
};
|
||||||
const isPresenter = currentPlayerId === presenterId;
|
const isPresenter = currentPlayerId === presenterId;
|
||||||
const canSelectPresenter = isHost && !hostParticipates && onSetPresenter;
|
const canSelectPresenter = isHost && !hostParticipates && onSetPresenter;
|
||||||
|
|
||||||
|
|
@ -192,7 +203,28 @@ export const Lobby: React.FC<LobbyProps> = ({ quizTitle, players, gamePin, role,
|
||||||
className="bg-yellow-400 text-black px-4 md:px-6 py-2 md:py-3 rounded-full font-black text-base md:text-xl shadow-[0_4px_0_rgba(0,0,0,0.2)] flex items-center gap-2 md:gap-3 border-b-4 border-yellow-500"
|
className="bg-yellow-400 text-black px-4 md:px-6 py-2 md:py-3 rounded-full font-black text-base md:text-xl shadow-[0_4px_0_rgba(0,0,0,0.2)] flex items-center gap-2 md:gap-3 border-b-4 border-yellow-500"
|
||||||
>
|
>
|
||||||
<PlayerAvatar seed={hostPlayer.avatarSeed} size={20} />
|
<PlayerAvatar seed={hostPlayer.avatarSeed} size={20} />
|
||||||
{hostPlayer.name}
|
{isEditingName ? (
|
||||||
|
<form onSubmit={(e) => { e.preventDefault(); handleNameSubmit(); }} className="flex items-center gap-2">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={editedName}
|
||||||
|
onChange={(e) => setEditedName(e.target.value)}
|
||||||
|
onBlur={handleNameSubmit}
|
||||||
|
autoFocus
|
||||||
|
maxLength={20}
|
||||||
|
className="bg-white/80 text-black px-2 py-1 rounded-lg text-base font-bold w-28 outline-none focus:ring-2 focus:ring-yellow-600"
|
||||||
|
/>
|
||||||
|
</form>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={() => { setEditedName(hostPlayer.name); setIsEditingName(true); }}
|
||||||
|
className="flex items-center gap-1.5 hover:bg-black/10 px-2 py-0.5 rounded-lg transition-colors cursor-pointer"
|
||||||
|
title="Click to edit name"
|
||||||
|
>
|
||||||
|
{hostPlayer.name}
|
||||||
|
<Pencil size={14} className="opacity-60" />
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
<span className="text-xs bg-black/20 px-2 py-0.5 rounded-full">HOST</span>
|
<span className="text-xs bg-black/20 px-2 py-0.5 rounded-full">HOST</span>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1732,10 +1732,21 @@ export const useGame = (defaultGameConfig?: GameConfig) => {
|
||||||
hostConnectionRef.current.send({ type: 'ADVANCE', payload: { action } });
|
hostConnectionRef.current.send({ type: 'ADVANCE', payload: { action } });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const setHostName = (name: string) => {
|
||||||
|
if (role !== 'HOST') return;
|
||||||
|
const trimmedName = name.trim() || 'Host';
|
||||||
|
setCurrentPlayerName(trimmedName);
|
||||||
|
const updatedPlayers = playersRef.current.map(p =>
|
||||||
|
p.id === 'host' ? { ...p, name: trimmedName } : p
|
||||||
|
);
|
||||||
|
playersRef.current = updatedPlayers;
|
||||||
|
setPlayers(updatedPlayers);
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
role, gameState, quiz, players, currentQuestionIndex, timeLeft, error, gamePin, hasAnswered, lastPointsEarned, lastAnswerCorrect, currentCorrectShape, selectedOption, currentPlayerScore, currentStreak, currentPlayerId, gameConfig,
|
role, gameState, quiz, players, currentQuestionIndex, timeLeft, error, gamePin, hasAnswered, lastPointsEarned, lastAnswerCorrect, currentCorrectShape, selectedOption, currentPlayerScore, currentStreak, currentPlayerId, gameConfig,
|
||||||
pendingQuizToSave, dismissSavePrompt, sourceQuizId, isReconnecting, currentPlayerName, presenterId, connectedPlayerIds,
|
pendingQuizToSave, dismissSavePrompt, sourceQuizId, isReconnecting, currentPlayerName, presenterId, connectedPlayerIds,
|
||||||
startQuizGen, startManualCreation, cancelCreation, finalizeManualQuiz, loadSavedQuiz, joinGame, startGame: startHostGame, handleAnswer, nextQuestion, showScoreboard,
|
startQuizGen, startManualCreation, cancelCreation, finalizeManualQuiz, loadSavedQuiz, joinGame, startGame: startHostGame, handleAnswer, nextQuestion, showScoreboard,
|
||||||
updateQuizFromEditor, startGameFromEditor, backFromEditor, endGame, attemptReconnect, goHomeFromDisconnected, resumeGame, setPresenterPlayer, sendAdvance, kickPlayer, leaveGame
|
updateQuizFromEditor, startGameFromEditor, backFromEditor, endGame, attemptReconnect, goHomeFromDisconnected, resumeGame, setPresenterPlayer, sendAdvance, kickPlayer, leaveGame, setHostName
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue