🏓 Initial ServeSync demo build
- FastAPI backend with PostgreSQL + Redis - 4 core features: Registration, Courts, Matchmaking, Tournament - Double elimination tournament with bracket visualization - ELO-based matchmaking (Stage 1 Open, Stage 2 Skill-Based) - Real-time WebSocket updates - TV Screen display for courts - Vue 3 + Tailwind CSS frontend - Seed data: 12 players, 4 courts, active matches, tournament in progress - Docker compose stack with Nginx reverse proxy
This commit is contained in:
125
frontend/src/stores/app.js
Normal file
125
frontend/src/stores/app.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import axios from 'axios'
|
||||
|
||||
const api = axios.create({ baseURL: '/api' })
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
const currentPlayer = ref(null)
|
||||
const players = ref([])
|
||||
const courts = ref([])
|
||||
const matches = ref([])
|
||||
const activeTournament = ref(null)
|
||||
const loading = ref(false)
|
||||
|
||||
// Set demo player (no auth needed)
|
||||
const setCurrentPlayer = (player) => {
|
||||
currentPlayer.value = player
|
||||
localStorage.setItem('currentPlayerId', player.id)
|
||||
}
|
||||
|
||||
const loadPlayers = async () => {
|
||||
const res = await api.get('/players/')
|
||||
players.value = res.data
|
||||
// Auto-set first player as current if not set
|
||||
if (!currentPlayer.value && players.value.length > 0) {
|
||||
const savedId = localStorage.getItem('currentPlayerId')
|
||||
const saved = savedId ? players.value.find(p => p.id == savedId) : null
|
||||
currentPlayer.value = saved || players.value[0]
|
||||
}
|
||||
return players.value
|
||||
}
|
||||
|
||||
const loadCourts = async () => {
|
||||
const res = await api.get('/courts/')
|
||||
courts.value = res.data
|
||||
return courts.value
|
||||
}
|
||||
|
||||
const loadMatches = async () => {
|
||||
const res = await api.get('/matches/')
|
||||
matches.value = res.data
|
||||
return matches.value
|
||||
}
|
||||
|
||||
const loadLobby = async () => {
|
||||
const res = await api.get('/matches/lobby')
|
||||
return res.data
|
||||
}
|
||||
|
||||
const loadActiveMatches = async () => {
|
||||
const res = await api.get('/matches/active')
|
||||
return res.data
|
||||
}
|
||||
|
||||
const createMatch = async (data) => {
|
||||
const res = await api.post('/matches/', data)
|
||||
return res.data
|
||||
}
|
||||
|
||||
const joinMatch = async (matchId, playerId, team) => {
|
||||
const res = await api.post(`/matches/${matchId}/join`, { player_id: playerId, team })
|
||||
return res.data
|
||||
}
|
||||
|
||||
const startMatch = async (matchId) => {
|
||||
const res = await api.post(`/matches/${matchId}/start`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
const updateScore = async (matchId, team1Score, team2Score) => {
|
||||
const res = await api.post(`/matches/${matchId}/score`, { team1_score: team1Score, team2_score: team2Score })
|
||||
return res.data
|
||||
}
|
||||
|
||||
const completeMatch = async (matchId, team1Score, team2Score) => {
|
||||
const res = await api.post(`/matches/${matchId}/complete`, { team1_score: team1Score, team2_score: team2Score })
|
||||
return res.data
|
||||
}
|
||||
|
||||
const bookCourt = async (data) => {
|
||||
const res = await api.post('/courts/book', data)
|
||||
return res.data
|
||||
}
|
||||
|
||||
const loadTournaments = async () => {
|
||||
const res = await api.get('/tournaments/')
|
||||
return res.data
|
||||
}
|
||||
|
||||
const loadTournament = async (id) => {
|
||||
const res = await api.get(`/tournaments/${id}`)
|
||||
activeTournament.value = res.data
|
||||
return res.data
|
||||
}
|
||||
|
||||
const getLeaderboard = async (limit = 10) => {
|
||||
const res = await api.get(`/players/leaderboard?limit=${limit}`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
const getCourtDisplay = async (courtId) => {
|
||||
const res = await api.get(`/screen/court/${courtId}`)
|
||||
return res.data
|
||||
}
|
||||
|
||||
const getOverview = async () => {
|
||||
const res = await api.get('/screen/overview')
|
||||
return res.data
|
||||
}
|
||||
|
||||
const completeTournamentMatch = async (tournamentId, matchId, s1, s2) => {
|
||||
const res = await api.post(`/tournaments/${tournamentId}/matches/${matchId}/score`, {
|
||||
team1_score: s1, team2_score: s2
|
||||
})
|
||||
return res.data
|
||||
}
|
||||
|
||||
return {
|
||||
currentPlayer, players, courts, matches, activeTournament, loading,
|
||||
setCurrentPlayer, loadPlayers, loadCourts, loadMatches,
|
||||
loadLobby, loadActiveMatches, createMatch, joinMatch, startMatch,
|
||||
updateScore, completeMatch, bookCourt, loadTournaments, loadTournament,
|
||||
getLeaderboard, getCourtDisplay, getOverview, completeTournamentMatch,
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user