feat: add location autocomplete functionality to HeroSection search input
This commit is contained in:
@@ -20,6 +20,7 @@ export function HeroSection({ content }: { content?: HeroContent }) {
|
||||
const [agentTypes, setAgentTypes] = useState<AgentType[]>([]);
|
||||
const [specializationOptions, setSpecializationOptions] = useState<{ id: string; name: string }[]>([]);
|
||||
const [specializationSlug, setSpecializationSlug] = useState<string>('');
|
||||
const [locationOptions, setLocationOptions] = useState<{ label: string; value: string }[]>([]);
|
||||
const [searchParams, setSearchParams] = useState({
|
||||
specialization: '',
|
||||
type: '',
|
||||
@@ -47,6 +48,30 @@ export function HeroSection({ content }: { content?: HeroContent }) {
|
||||
setSpecializationSlug(specField.slug);
|
||||
setSpecializationOptions(specField.options.map(o => ({ id: o.value, name: o.label })));
|
||||
}
|
||||
// Collect city + state options for location autocomplete.
|
||||
// Cities in the system may carry a state prefix (e.g. "ne_adams") — strip it for display.
|
||||
const formatCity = (label: string) => label.replace(/^[A-Z]{2}\s*[-–—]\s*/, '').trim();
|
||||
const locs: { label: string; value: string }[] = [];
|
||||
const seen = new Set<string>();
|
||||
for (const f of fields) {
|
||||
if (f.slug === 'state') {
|
||||
for (const opt of f.options) {
|
||||
const key = `state:${opt.label.toLowerCase()}`;
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
locs.push({ label: opt.label, value: opt.label });
|
||||
}
|
||||
} else if (f.slug === 'city') {
|
||||
for (const opt of f.options) {
|
||||
const clean = formatCity(opt.label);
|
||||
const key = `city:${clean.toLowerCase()}`;
|
||||
if (seen.has(key)) continue;
|
||||
seen.add(key);
|
||||
locs.push({ label: clean, value: clean });
|
||||
}
|
||||
}
|
||||
}
|
||||
setLocationOptions(locs);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch specializations:', error);
|
||||
}
|
||||
@@ -55,6 +80,10 @@ export function HeroSection({ content }: { content?: HeroContent }) {
|
||||
fetchSpecializations();
|
||||
}, []);
|
||||
|
||||
const filteredLocationOptions = searchParams.location.trim()
|
||||
? locationOptions.filter(o => o.label.toLowerCase().includes(searchParams.location.trim().toLowerCase())).slice(0, 8)
|
||||
: [];
|
||||
|
||||
const handleSearch = () => {
|
||||
// Validate that at least one field has a value
|
||||
const hasType = searchParams.type.trim() !== '';
|
||||
@@ -182,15 +211,39 @@ export function HeroSection({ content }: { content?: HeroContent }) {
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Location Input */}
|
||||
<div className="flex-1 md:min-w-[140px]">
|
||||
{/* Location Input with autocomplete */}
|
||||
<div className="relative flex-1 md:min-w-[140px]">
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Location"
|
||||
value={searchParams.location}
|
||||
onChange={(e) => handleInputChange('location', e.target.value)}
|
||||
onChange={(e) => {
|
||||
handleInputChange('location', e.target.value);
|
||||
setOpenDropdown('location');
|
||||
}}
|
||||
onFocus={() => setOpenDropdown('location')}
|
||||
onBlur={() => setTimeout(() => setOpenDropdown((cur) => (cur === 'location' ? null : cur)), 150)}
|
||||
autoComplete="off"
|
||||
className="w-full h-[42px] px-4 rounded-[7px] border border-[#00293d]/10 bg-white font-serif text-sm text-[#00293d] placeholder:text-[#00293d] focus:outline-none"
|
||||
/>
|
||||
{openDropdown === 'location' && filteredLocationOptions.length > 0 && (
|
||||
<div className="absolute top-full left-0 right-0 mt-0 bg-white rounded-[7px] border border-[#00293d]/10 shadow-lg z-20 overflow-hidden max-h-[240px] overflow-y-auto">
|
||||
{filteredLocationOptions.map((option, index, arr) => (
|
||||
<button
|
||||
key={option.value}
|
||||
onMouseDown={(e) => {
|
||||
e.preventDefault();
|
||||
setSearchParams((prev) => ({ ...prev, location: option.value }));
|
||||
setOpenDropdown(null);
|
||||
setValidationError(null);
|
||||
}}
|
||||
className={`w-full px-4 py-2.5 text-left font-serif text-sm text-[#00293d] hover:bg-[#00293d]/5 ${index < arr.length - 1 ? 'border-b border-[#00293d]/10' : ''}`}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Specialization Select */}
|
||||
|
||||
Reference in New Issue
Block a user