Improve admin panel UX with toasts, evolution CRUD, sorting, drag-and-drop, and responsive layout
Add sonner toast notifications to all mutations, evolution management backend
(CRUD endpoints with search/pagination) and frontend (form modal with pokemon
selector, paginated list page), sortable AdminTable columns (Region/Gen/Year
on Games), drag-and-drop route reordering via @dnd-kit, skeleton loading states,
card-styled table wrappers, and responsive mobile nav in AdminLayout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:09:27 +01:00
|
|
|
import { type FormEvent, useState } from 'react'
|
|
|
|
|
import { FormModal } from './FormModal'
|
|
|
|
|
import { PokemonSelector } from './PokemonSelector'
|
|
|
|
|
import type { EvolutionAdmin, CreateEvolutionInput, UpdateEvolutionInput } from '../../types'
|
|
|
|
|
|
|
|
|
|
interface EvolutionFormModalProps {
|
|
|
|
|
evolution?: EvolutionAdmin
|
|
|
|
|
onSubmit: (data: CreateEvolutionInput | UpdateEvolutionInput) => void
|
|
|
|
|
onClose: () => void
|
|
|
|
|
isSubmitting?: boolean
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const TRIGGER_OPTIONS = ['level-up', 'trade', 'use-item', 'shed', 'other']
|
|
|
|
|
|
|
|
|
|
export function EvolutionFormModal({
|
|
|
|
|
evolution,
|
|
|
|
|
onSubmit,
|
|
|
|
|
onClose,
|
|
|
|
|
isSubmitting,
|
|
|
|
|
}: EvolutionFormModalProps) {
|
|
|
|
|
const [fromPokemonId, setFromPokemonId] = useState<number | null>(
|
|
|
|
|
evolution?.fromPokemonId ?? null,
|
|
|
|
|
)
|
|
|
|
|
const [toPokemonId, setToPokemonId] = useState<number | null>(
|
|
|
|
|
evolution?.toPokemonId ?? null,
|
|
|
|
|
)
|
|
|
|
|
const [trigger, setTrigger] = useState(evolution?.trigger ?? 'level-up')
|
|
|
|
|
const [minLevel, setMinLevel] = useState(String(evolution?.minLevel ?? ''))
|
|
|
|
|
const [item, setItem] = useState(evolution?.item ?? '')
|
|
|
|
|
const [heldItem, setHeldItem] = useState(evolution?.heldItem ?? '')
|
|
|
|
|
const [condition, setCondition] = useState(evolution?.condition ?? '')
|
2026-02-07 20:05:07 +01:00
|
|
|
const [region, setRegion] = useState(evolution?.region ?? '')
|
Improve admin panel UX with toasts, evolution CRUD, sorting, drag-and-drop, and responsive layout
Add sonner toast notifications to all mutations, evolution management backend
(CRUD endpoints with search/pagination) and frontend (form modal with pokemon
selector, paginated list page), sortable AdminTable columns (Region/Gen/Year
on Games), drag-and-drop route reordering via @dnd-kit, skeleton loading states,
card-styled table wrappers, and responsive mobile nav in AdminLayout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:09:27 +01:00
|
|
|
|
|
|
|
|
const handleSubmit = (e: FormEvent) => {
|
|
|
|
|
e.preventDefault()
|
|
|
|
|
if (!fromPokemonId || !toPokemonId) return
|
|
|
|
|
onSubmit({
|
|
|
|
|
fromPokemonId,
|
|
|
|
|
toPokemonId,
|
|
|
|
|
trigger,
|
|
|
|
|
minLevel: minLevel ? Number(minLevel) : null,
|
|
|
|
|
item: item || null,
|
|
|
|
|
heldItem: heldItem || null,
|
|
|
|
|
condition: condition || null,
|
2026-02-07 20:05:07 +01:00
|
|
|
region: region || null,
|
Improve admin panel UX with toasts, evolution CRUD, sorting, drag-and-drop, and responsive layout
Add sonner toast notifications to all mutations, evolution management backend
(CRUD endpoints with search/pagination) and frontend (form modal with pokemon
selector, paginated list page), sortable AdminTable columns (Region/Gen/Year
on Games), drag-and-drop route reordering via @dnd-kit, skeleton loading states,
card-styled table wrappers, and responsive mobile nav in AdminLayout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:09:27 +01:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<FormModal
|
|
|
|
|
title={evolution ? 'Edit Evolution' : 'Add Evolution'}
|
|
|
|
|
onClose={onClose}
|
|
|
|
|
onSubmit={handleSubmit}
|
|
|
|
|
isSubmitting={isSubmitting}
|
|
|
|
|
>
|
|
|
|
|
<PokemonSelector
|
|
|
|
|
label="From Pokemon"
|
|
|
|
|
selectedId={fromPokemonId}
|
|
|
|
|
initialName={evolution?.fromPokemon.name}
|
|
|
|
|
onChange={setFromPokemonId}
|
|
|
|
|
/>
|
|
|
|
|
<PokemonSelector
|
|
|
|
|
label="To Pokemon"
|
|
|
|
|
selectedId={toPokemonId}
|
|
|
|
|
initialName={evolution?.toPokemon.name}
|
|
|
|
|
onChange={setToPokemonId}
|
|
|
|
|
/>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium mb-1">Trigger</label>
|
|
|
|
|
<select
|
|
|
|
|
value={trigger}
|
|
|
|
|
onChange={(e) => setTrigger(e.target.value)}
|
|
|
|
|
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
|
|
|
|
|
>
|
|
|
|
|
{TRIGGER_OPTIONS.map((t) => (
|
|
|
|
|
<option key={t} value={t}>
|
|
|
|
|
{t}
|
|
|
|
|
</option>
|
|
|
|
|
))}
|
|
|
|
|
</select>
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium mb-1">Min Level</label>
|
|
|
|
|
<input
|
|
|
|
|
type="number"
|
|
|
|
|
min={1}
|
|
|
|
|
max={100}
|
|
|
|
|
value={minLevel}
|
|
|
|
|
onChange={(e) => setMinLevel(e.target.value)}
|
|
|
|
|
placeholder="Optional"
|
|
|
|
|
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">Item</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={item}
|
|
|
|
|
onChange={(e) => setItem(e.target.value)}
|
|
|
|
|
placeholder="e.g. thunder-stone"
|
|
|
|
|
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">Held Item</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={heldItem}
|
|
|
|
|
onChange={(e) => setHeldItem(e.target.value)}
|
|
|
|
|
placeholder="Optional"
|
|
|
|
|
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">Condition</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={condition}
|
|
|
|
|
onChange={(e) => setCondition(e.target.value)}
|
|
|
|
|
placeholder="e.g. high-happiness, daytime"
|
|
|
|
|
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
2026-02-07 20:05:07 +01:00
|
|
|
<div>
|
|
|
|
|
<label className="block text-sm font-medium mb-1">Region</label>
|
|
|
|
|
<input
|
|
|
|
|
type="text"
|
|
|
|
|
value={region}
|
|
|
|
|
onChange={(e) => setRegion(e.target.value)}
|
|
|
|
|
placeholder="e.g. alola (blank = all regions)"
|
|
|
|
|
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
Improve admin panel UX with toasts, evolution CRUD, sorting, drag-and-drop, and responsive layout
Add sonner toast notifications to all mutations, evolution management backend
(CRUD endpoints with search/pagination) and frontend (form modal with pokemon
selector, paginated list page), sortable AdminTable columns (Region/Gen/Year
on Games), drag-and-drop route reordering via @dnd-kit, skeleton loading states,
card-styled table wrappers, and responsive mobile nav in AdminLayout.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:09:27 +01:00
|
|
|
</FormModal>
|
|
|
|
|
)
|
|
|
|
|
}
|