import { useState } from 'react' import { useParams, Link } from 'react-router-dom' import { useRun } from '../hooks/useRuns' import { useGameRoutes } from '../hooks/useGames' import { useCreateEncounter, useUpdateEncounter } from '../hooks/useEncounters' import { EncounterModal } from '../components' import type { Route, EncounterDetail, EncounterStatus } from '../types' type RouteStatus = 'caught' | 'fainted' | 'missed' | 'none' function getRouteStatus(encounter?: EncounterDetail): RouteStatus { if (!encounter) return 'none' return encounter.status } const statusIndicator: Record< RouteStatus, { dot: string; label: string; bg: string } > = { caught: { dot: 'bg-green-500', label: 'Caught', bg: 'bg-green-50 dark:bg-green-900/10', }, fainted: { dot: 'bg-red-500', label: 'Fainted', bg: 'bg-red-50 dark:bg-red-900/10', }, missed: { dot: 'bg-gray-400', label: 'Missed', bg: 'bg-gray-50 dark:bg-gray-900/10', }, none: { dot: 'bg-gray-300 dark:bg-gray-600', label: '', bg: '' }, } export function RunEncounters() { const { runId } = useParams<{ runId: string }>() const runIdNum = Number(runId) const { data: run, isLoading, error } = useRun(runIdNum) const { data: routes, isLoading: loadingRoutes } = useGameRoutes( run?.gameId ?? null, ) const createEncounter = useCreateEncounter(runIdNum) const updateEncounter = useUpdateEncounter(runIdNum) const [selectedRoute, setSelectedRoute] = useState(null) const [editingEncounter, setEditingEncounter] = useState(null) const [filter, setFilter] = useState<'all' | RouteStatus>('all') if (isLoading || loadingRoutes) { return (
) } if (error || !run) { return (
Failed to load run.
Back to runs
) } // Map routeId → encounter for quick lookup const encounterByRoute = new Map() for (const enc of run.encounters) { encounterByRoute.set(enc.routeId, enc) } const allRoutes = routes ?? [] const completedCount = allRoutes.filter((r) => encounterByRoute.has(r.id), ).length // Filter routes const filteredRoutes = filter === 'all' ? allRoutes : allRoutes.filter((r) => { const enc = encounterByRoute.get(r.id) return getRouteStatus(enc) === filter }) const handleRouteClick = (route: Route) => { const existing = encounterByRoute.get(route.id) if (existing) { setEditingEncounter(existing) } else { setEditingEncounter(null) } setSelectedRoute(route) } const handleCreate = (data: { routeId: number pokemonId: number nickname?: string status: EncounterStatus catchLevel?: number }) => { createEncounter.mutate(data, { onSuccess: () => { setSelectedRoute(null) setEditingEncounter(null) }, }) } const handleUpdate = (data: { id: number data: { nickname?: string status?: EncounterStatus faintLevel?: number deathCause?: string } }) => { updateEncounter.mutate(data, { onSuccess: () => { setSelectedRoute(null) setEditingEncounter(null) }, }) } return (
{/* Header */}
← {run.name}

Encounters

{run.game.name} · {completedCount} / {allRoutes.length} routes

{/* Progress bar */}
0 ? (completedCount / allRoutes.length) * 100 : 0}%`, }} />
{/* Filter tabs */}
{( [ { key: 'all', label: 'All' }, { key: 'none', label: 'Unvisited' }, { key: 'caught', label: 'Caught' }, { key: 'fainted', label: 'Fainted' }, { key: 'missed', label: 'Missed' }, ] as const ).map(({ key, label }) => ( ))}
{/* Route list */}
{filteredRoutes.length === 0 && (

No routes match this filter

)} {filteredRoutes.map((route) => { const encounter = encounterByRoute.get(route.id) const rs = getRouteStatus(encounter) const si = statusIndicator[rs] return ( ) })}
{/* Encounter Modal */} {selectedRoute && ( { setSelectedRoute(null) setEditingEncounter(null) }} isPending={createEncounter.isPending || updateEncounter.isPending} /> )}
) }