fix(hackathon): match search input height with city select and add debounce

- Set consistent h-[42px] height for both search and city filter inputs
- Add 300ms debounce to search to reduce API calls while typing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Maulana Sodiqin
2025-11-26 14:19:33 +07:00
co-authored by Claude
parent 7f8b53edd4
commit 63db7ff6ad
2 changed files with 18 additions and 9 deletions
+17 -8
View File
@@ -1,5 +1,5 @@
import { FC, ReactElement, useState } from 'react'; import { FC, ReactElement, useState, useEffect } from 'react';
import { Button, Input } from '@imphnen-frontend-service/ui/atoms'; import { Button } from '@imphnen-frontend-service/ui/atoms';
import { Link, useNavigate } from 'react-router'; import { Link, useNavigate } from 'react-router';
import { useTeams, useJoinTeam, useMyTeams, ETeamVisibility, joinTeamSchema, TJoinTeamForm } from '@imphnen-frontend-service/service'; import { useTeams, useJoinTeam, useMyTeams, ETeamVisibility, joinTeamSchema, TJoinTeamForm } from '@imphnen-frontend-service/service';
import { useForm } from 'react-hook-form'; import { useForm } from 'react-hook-form';
@@ -8,13 +8,22 @@ import { CitySelect } from '../../../components/city-select';
const BrowseTeamsPage: FC = (): ReactElement => { const BrowseTeamsPage: FC = (): ReactElement => {
const navigate = useNavigate(); const navigate = useNavigate();
const [search, setSearch] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [debouncedSearch, setDebouncedSearch] = useState('');
const [selectedCity, setSelectedCity] = useState(''); const [selectedCity, setSelectedCity] = useState('');
const [selectedTeamId, setSelectedTeamId] = useState<string | null>(null); const [selectedTeamId, setSelectedTeamId] = useState<string | null>(null);
const [showJoinModal, setShowJoinModal] = useState(false); const [showJoinModal, setShowJoinModal] = useState(false);
// Debounce search term
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedSearch(searchTerm);
}, 300);
return () => clearTimeout(timer);
}, [searchTerm]);
const { data: teamsData, isLoading } = useTeams({ const { data: teamsData, isLoading } = useTeams({
search, search: debouncedSearch,
city: selectedCity || undefined, city: selectedCity || undefined,
visibility: ETeamVisibility.PUBLIC, visibility: ETeamVisibility.PUBLIC,
}); });
@@ -78,12 +87,12 @@ const BrowseTeamsPage: FC = (): ReactElement => {
<label className="block text-sm font-medium text-gray-700 mb-2"> <label className="block text-sm font-medium text-gray-700 mb-2">
Search Teams Search Teams
</label> </label>
<Input <input
type="text" type="text"
placeholder="Search by team name..." placeholder="Search by team name..."
value={search} value={searchTerm}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearchTerm(e.target.value)}
className="h-12" className="w-full h-[42px] px-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent"
/> />
</div> </div>
<div> <div>
@@ -70,7 +70,7 @@ export const CitySelect: FC<CitySelectProps> = ({
}} }}
onClick={handleInputClick} onClick={handleInputClick}
placeholder={placeholder} placeholder={placeholder}
className={`w-full px-3 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${ className={`w-full h-[42px] px-3 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${
error ? 'border-red-500' : 'border-gray-300' error ? 'border-red-500' : 'border-gray-300'
}`} }`}
/> />