Files
nuzlocke-tracker/frontend/src/components/admin/EvolutionFormModal.tsx
Julian Tabel 3a64661760
Some checks failed
CI / backend-lint (push) Failing after 1m4s
CI / actions-lint (push) Failing after 6s
CI / frontend-lint (push) Successful in 59s
Align repo config with global development standards
- Add missing tsconfig strictness flags (noUncheckedIndexedAccess,
  exactOptionalPropertyTypes, noImplicitOverride,
  noPropertyAccessFromIndexSignature) and fix all resulting type errors
- Replace ESLint/Prettier with oxlint 1.48.0 and oxfmt 0.33.0
- Pin all frontend and backend dependencies to exact versions
- Pin GitHub Actions to SHA hashes with persist-credentials: false
- Fix CI Python version mismatch (3.12 -> 3.14) and ruff target-version
- Add vitest 4.0.18 with jsdom environment for frontend testing
- Add ty 0.0.17 for Python type checking (non-blocking in CI)
- Add actionlint and zizmor CI job for workflow linting and security audit
- Add Dependabot config for npm, pip, and github-actions
- Update CLAUDE.md and pre-commit hooks to reflect new tooling
- Ignore Claude Code sandbox artifacts in gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:39:41 +01:00

141 lines
4.5 KiB
TypeScript

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
onDelete?: () => void
isDeleting?: boolean
}
const TRIGGER_OPTIONS = ['level-up', 'trade', 'use-item', 'shed', 'other']
export function EvolutionFormModal({
evolution,
onSubmit,
onClose,
isSubmitting,
onDelete,
isDeleting,
}: 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 ?? '')
const [region, setRegion] = useState(evolution?.region ?? '')
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,
region: region || null,
})
}
return (
<FormModal
title={evolution ? 'Edit Evolution' : 'Add Evolution'}
onClose={onClose}
onSubmit={handleSubmit}
isSubmitting={isSubmitting}
onDelete={onDelete}
isDeleting={isDeleting}
>
<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>
<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>
</FormModal>
)
}