import { useState, useEffect } from 'react' import { useRoutePokemon } from '../hooks/useGames' import type { Route, EncounterDetail, EncounterStatus, RouteEncounterDetail, } from '../types' interface EncounterModalProps { route: Route existing?: EncounterDetail onSubmit: (data: { routeId: number pokemonId: number nickname?: string status: EncounterStatus catchLevel?: number }) => void onUpdate?: (data: { id: number data: { nickname?: string status?: EncounterStatus faintLevel?: number deathCause?: string } }) => void onClose: () => void isPending: boolean } const statusOptions: { value: EncounterStatus; label: string; color: string }[] = [ { value: 'caught', label: 'Caught', color: 'bg-green-100 text-green-800 border-green-300 dark:bg-green-900/40 dark:text-green-300 dark:border-green-700', }, { value: 'fainted', label: 'Fainted', color: 'bg-red-100 text-red-800 border-red-300 dark:bg-red-900/40 dark:text-red-300 dark:border-red-700', }, { value: 'missed', label: 'Missed / Ran', color: 'bg-gray-100 text-gray-800 border-gray-300 dark:bg-gray-700 dark:text-gray-300 dark:border-gray-600', }, ] const specialMethodStyles: Record = { starter: { label: 'Starter', color: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/40 dark:text-yellow-300', }, gift: { label: 'Gift', color: 'bg-pink-100 text-pink-800 dark:bg-pink-900/40 dark:text-pink-300', }, fossil: { label: 'Fossil', color: 'bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300', }, trade: { label: 'Trade', color: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300', }, } function EncounterMethodBadge({ method }: { method: string }) { const config = specialMethodStyles[method] if (!config) return null return ( {config.label} ) } export function EncounterModal({ route, existing, onSubmit, onUpdate, onClose, isPending, }: EncounterModalProps) { const { data: routePokemon, isLoading: loadingPokemon } = useRoutePokemon( route.id, ) const [selectedPokemon, setSelectedPokemon] = useState(null) const [status, setStatus] = useState( existing?.status ?? 'caught', ) const [nickname, setNickname] = useState(existing?.nickname ?? '') const [catchLevel, setCatchLevel] = useState( existing?.catchLevel?.toString() ?? '', ) const [faintLevel, setFaintLevel] = useState('') const [deathCause, setDeathCause] = useState('') const [search, setSearch] = useState('') const isEditing = !!existing // Pre-select pokemon when editing useEffect(() => { if (existing && routePokemon) { const match = routePokemon.find( (rp) => rp.pokemonId === existing.pokemonId, ) if (match) setSelectedPokemon(match) } }, [existing, routePokemon]) const filteredPokemon = routePokemon?.filter((rp) => rp.pokemon.name.toLowerCase().includes(search.toLowerCase()), ) const handleSubmit = () => { if (isEditing && onUpdate) { onUpdate({ id: existing.id, data: { nickname: nickname || undefined, status, faintLevel: faintLevel ? Number(faintLevel) : undefined, deathCause: deathCause || undefined, }, }) } else if (selectedPokemon) { onSubmit({ routeId: route.id, pokemonId: selectedPokemon.pokemonId, nickname: nickname || undefined, status, catchLevel: catchLevel ? Number(catchLevel) : undefined, }) } } const canSubmit = isEditing || selectedPokemon return (

{isEditing ? 'Edit Encounter' : 'Log Encounter'}

{route.name}

{/* Pokemon Selection (only for new encounters) */} {!isEditing && (
{loadingPokemon ? (
) : filteredPokemon && filteredPokemon.length > 0 ? ( <> {(routePokemon?.length ?? 0) > 6 && ( setSearch(e.target.value)} className="w-full px-3 py-1.5 mb-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 text-sm focus:outline-none focus:ring-2 focus:ring-blue-500" /> )}
{filteredPokemon.map((rp) => ( ))}
) : (

No pokemon data for this route

)}
)} {/* Editing: show pokemon info */} {isEditing && existing && (
{existing.pokemon.spriteUrl ? ( {existing.pokemon.name} ) : (
{existing.pokemon.name[0].toUpperCase()}
)}
{existing.pokemon.name}
Caught at Lv. {existing.catchLevel ?? '?'}
)} {/* Status */}
{statusOptions.map((opt) => ( ))}
{/* Nickname (for caught) */} {status === 'caught' && (
setNickname(e.target.value)} placeholder="Give it a name..." className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500" />
)} {/* Level (for new caught encounters) */} {!isEditing && status === 'caught' && (
setCatchLevel(e.target.value)} placeholder={ selectedPokemon ? `${selectedPokemon.minLevel}–${selectedPokemon.maxLevel}` : 'Level' } className="w-24 px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500" />
)} {/* Faint Level + Death Cause (only when editing a caught pokemon to mark dead) */} {isEditing && existing?.status === 'caught' && existing?.faintLevel === null && ( <>
setFaintLevel(e.target.value)} placeholder="Leave empty if still alive" className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500" />
setDeathCause(e.target.value)} placeholder="e.g. Crit from rival's Charizard" className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500" />
)}
) }