Add pre-commit hooks for linting and formatting
All checks were successful
CI / backend-lint (push) Successful in 9s
CI / frontend-lint (push) Successful in 33s

Set up pre-commit framework with ruff (backend) and ESLint/Prettier/tsc
(frontend) hooks to catch issues locally before CI. Auto-format all
frontend files with Prettier to comply with the new check.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 16:41:24 +01:00
parent b05a75f7f2
commit 2963f16aa4
67 changed files with 1905 additions and 792 deletions

View File

@@ -36,15 +36,17 @@ export const createGame = (data: CreateGameInput) =>
export const updateGame = (id: number, data: UpdateGameInput) =>
api.put<Game>(`/games/${id}`, data)
export const deleteGame = (id: number) =>
api.del(`/games/${id}`)
export const deleteGame = (id: number) => api.del(`/games/${id}`)
// Routes
export const createRoute = (gameId: number, data: CreateRouteInput) =>
api.post<Route>(`/games/${gameId}/routes`, data)
export const updateRoute = (gameId: number, routeId: number, data: UpdateRouteInput) =>
api.put<Route>(`/games/${gameId}/routes/${routeId}`, data)
export const updateRoute = (
gameId: number,
routeId: number,
data: UpdateRouteInput
) => api.put<Route>(`/games/${gameId}/routes/${routeId}`, data)
export const deleteRoute = (gameId: number, routeId: number) =>
api.del(`/games/${gameId}/routes/${routeId}`)
@@ -53,7 +55,12 @@ export const reorderRoutes = (gameId: number, routes: RouteReorderItem[]) =>
api.put<Route[]>(`/games/${gameId}/routes/reorder`, { routes })
// Pokemon
export const listPokemon = (search?: string, limit = 50, offset = 0, type?: string) => {
export const listPokemon = (
search?: string,
limit = 50,
offset = 0,
type?: string
) => {
const params = new URLSearchParams()
if (search) params.set('search', search)
if (type) params.set('type', type)
@@ -68,11 +75,17 @@ export const createPokemon = (data: CreatePokemonInput) =>
export const updatePokemon = (id: number, data: UpdatePokemonInput) =>
api.put<Pokemon>(`/pokemon/${id}`, data)
export const deletePokemon = (id: number) =>
api.del(`/pokemon/${id}`)
export const deletePokemon = (id: number) => api.del(`/pokemon/${id}`)
export const bulkImportPokemon = (items: Array<{ pokeapiId: number; nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) =>
api.post<BulkImportResult>('/pokemon/bulk-import', items)
export const bulkImportPokemon = (
items: Array<{
pokeapiId: number
nationalDex: number
name: string
types: string[]
spriteUrl?: string | null
}>
) => api.post<BulkImportResult>('/pokemon/bulk-import', items)
export const bulkImportEvolutions = (items: unknown[]) =>
api.post<BulkImportResult>('/evolutions/bulk-import', items)
@@ -84,7 +97,12 @@ export const bulkImportBosses = (gameId: number, items: unknown[]) =>
api.post<BulkImportResult>(`/games/${gameId}/bosses/bulk-import`, items)
// Evolutions
export const listEvolutions = (search?: string, limit = 50, offset = 0, trigger?: string) => {
export const listEvolutions = (
search?: string,
limit = 50,
offset = 0,
trigger?: string
) => {
const params = new URLSearchParams()
if (search) params.set('search', search)
if (trigger) params.set('trigger', trigger)
@@ -99,8 +117,7 @@ export const createEvolution = (data: CreateEvolutionInput) =>
export const updateEvolution = (id: number, data: UpdateEvolutionInput) =>
api.put<EvolutionAdmin>(`/evolutions/${id}`, data)
export const deleteEvolution = (id: number) =>
api.del(`/evolutions/${id}`)
export const deleteEvolution = (id: number) => api.del(`/evolutions/${id}`)
// Export
export const exportGames = () =>
@@ -119,11 +136,20 @@ export const exportEvolutions = () =>
api.get<Record<string, unknown>[]>('/export/evolutions')
// Route Encounters
export const addRouteEncounter = (routeId: number, data: CreateRouteEncounterInput) =>
api.post<RouteEncounterDetail>(`/routes/${routeId}/pokemon`, data)
export const addRouteEncounter = (
routeId: number,
data: CreateRouteEncounterInput
) => api.post<RouteEncounterDetail>(`/routes/${routeId}/pokemon`, data)
export const updateRouteEncounter = (routeId: number, encounterId: number, data: UpdateRouteEncounterInput) =>
api.put<RouteEncounterDetail>(`/routes/${routeId}/pokemon/${encounterId}`, data)
export const updateRouteEncounter = (
routeId: number,
encounterId: number,
data: UpdateRouteEncounterInput
) =>
api.put<RouteEncounterDetail>(
`/routes/${routeId}/pokemon/${encounterId}`,
data
)
export const removeRouteEncounter = (routeId: number, encounterId: number) =>
api.del(`/routes/${routeId}/pokemon/${encounterId}`)
@@ -132,8 +158,11 @@ export const removeRouteEncounter = (routeId: number, encounterId: number) =>
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 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}`)
@@ -141,15 +170,17 @@ export const deleteBossBattle = (gameId: number, bossId: number) =>
export const reorderBosses = (gameId: number, bosses: BossReorderItem[]) =>
api.put<BossBattle[]>(`/games/${gameId}/bosses/reorder`, { bosses })
export const setBossTeam = (gameId: number, bossId: number, team: BossPokemonInput[]) =>
api.put<BossBattle>(`/games/${gameId}/bosses/${bossId}/pokemon`, team)
export const setBossTeam = (
gameId: number,
bossId: number,
team: BossPokemonInput[]
) => api.put<BossBattle>(`/games/${gameId}/bosses/${bossId}/pokemon`, team)
// Genlockes
export const updateGenlocke = (id: number, data: UpdateGenlockeInput) =>
api.patch<Genlocke>(`/genlockes/${id}`, data)
export const deleteGenlocke = (id: number) =>
api.del(`/genlockes/${id}`)
export const deleteGenlocke = (id: number) => api.del(`/genlockes/${id}`)
export const addGenlockeLeg = (genlockeId: number, data: AddGenlockeLegInput) =>
api.post<Genlocke>(`/genlockes/${genlockeId}/legs`, data)

View File

@@ -1,7 +1,14 @@
import { api } from './client'
import type { BossBattle, BossResult, CreateBossResultInput } from '../types/game'
import type {
BossBattle,
BossResult,
CreateBossResultInput,
} from '../types/game'
export function getGameBosses(gameId: number, all?: boolean): Promise<BossBattle[]> {
export function getGameBosses(
gameId: number,
all?: boolean
): Promise<BossBattle[]> {
const params = all ? '?all=true' : ''
return api.get(`/games/${gameId}/bosses${params}`)
}
@@ -10,10 +17,16 @@ export function getBossResults(runId: number): Promise<BossResult[]> {
return api.get(`/runs/${runId}/boss-results`)
}
export function createBossResult(runId: number, data: CreateBossResultInput): Promise<BossResult> {
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> {
export function deleteBossResult(
runId: number,
resultId: number
): Promise<void> {
return api.del(`/runs/${runId}/boss-results/${resultId}`)
}

View File

@@ -10,10 +10,7 @@ export class ApiError extends Error {
}
}
async function request<T>(
path: string,
options?: RequestInit,
): Promise<T> {
async function request<T>(path: string, options?: RequestInit): Promise<T> {
const res = await fetch(`${API_BASE}/api/v1${path}`, {
...options,
headers: {
@@ -52,6 +49,5 @@ export const api = {
body: JSON.stringify(body),
}),
del: <T = void>(path: string) =>
request<T>(path, { method: 'DELETE' }),
del: <T = void>(path: string) => request<T>(path, { method: 'DELETE' }),
}

View File

@@ -9,14 +9,14 @@ import type {
export function createEncounter(
runId: number,
data: CreateEncounterInput,
data: CreateEncounterInput
): Promise<EncounterDetail> {
return api.post(`/runs/${runId}/encounters`, data)
}
export function updateEncounter(
id: number,
data: UpdateEncounterInput,
data: UpdateEncounterInput
): Promise<EncounterDetail> {
return api.patch(`/encounters/${id}`, data)
}
@@ -25,7 +25,10 @@ export function deleteEncounter(id: number): Promise<void> {
return api.del(`/encounters/${id}`)
}
export function fetchEvolutions(pokemonId: number, region?: string): Promise<Evolution[]> {
export function fetchEvolutions(
pokemonId: number,
region?: string
): Promise<Evolution[]> {
const params = region ? `?region=${encodeURIComponent(region)}` : ''
return api.get(`/pokemon/${pokemonId}/evolutions${params}`)
}
@@ -34,6 +37,8 @@ export function fetchForms(pokemonId: number): Promise<Pokemon[]> {
return api.get(`/pokemon/${pokemonId}/forms`)
}
export function bulkRandomizeEncounters(runId: number): Promise<{ created: unknown[]; skippedRoutes: number }> {
export function bulkRandomizeEncounters(
runId: number
): Promise<{ created: unknown[]; skippedRoutes: number }> {
return api.post(`/runs/${runId}/encounters/bulk-randomize`, {})
}

View File

@@ -19,7 +19,10 @@ export function getGameRoutes(gameId: number): Promise<Route[]> {
return api.get(`/games/${gameId}/routes?flat=true`)
}
export function getRoutePokemon(routeId: number, gameId?: number): Promise<RouteEncounterDetail[]> {
export function getRoutePokemon(
routeId: number,
gameId?: number
): Promise<RouteEncounterDetail[]> {
const params = gameId != null ? `?game_id=${gameId}` : ''
return api.get(`/routes/${routeId}/pokemon${params}`)
}

View File

@@ -1,5 +1,15 @@
import { api } from './client'
import type { Genlocke, GenlockeListItem, GenlockeDetail, GenlockeGraveyard, GenlockeLineage, CreateGenlockeInput, Region, SurvivorEncounter, AdvanceLegInput } from '../types/game'
import type {
Genlocke,
GenlockeListItem,
GenlockeDetail,
GenlockeGraveyard,
GenlockeLineage,
CreateGenlockeInput,
Region,
SurvivorEncounter,
AdvanceLegInput,
} from '../types/game'
export function getGenlockes(): Promise<GenlockeListItem[]> {
return api.get('/genlockes')
@@ -25,10 +35,20 @@ export function getGenlockeLineages(id: number): Promise<GenlockeLineage> {
return api.get(`/genlockes/${id}/lineages`)
}
export function getLegSurvivors(genlockeId: number, legOrder: number): Promise<SurvivorEncounter[]> {
export function getLegSurvivors(
genlockeId: number,
legOrder: number
): Promise<SurvivorEncounter[]> {
return api.get(`/genlockes/${genlockeId}/legs/${legOrder}/survivors`)
}
export function advanceLeg(genlockeId: number, legOrder: number, data?: AdvanceLegInput): Promise<Genlocke> {
return api.post(`/genlockes/${genlockeId}/legs/${legOrder}/advance`, data ?? {})
export function advanceLeg(
genlockeId: number,
legOrder: number,
data?: AdvanceLegInput
): Promise<Genlocke> {
return api.post(
`/genlockes/${genlockeId}/legs/${legOrder}/advance`,
data ?? {}
)
}

View File

@@ -10,10 +10,14 @@ export function fetchPokemonFamilies(): Promise<{ families: number[][] }> {
return api.get('/pokemon/families')
}
export function fetchPokemonEncounterLocations(pokemonId: number): Promise<PokemonEncounterLocation[]> {
export function fetchPokemonEncounterLocations(
pokemonId: number
): Promise<PokemonEncounterLocation[]> {
return api.get(`/pokemon/${pokemonId}/encounter-locations`)
}
export function fetchPokemonEvolutionChain(pokemonId: number): Promise<EvolutionAdmin[]> {
export function fetchPokemonEvolutionChain(
pokemonId: number
): Promise<EvolutionAdmin[]> {
return api.get(`/pokemon/${pokemonId}/evolution-chain`)
}

View File

@@ -20,7 +20,7 @@ export function createRun(data: CreateRunInput): Promise<NuzlockeRun> {
export function updateRun(
id: number,
data: UpdateRunInput,
data: UpdateRunInput
): Promise<NuzlockeRun> {
return api.patch(`/runs/${id}`, data)
}
@@ -33,7 +33,11 @@ export function getNamingCategories(): Promise<string[]> {
return api.get('/runs/naming-categories')
}
export function getNameSuggestions(runId: number, count = 10, pokemonId?: number): Promise<string[]> {
export function getNameSuggestions(
runId: number,
count = 10,
pokemonId?: number
): Promise<string[]> {
let url = `/runs/${runId}/name-suggestions?count=${count}`
if (pokemonId != null) {
url += `&pokemon_id=${pokemonId}`