+
{
const generateGamePin = () => Math.floor(Math.random() * 900000) + 100000 + "";
+ const generateRandomName = (): string => {
+ return uniqueNamesGenerator({
+ dictionaries: [adjectives, animals],
+ separator: ' ',
+ style: 'capital',
+ length: 2,
+ });
+ };
+
const syncGameState = useCallback(async () => {
if (!gamePinRef.current || !hostSecretRef.current) return;
if (gameStateRef.current === 'LANDING' || gameStateRef.current === 'EDITING' || gameStateRef.current === 'CREATING' || gameStateRef.current === 'GENERATING') return;
@@ -510,13 +520,23 @@ export const useGame = () => {
allPlayers: playersRef.current.map(p => ({ id: p.id, name: p.name, lastAnswerCorrect: p.lastAnswerCorrect }))
});
+ let assignedName = payload.name;
+ if (!reconnectedPlayer && gameConfigRef.current.randomNamesEnabled) {
+ assignedName = generateRandomName();
+ }
+
+ let updatedPlayers = playersRef.current;
+ let newPlayer: Player | null = null;
+
if (reconnectedPlayer) {
- setPlayers(prev => prev.map(p => p.id === reconnectedPlayer.id ? { ...p, id: conn.peer } : p));
+ updatedPlayers = playersRef.current.map(p => p.id === reconnectedPlayer.id ? { ...p, id: conn.peer } : p);
+ setPlayers(updatedPlayers);
+ assignedName = reconnectedPlayer.name;
} else if (!playersRef.current.find(p => p.id === conn.peer)) {
const colorIndex = playersRef.current.length % PLAYER_COLORS.length;
- const newPlayer: Player = {
+ newPlayer = {
id: conn.peer,
- name: payload.name,
+ name: assignedName,
score: 0,
previousScore: 0,
streak: 0,
@@ -527,7 +547,8 @@ export const useGame = () => {
avatarSeed: Math.random(),
color: PLAYER_COLORS[colorIndex]
};
- setPlayers(prev => [...prev, newPlayer]);
+ updatedPlayers = [...playersRef.current, newPlayer];
+ setPlayers(updatedPlayers);
}
const currentState = gameStateRef.current;
@@ -538,7 +559,7 @@ export const useGame = () => {
const welcomePayload: any = {
playerId: conn.peer,
quizTitle: currentQuiz?.title || 'Kaboot',
- players: playersRef.current,
+ players: updatedPlayers,
gameState: currentState,
currentQuestionIndex: currentIndex,
totalQuestions: currentQuiz?.questions.length || 0,
@@ -548,6 +569,7 @@ export const useGame = () => {
hasAnswered: false,
lastAnswerCorrect: null,
selectedShape: null,
+ assignedName,
};
if (currentQuestion) {
@@ -915,6 +937,13 @@ export const useGame = () => {
if (payload.players) {
setPlayers(payload.players);
}
+ if (payload.assignedName) {
+ setCurrentPlayerName(payload.assignedName);
+ const session = getStoredSession();
+ if (session) {
+ storeSession({ ...session, playerName: payload.assignedName });
+ }
+ }
if (payload.selectedShape && payload.options) {
const matchedOption = payload.options.find(opt => opt.shape === payload.selectedShape);
if (matchedOption) {
diff --git a/index.css b/index.css
index e8b64b7..1d21d0e 100644
--- a/index.css
+++ b/index.css
@@ -1,16 +1,11 @@
-html, body, #root {
- height: 100%;
- min-height: 100dvh;
-}
-
.h-screen {
- height: 100dvh;
+ height: 100dvh !important;
}
.min-h-screen {
- min-height: 100dvh;
+ min-height: 100dvh !important;
}
.max-h-screen {
- max-height: 100dvh;
+ max-height: 100dvh !important;
}
diff --git a/index.html b/index.html
index 46b0b5c..925b482 100644
--- a/index.html
+++ b/index.html
@@ -33,8 +33,19 @@
font-family: 'Montserrat', sans-serif;
background: linear-gradient(180deg, var(--theme-primary) 0%, var(--theme-primary-darker) 100%);
color: white;
- overflow-x: hidden;
- min-height: 100dvh;
+ overflow: hidden;
+ height: 100dvh;
+ margin: 0;
+ padding: 0;
+ }
+
+ html {
+ height: 100dvh;
+ overflow: hidden;
+ }
+
+ #root {
+ height: 100%;
}
h1, h2, h3, h4, h5, h6, .font-display {
diff --git a/package-lock.json b/package-lock.json
index 7323a05..6c215ed 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -22,6 +22,7 @@
"react-hot-toast": "^2.6.0",
"react-oidc-context": "^3.2.0",
"recharts": "^3.6.0",
+ "unique-names-generator": "^4.7.1",
"uuid": "^13.0.0"
},
"devDependencies": {
@@ -4160,6 +4161,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/unique-names-generator": {
+ "version": "4.7.1",
+ "resolved": "https://registry.npmjs.org/unique-names-generator/-/unique-names-generator-4.7.1.tgz",
+ "integrity": "sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz",
diff --git a/package.json b/package.json
index 72eb488..1077f01 100644
--- a/package.json
+++ b/package.json
@@ -26,6 +26,7 @@
"react-hot-toast": "^2.6.0",
"react-oidc-context": "^3.2.0",
"recharts": "^3.6.0",
+ "unique-names-generator": "^4.7.1",
"uuid": "^13.0.0"
},
"devDependencies": {
diff --git a/server/src/routes/games.ts b/server/src/routes/games.ts
index c083f1e..0d6aa29 100644
--- a/server/src/routes/games.ts
+++ b/server/src/routes/games.ts
@@ -74,6 +74,7 @@ router.get('/:pin', (req: Request, res: Response) => {
return;
}
+ const gameConfig = JSON.parse(session.game_config);
res.json({
pin: session.pin,
hostPeerId: session.host_peer_id,
@@ -81,6 +82,7 @@ router.get('/:pin', (req: Request, res: Response) => {
currentQuestionIndex: session.current_question_index,
quizTitle: JSON.parse(session.quiz_data).title,
playerCount: JSON.parse(session.players_data).length,
+ randomNamesEnabled: gameConfig.randomNamesEnabled || false,
});
} catch (err) {
console.error('Error getting game session:', err);
diff --git a/types.ts b/types.ts
index 8e375f3..6b85014 100644
--- a/types.ts
+++ b/types.ts
@@ -62,6 +62,7 @@ export interface GameConfig {
shuffleQuestions: boolean;
shuffleAnswers: boolean;
hostParticipates: boolean;
+ randomNamesEnabled: boolean;
streakBonusEnabled: boolean;
streakThreshold: number;
streakMultiplier: number;
@@ -77,6 +78,7 @@ export const DEFAULT_GAME_CONFIG: GameConfig = {
shuffleQuestions: false,
shuffleAnswers: false,
hostParticipates: true,
+ randomNamesEnabled: false,
streakBonusEnabled: false,
streakThreshold: 3,
streakMultiplier: 1.1,
@@ -170,6 +172,7 @@ export type NetworkMessage =
options?: AnswerOption[];
correctShape?: string;
timeLeft?: number;
+ assignedName?: string;
} }
| { type: 'PLAYER_JOINED'; payload: { player: Player } }
| { type: 'GAME_START'; payload: {} }