Files
nuzlocke-tracker/frontend/src/components/admin/RouteEncounterFormModal.tsx

150 lines
5.0 KiB
TypeScript
Raw Normal View History

import { type FormEvent, useState } from 'react'
import { FormModal } from './FormModal'
import { PokemonSelector } from './PokemonSelector'
import { METHOD_ORDER, METHOD_CONFIG, getMethodLabel } from '../EncounterMethodBadge'
import type { RouteEncounterDetail, CreateRouteEncounterInput, UpdateRouteEncounterInput } from '../../types'
interface RouteEncounterFormModalProps {
encounter?: RouteEncounterDetail
onSubmit: (data: CreateRouteEncounterInput | UpdateRouteEncounterInput) => void
onClose: () => void
isSubmitting?: boolean
onDelete?: () => void
isDeleting?: boolean
}
export function RouteEncounterFormModal({
encounter,
onSubmit,
onClose,
isSubmitting,
onDelete,
isDeleting,
}: RouteEncounterFormModalProps) {
const [pokemonId, setPokemonId] = useState(encounter?.pokemonId ?? 0)
const initialMethod = encounter?.encounterMethod ?? ''
const isKnownMethod = METHOD_ORDER.includes(initialMethod)
const [selectedMethod, setSelectedMethod] = useState(isKnownMethod ? initialMethod : initialMethod ? 'other' : '')
const [customMethod, setCustomMethod] = useState(isKnownMethod ? '' : initialMethod)
const encounterMethod = selectedMethod === 'other' ? customMethod : selectedMethod
const [encounterRate, setEncounterRate] = useState(String(encounter?.encounterRate ?? ''))
const [minLevel, setMinLevel] = useState(String(encounter?.minLevel ?? ''))
const [maxLevel, setMaxLevel] = useState(String(encounter?.maxLevel ?? ''))
const handleSubmit = (e: FormEvent) => {
e.preventDefault()
if (encounter) {
onSubmit({
encounterMethod,
encounterRate: Number(encounterRate),
minLevel: Number(minLevel),
maxLevel: Number(maxLevel),
})
} else {
onSubmit({
pokemonId,
encounterMethod,
encounterRate: Number(encounterRate),
minLevel: Number(minLevel),
maxLevel: Number(maxLevel),
})
}
}
return (
<FormModal
title={encounter ? 'Edit Route Encounter' : 'Add Pokemon to Route'}
onClose={onClose}
onSubmit={handleSubmit}
isSubmitting={isSubmitting}
onDelete={onDelete}
isDeleting={isDeleting}
>
{!encounter && (
<PokemonSelector
label="Pokemon"
selectedId={pokemonId || null}
onChange={(id) => setPokemonId(id ?? 0)}
/>
)}
<div>
<label className="block text-sm font-medium mb-1">Encounter Method</label>
<select
required
value={selectedMethod}
onChange={(e) => {
setSelectedMethod(e.target.value)
if (e.target.value !== 'other') setCustomMethod('')
}}
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
>
<option value="">Select method...</option>
{METHOD_ORDER.map((m) => (
<option key={m} value={m}>
{getMethodLabel(m)}
</option>
))}
<option value="other">Other...</option>
</select>
{selectedMethod && selectedMethod !== 'other' && (
<span
className={`inline-block mt-1 text-[9px] px-1.5 py-0.5 font-medium rounded-full whitespace-nowrap ${METHOD_CONFIG[selectedMethod]?.color ?? ''}`}
>
{getMethodLabel(selectedMethod)}
</span>
)}
{selectedMethod === 'other' && (
<input
type="text"
required
value={customMethod}
onChange={(e) => setCustomMethod(e.target.value)}
placeholder="Custom method name"
className="w-full mt-2 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">Encounter Rate (%)</label>
<input
type="number"
required
min={1}
max={100}
value={encounterRate}
onChange={(e) => setEncounterRate(e.target.value)}
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium mb-1">Min Level</label>
<input
type="number"
required
min={1}
max={100}
value={minLevel}
onChange={(e) => setMinLevel(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">Max Level</label>
<input
type="number"
required
min={1}
max={100}
value={maxLevel}
onChange={(e) => setMaxLevel(e.target.value)}
className="w-full px-3 py-2 border rounded-md dark:bg-gray-700 dark:border-gray-600"
/>
</div>
</div>
</FormModal>
)
}