Add boss battles, level caps, and badge tracking

Introduces full boss battle system: data models (BossBattle, BossPokemon,
BossResult), API endpoints for CRUD and per-run defeat tracking, and frontend
UI including a sticky level cap bar with badge display on the run page,
interleaved boss battle cards in the encounter list, and an admin panel
section for managing boss battles and their pokemon teams.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-08 11:16:13 +01:00
parent 3b87397432
commit 190b08eb26
23 changed files with 1614 additions and 61 deletions

View File

@@ -4,6 +4,7 @@ import type {
Route,
Pokemon,
RouteEncounterDetail,
BossBattle,
CreateGameInput,
UpdateGameInput,
CreateRouteInput,
@@ -19,6 +20,9 @@ import type {
PaginatedEvolutions,
CreateEvolutionInput,
UpdateEvolutionInput,
CreateBossBattleInput,
UpdateBossBattleInput,
BossPokemonInput,
} from '../types'
// Games
@@ -105,3 +109,16 @@ export const updateRouteEncounter = (routeId: number, encounterId: number, data:
export const removeRouteEncounter = (routeId: number, encounterId: number) =>
api.del(`/routes/${routeId}/pokemon/${encounterId}`)
// Boss Battles
export const createBossBattle = (gameId: number, data: CreateBossBattleInput) =>
api.post<BossBattle>(`/games/${gameId}/bosses`, data)
export const updateBossBattle = (gameId: number, bossId: number, data: UpdateBossBattleInput) =>
api.put<BossBattle>(`/games/${gameId}/bosses/${bossId}`, data)
export const deleteBossBattle = (gameId: number, bossId: number) =>
api.del(`/games/${gameId}/bosses/${bossId}`)
export const setBossTeam = (gameId: number, bossId: number, team: BossPokemonInput[]) =>
api.put<BossBattle>(`/games/${gameId}/bosses/${bossId}/pokemon`, team)

View File

@@ -0,0 +1,18 @@
import { api } from './client'
import type { BossBattle, BossResult, CreateBossResultInput } from '../types/game'
export function getGameBosses(gameId: number): Promise<BossBattle[]> {
return api.get(`/games/${gameId}/bosses`)
}
export function getBossResults(runId: number): Promise<BossResult[]> {
return api.get(`/runs/${runId}/boss-results`)
}
export function createBossResult(runId: number, data: CreateBossResultInput): Promise<BossResult> {
return api.post(`/runs/${runId}/boss-results`, data)
}
export function deleteBossResult(runId: number, resultId: number): Promise<void> {
return api.del(`/runs/${runId}/boss-results/${resultId}`)
}