import { useState, useEffect, useCallback } from 'react' import { useNavigate, useLocation } from 'react-router-dom' import { useAuth } from '../hooks/useAuth' import { useGameWebSocket } from '../hooks/useGameWebSocket' import api from '../services/api' import { useTranslation } from 'react-i18next' import LanguageSelector from './LanguageSelector' import { useOptionalGame } from '../contexts/GameContext' import { getTranslatedText } from '../utils/i18nUtils' import './Game.css' import { GameTooltip } from './common/GameTooltip' // Import the new specific header styles import './GameHeader.css' interface CombatInfo { enemyName: string yourTurn: boolean } interface GameHeaderProps { className?: string locationName?: string combatInfo?: CombatInfo | null dangerLevel?: number } export default function GameHeader({ className = '' }: GameHeaderProps) { const navigate = useNavigate() const location = useLocation() const { currentCharacter, logout } = useAuth() const { t } = useTranslation() const [playerCount, setPlayerCount] = useState(0) const [isFullscreen, setIsFullscreen] = useState(!!document.fullscreenElement) // Fullscreen toggle const toggleFullscreen = useCallback(() => { if (!document.fullscreenElement) { document.documentElement.requestFullscreen().catch((err) => { console.error('Failed to enter fullscreen:', err) }) } else { document.exitFullscreen().catch((err) => { console.error('Failed to exit fullscreen:', err) }) } }, []) useEffect(() => { const handleFullscreenChange = () => { setIsFullscreen(!!document.fullscreenElement) } document.addEventListener('fullscreenchange', handleFullscreenChange) return () => document.removeEventListener('fullscreenchange', handleFullscreenChange) }, []) // Get game state from context (undefined when outside GameProvider) const gameContext = useOptionalGame() const gameState = gameContext?.state // Extract location and combat info from game state const locationName = gameState?.location?.name ? getTranslatedText(gameState.location.name) : undefined const dangerLevel = gameState?.location?.danger_level const combatInfo = gameState?.combatState ? { enemyName: getTranslatedText(gameState.enemyName) || 'Enemy', yourTurn: gameState.combatState.yourTurn || false } : null // Fetch initial player count useEffect(() => { const fetchPlayerCount = async () => { try { const response = await api.get('/api/statistics/online-players') if (response.data && typeof response.data.count === 'number') { setPlayerCount(response.data.count) } } catch (error) { console.error('Failed to fetch player count:', error) } } fetchPlayerCount() }, []) // Connect to WebSocket for player count updates // We use a separate connection here to ensure the header always has live data // regardless of which page is active (Game, Leaderboards, Profile) const token = localStorage.getItem('token') useGameWebSocket({ token, enabled: !!token, onMessage: (message) => { if (message.type === 'player_count_update' && message.data?.count !== undefined) { //console.log('🔢 GameHeader received count update:', message.data.count) setPlayerCount(message.data.count) } } }) const isActive = (path: string) => { return location.pathname === path || location.pathname.startsWith(path) } const isOnOwnProfile = location.pathname === `/profile/${currentCharacter?.id}` // Helper for danger badge class const getDangerClass = (level: number | undefined) => { if (level === undefined || level === 0) return 'danger-safe' return `danger-${Math.min(level, 5)}` } return (
{/* Left: Logo and Version */}

Echoes of the Ash

v0.9
{/* Center: Location/Combat Title */}
{combatInfo ? (
⚔️ {combatInfo.enemyName} {combatInfo.yourTurn ? t('combat.yourTurn') : t('combat.enemyTurn')}
) : locationName ? (
{locationName} {dangerLevel !== undefined && ( {dangerLevel === 0 ? t('danger.safe') : `⚠️ ${dangerLevel}`} )}
) : null}
{/* Right: Navigation + User Info */}
{playerCount}
) }