mirror of
https://github.com/fsolla/teqo.git
synced 2026-11-13 15:13:07 +00:00
Turn StateSelect and CitySelect into autocomplete comboboxes so long lists no longer bias people toward the top option. A shared FormCombobox wraps shadcn's (Base UI) Combobox and bridges it to react-hook-form via useController, storing the state code / city name while displaying a label. Matching is accent-insensitive and prefix-based; the list opens after 1 character and results are alphabetical. State searches by both full name and initials (new StateNames map). Adds @base-ui/react + shadcn combobox/input-group primitives, and documents our export-const and named-hook-import conventions in the components rule (with the src/components/ui/* shadcn carve-out).
43 lines
1.1 KiB
TypeScript
43 lines
1.1 KiB
TypeScript
import { CitiesByState } from '@/lib/cities'
|
|
import { useEffect, useMemo } from 'react'
|
|
import { useFormContext, useWatch } from 'react-hook-form'
|
|
import { FormCombobox, type ComboboxOption } from './FormCombobox'
|
|
|
|
interface CitySelectProps {
|
|
placeholder?: string
|
|
}
|
|
|
|
export const CitySelect = ({ placeholder = 'Selecione uma cidade' }: CitySelectProps) => {
|
|
const { control, setValue } = useFormContext()
|
|
const state: keyof typeof CitiesByState | undefined = useWatch({
|
|
control,
|
|
name: 'state',
|
|
})
|
|
|
|
const options = useMemo<ComboboxOption[]>(
|
|
() =>
|
|
state
|
|
? CitiesByState[state]
|
|
.map((city) => ({ value: city, label: city }))
|
|
.sort((a, b) => a.label.localeCompare(b.label, 'pt-BR'))
|
|
: [],
|
|
[state],
|
|
)
|
|
|
|
useEffect(() => {
|
|
setValue('city', '')
|
|
}, [state, setValue])
|
|
|
|
return (
|
|
<FormCombobox
|
|
name="city"
|
|
id="city"
|
|
options={options}
|
|
placeholder={placeholder}
|
|
minChars={1}
|
|
disabled={!options.length}
|
|
required
|
|
emptyMessage="Nenhuma cidade encontrada."
|
|
/>
|
|
)
|
|
}
|