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:
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -121,7 +121,12 @@ export function RunEncounters() {
|
||||
|
||||
const handleUpdate = (data: {
|
||||
id: number
|
||||
data: { nickname?: string; status?: EncounterStatus; faintLevel?: number }
|
||||
data: {
|
||||
nickname?: string
|
||||
status?: EncounterStatus
|
||||
faintLevel?: number
|
||||
deathCause?: string
|
||||
}
|
||||
}) => {
|
||||
updateEncounter.mutate(data, {
|
||||
onSuccess: () => {
|
||||
@@ -225,7 +230,9 @@ export function RunEncounters() {
|
||||
{encounter.nickname ?? encounter.pokemon.name}
|
||||
{encounter.status === 'caught' &&
|
||||
encounter.faintLevel !== null &&
|
||||
' (dead)'}
|
||||
(encounter.deathCause
|
||||
? ` — ${encounter.deathCause}`
|
||||
: ' (dead)')}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user