feat: Migración completa de SnatchGame a Nuxt 4
Some checks failed
build-and-deploy / filter (push) Successful in 3s
build-and-deploy / build (push) Failing after 6s
build-and-deploy / deploy (push) Has been skipped

- Creado nuevo proyecto Nuxt 4 con estructura app/
- Servidor Colyseus separado para evitar problemas con decoradores
- Migrado GameRoom y toda la lógica del juego
- Implementado cliente con composables useGameClient
- Panel de administración funcional
- Componentes Vue migrados (HomeScreen, GameScreen, PlayerCard, etc)
- Configuración para ejecutar ambos servidores (npm run dev:all)
This commit is contained in:
2025-08-05 16:05:51 -06:00
parent b83d450ac6
commit 62226ab5d4
36 changed files with 17126 additions and 2661 deletions

View File

@@ -0,0 +1,176 @@
import { ref, onUnmounted } from 'vue'
export interface AdminStats {
connectedPlayers: number
activeGames: number
currentRound: string
gameState: string
players: any[]
rooms: any[]
timestamp?: number
}
export const useAdminService = () => {
const stats = ref<AdminStats>({
connectedPlayers: 0,
activeGames: 0,
currentRound: 'waiting',
gameState: 'waiting_for_players',
players: [],
rooms: []
})
const isConnected = ref(false)
const error = ref<string | null>(null)
let eventSource: EventSource | null = null
const connect = () => {
if (eventSource) {
console.warn('Already connected to admin stream')
return
}
try {
eventSource = new EventSource('/api/admin/stream')
eventSource.onopen = () => {
console.log('Connected to admin stream')
isConnected.value = true
error.value = null
}
eventSource.onmessage = (event) => {
try {
const data = JSON.parse(event.data)
stats.value = data
} catch (err) {
console.error('Failed to parse admin stats:', err)
error.value = 'Failed to parse stats data'
}
}
eventSource.onerror = (err) => {
console.error('Admin stream error:', err)
isConnected.value = false
error.value = 'Connection lost'
// Attempt to reconnect after 5 seconds
setTimeout(() => {
if (!eventSource) return
console.log('Attempting to reconnect to admin stream...')
disconnect()
connect()
}, 5000)
}
} catch (err) {
console.error('Failed to connect to admin stream:', err)
error.value = 'Failed to connect'
isConnected.value = false
}
}
const disconnect = () => {
if (eventSource) {
eventSource.close()
eventSource = null
isConnected.value = false
console.log('Disconnected from admin stream')
}
}
const kickPlayer = async (playerId: string) => {
try {
const response = await $fetch('/api/admin/kick-player', {
method: 'POST',
body: { playerId }
})
return response
} catch (err) {
console.error('Failed to kick player:', err)
throw err
}
}
const pauseGame = async () => {
try {
const response = await $fetch('/api/admin/pause-game', {
method: 'POST'
})
return response
} catch (err) {
console.error('Failed to pause game:', err)
throw err
}
}
const resumeGame = async () => {
try {
const response = await $fetch('/api/admin/resume-game', {
method: 'POST'
})
return response
} catch (err) {
console.error('Failed to resume game:', err)
throw err
}
}
const kickAllPlayers = async () => {
try {
const response = await $fetch('/api/admin/kick-all-players', {
method: 'POST'
})
return response
} catch (err) {
console.error('Failed to kick all players:', err)
throw err
}
}
const advanceRound = async () => {
try {
const response = await $fetch('/api/admin/advance-round', {
method: 'POST'
})
return response
} catch (err) {
console.error('Failed to advance round:', err)
throw err
}
}
const previousRound = async () => {
try {
const response = await $fetch('/api/admin/previous-round', {
method: 'POST'
})
return response
} catch (err) {
console.error('Failed to go to previous round:', err)
throw err
}
}
// Clean up on unmount
onUnmounted(() => {
disconnect()
})
return {
// State
stats: readonly(stats),
isConnected: readonly(isConnected),
error: readonly(error),
// Methods
connect,
disconnect,
kickPlayer,
pauseGame,
resumeGame,
kickAllPlayers,
advanceRound,
previousRound
}
}