Files
nuzlocke-tracker/frontend/src/components/admin/AbilitySelector.tsx
Julian Tabel 0a519e356e
Some checks failed
CI / backend-tests (push) Failing after 1m16s
CI / frontend-tests (push) Successful in 57s
feat: add auth system, boss pokemon details, moves/abilities API, and run ownership
Add user authentication with login/signup/protected routes, boss pokemon
detail fields and result team tracking, moves and abilities selector
components and API, run ownership and visibility controls, and various
UI improvements across encounters, run list, and journal pages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 21:41:38 +01:00

70 lines
2.1 KiB
TypeScript

import { useState, useRef, useEffect } from 'react'
import { useSearchAbilities } from '../../hooks/useMoves'
interface AbilitySelectorProps {
label: string
selectedId: number | null
initialName?: string
onChange: (id: number | null, name: string) => void
}
export function AbilitySelector({
label,
selectedId,
initialName,
onChange,
}: AbilitySelectorProps) {
const [search, setSearch] = useState(initialName ?? '')
const [open, setOpen] = useState(false)
const ref = useRef<HTMLDivElement>(null)
const { data } = useSearchAbilities(search)
const abilities = data?.items ?? []
useEffect(() => {
function handleClick(e: MouseEvent) {
if (ref.current && !ref.current.contains(e.target as Node)) {
setOpen(false)
}
}
document.addEventListener('mousedown', handleClick)
return () => document.removeEventListener('mousedown', handleClick)
}, [])
return (
<div ref={ref} className="relative">
<label className="block text-xs font-medium mb-0.5 text-text-secondary">{label}</label>
<input
type="text"
value={search}
onChange={(e) => {
setSearch(e.target.value)
setOpen(true)
if (!e.target.value) onChange(null, '')
}}
onFocus={() => search && setOpen(true)}
placeholder="Search ability..."
className="w-full px-2 py-1.5 text-sm border rounded bg-surface-2 border-border-default"
/>
{open && abilities.length > 0 && (
<ul className="absolute z-20 mt-1 w-full bg-surface-1 border border-border-default rounded shadow-lg max-h-40 overflow-y-auto">
{abilities.map((a) => (
<li
key={a.id}
onClick={() => {
onChange(a.id, a.name)
setSearch(a.name)
setOpen(false)
}}
className={`px-2 py-1.5 cursor-pointer hover:bg-surface-2 text-sm ${
a.id === selectedId ? 'bg-accent-900/30' : ''
}`}
>
{a.name}
</li>
))}
</ul>
)}
</div>
)
}