Add pokemon status management with death tracking

Implement status change workflow (alive → dead) with confirmation modal,
death cause recording, and visual status indicators on pokemon cards.
Includes backend migration for death_cause field and graveyard view
on the run dashboard.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 18:36:08 +01:00
parent 628c621fa9
commit a911259ef5
12 changed files with 462 additions and 53 deletions

View File

@@ -1,8 +1,10 @@
import { useState } from 'react'
import { useParams, Link } from 'react-router-dom'
import { useRun } from '../hooks/useRuns'
import { useGameRoutes } from '../hooks/useGames'
import { StatCard, PokemonCard, RuleBadges } from '../components'
import type { RunStatus } from '../types'
import { useUpdateEncounter } from '../hooks/useEncounters'
import { StatCard, PokemonCard, RuleBadges, StatusChangeModal } from '../components'
import type { RunStatus, EncounterDetail } from '../types'
const statusStyles: Record<RunStatus, string> = {
active: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300',
@@ -13,8 +15,12 @@ const statusStyles: Record<RunStatus, string> = {
export function RunDashboard() {
const { runId } = useParams<{ runId: string }>()
const { data: run, isLoading, error } = useRun(Number(runId))
const runIdNum = Number(runId)
const { data: run, isLoading, error } = useRun(runIdNum)
const { data: routes } = useGameRoutes(run?.gameId ?? null)
const updateEncounter = useUpdateEncounter(runIdNum)
const [selectedEncounter, setSelectedEncounter] =
useState<EncounterDetail | null>(null)
if (isLoading) {
return (
@@ -118,7 +124,11 @@ export function RunDashboard() {
) : (
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-3">
{alive.map((enc) => (
<PokemonCard key={enc.id} encounter={enc} />
<PokemonCard
key={enc.id}
encounter={enc}
onClick={() => setSelectedEncounter(enc)}
/>
))}
</div>
)}
@@ -132,7 +142,12 @@ export function RunDashboard() {
</h2>
<div className="grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-6 gap-3">
{dead.map((enc) => (
<PokemonCard key={enc.id} encounter={enc} showFaintLevel />
<PokemonCard
key={enc.id}
encounter={enc}
showFaintLevel
onClick={() => setSelectedEncounter(enc)}
/>
))}
</div>
</div>
@@ -147,6 +162,20 @@ export function RunDashboard() {
Log Encounter
</Link>
</div>
{/* Status Change Modal */}
{selectedEncounter && (
<StatusChangeModal
encounter={selectedEncounter}
onUpdate={(data) => {
updateEncounter.mutate(data, {
onSuccess: () => setSelectedEncounter(null),
})
}}
onClose={() => setSelectedEncounter(null)}
isPending={updateEncounter.isPending}
/>
)}
</div>
)
}