Separate PokeAPI ID from national dex for correct form identification

Pokemon forms (e.g., Alolan Rattata) had their PokeAPI ID (10091) stored as
national_dex, causing them to display incorrectly. This renames the unique
identifier to pokeapi_id and adds a real national_dex field shared between
forms and their base species, so Alolan Rattata correctly shows as #19.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-07 14:55:06 +01:00
parent cb027e5215
commit d168d99bba
46 changed files with 23459 additions and 22289 deletions

View File

@@ -62,7 +62,7 @@ export const updatePokemon = (id: number, data: UpdatePokemonInput) =>
export const deletePokemon = (id: number) =>
api.del(`/pokemon/${id}`)
export const bulkImportPokemon = (items: Array<{ nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) =>
export const bulkImportPokemon = (items: Array<{ pokeapiId: number; nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) =>
api.post<BulkImportResult>('/pokemon/bulk-import', items)
// Evolutions

View File

@@ -2,13 +2,13 @@ import { type FormEvent, useState } from 'react'
import type { BulkImportResult } from '../../types'
interface BulkImportModalProps {
onSubmit: (items: Array<{ nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) => Promise<BulkImportResult>
onSubmit: (items: Array<{ pokeapiId: number; nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) => Promise<BulkImportResult>
onClose: () => void
}
const EXAMPLE = `[
{ "nationalDex": 1, "name": "Bulbasaur", "types": ["Grass", "Poison"] },
{ "nationalDex": 4, "name": "Charmander", "types": ["Fire"] }
{ "pokeapiId": 1, "nationalDex": 1, "name": "Bulbasaur", "types": ["Grass", "Poison"] },
{ "pokeapiId": 4, "nationalDex": 4, "name": "Charmander", "types": ["Fire"] }
]`
export function BulkImportModal({ onSubmit, onClose }: BulkImportModalProps) {
@@ -33,7 +33,7 @@ export function BulkImportModal({ onSubmit, onClose }: BulkImportModalProps) {
setIsSubmitting(true)
try {
const res = await onSubmit(items as Array<{ nationalDex: number; name: string; types: string[] }>)
const res = await onSubmit(items as Array<{ pokeapiId: number; nationalDex: number; name: string; types: string[] }>)
setResult(res)
} catch (err) {
setError(err instanceof Error ? err.message : 'Import failed')

View File

@@ -10,6 +10,7 @@ interface PokemonFormModalProps {
}
export function PokemonFormModal({ pokemon, onSubmit, onClose, isSubmitting }: PokemonFormModalProps) {
const [pokeapiId, setPokeapiId] = useState(String(pokemon?.pokeapiId ?? ''))
const [nationalDex, setNationalDex] = useState(String(pokemon?.nationalDex ?? ''))
const [name, setName] = useState(pokemon?.name ?? '')
const [types, setTypes] = useState(pokemon?.types.join(', ') ?? '')
@@ -22,6 +23,7 @@ export function PokemonFormModal({ pokemon, onSubmit, onClose, isSubmitting }: P
.map((t) => t.trim())
.filter(Boolean)
onSubmit({
pokeapiId: Number(pokeapiId),
nationalDex: Number(nationalDex),
name,
types: typesList,
@@ -36,6 +38,17 @@ export function PokemonFormModal({ pokemon, onSubmit, onClose, isSubmitting }: P
onSubmit={handleSubmit}
isSubmitting={isSubmitting}
>
<div>
<label className="block text-sm font-medium mb-1">PokeAPI ID</label>
<input
type="number"
required
min={1}
value={pokeapiId}
onChange={(e) => setPokeapiId(e.target.value)}
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
/>
</div>
<div>
<label className="block text-sm font-medium mb-1">National Dex #</label>
<input

View File

@@ -160,7 +160,7 @@ export function useDeletePokemon() {
export function useBulkImportPokemon() {
const qc = useQueryClient()
return useMutation({
mutationFn: (items: Array<{ nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) =>
mutationFn: (items: Array<{ pokeapiId: number; nationalDex: number; name: string; types: string[]; spriteUrl?: string | null }>) =>
adminApi.bulkImportPokemon(items),
onSuccess: (result) => {
qc.invalidateQueries({ queryKey: ['pokemon'] })

View File

@@ -32,6 +32,7 @@ export interface RouteReorderItem {
}
export interface CreatePokemonInput {
pokeapiId: number
nationalDex: number
name: string
types: string[]
@@ -39,6 +40,7 @@ export interface CreatePokemonInput {
}
export interface UpdatePokemonInput {
pokeapiId?: number
nationalDex?: number
name?: string
types?: string[]

View File

@@ -24,6 +24,7 @@ export interface RouteWithChildren extends Route {
export interface Pokemon {
id: number
pokeapiId: number
nationalDex: number
name: string
types: string[]