diff --git a/frontend/src/pages/mobile/public/Schedule.jsx b/frontend/src/pages/mobile/public/Schedule.jsx index c5b26b3..0a4ca44 100644 --- a/frontend/src/pages/mobile/public/Schedule.jsx +++ b/frontend/src/pages/mobile/public/Schedule.jsx @@ -34,6 +34,8 @@ function MobileSchedule() { const [showSuggestions, setShowSuggestions] = useState(false); const [selectedSuggestionIndex, setSelectedSuggestionIndex] = useState(-1); const [originalSearchQuery, setOriginalSearchQuery] = useState(''); // 필터링용 원본 쿼리 + const [suggestions, setSuggestions] = useState([]); // 추천 검색어 목록 + const [isLoadingSuggestions, setIsLoadingSuggestions] = useState(false); // 검색 모드 진입 함수 (history 상태 추가) const enterSearchMode = () => { @@ -205,6 +207,34 @@ function MobileSchedule() { }; }, [showSuggestions]); + // 검색어 자동완성 API 호출 (debounce 적용) + useEffect(() => { + // 검색어가 비어있으면 초기화 + if (!originalSearchQuery || originalSearchQuery.trim().length === 0) { + setSuggestions([]); + return; + } + + // debounce: 200ms 후에 API 호출 + const timeoutId = setTimeout(async () => { + setIsLoadingSuggestions(true); + try { + const response = await fetch(`/api/schedules/suggestions?q=${encodeURIComponent(originalSearchQuery)}&limit=10`); + if (response.ok) { + const data = await response.json(); + setSuggestions(data.suggestions || []); + } + } catch (error) { + console.error('추천 검색어 API 오류:', error); + setSuggestions([]); + } finally { + setIsLoadingSuggestions(false); + } + }, 200); + + return () => clearTimeout(timeoutId); + }, [originalSearchQuery]); + // 카테고리 색상 const getCategoryColor = (categoryId) => { const category = categories.find(c => c.id === categoryId); @@ -305,34 +335,29 @@ function MobileSchedule() { }} onFocus={() => setShowSuggestions(true)} onKeyDown={(e) => { - // 필터링은 원본 쿼리 기준으로 유지 - const dummySuggestions = ['성수기', '성수기 이채영', '이채영 먹방', 'NOW TOMORROW', '하얀 그리움', '콘서트', '월드투어'].filter(s => - s.toLowerCase().includes(originalSearchQuery.toLowerCase()) - ).slice(0, 7); - if (e.key === 'ArrowDown') { e.preventDefault(); - const newIndex = selectedSuggestionIndex < dummySuggestions.length - 1 + const newIndex = selectedSuggestionIndex < suggestions.length - 1 ? selectedSuggestionIndex + 1 : 0; setSelectedSuggestionIndex(newIndex); - if (dummySuggestions[newIndex]) { - setSearchInput(dummySuggestions[newIndex]); + if (suggestions[newIndex]) { + setSearchInput(suggestions[newIndex]); } } else if (e.key === 'ArrowUp') { e.preventDefault(); const newIndex = selectedSuggestionIndex > 0 ? selectedSuggestionIndex - 1 - : dummySuggestions.length - 1; + : suggestions.length - 1; setSelectedSuggestionIndex(newIndex); - if (dummySuggestions[newIndex]) { - setSearchInput(dummySuggestions[newIndex]); + if (suggestions[newIndex]) { + setSearchInput(suggestions[newIndex]); } } else if (e.key === 'Enter') { e.preventDefault(); - if (selectedSuggestionIndex >= 0 && dummySuggestions[selectedSuggestionIndex]) { - setSearchInput(dummySuggestions[selectedSuggestionIndex]); - setSearchTerm(dummySuggestions[selectedSuggestionIndex]); + if (selectedSuggestionIndex >= 0 && suggestions[selectedSuggestionIndex]) { + setSearchInput(suggestions[selectedSuggestionIndex]); + setSearchTerm(suggestions[selectedSuggestionIndex]); } else if (searchInput.trim()) { setSearchTerm(searchInput); } @@ -578,23 +603,12 @@ function MobileSchedule() { !searchTerm ? ( // 검색어 입력 전 - 추천 검색어 리스트 표시 (유튜브 스타일)
- {(() => { - const dummySuggestions = ['성수기', '성수기 이채영', '이채영 먹방', 'NOW TOMORROW', '하얀 그리움', '콘서트', '월드투어']; - - // 입력값이 있으면 필터링 - const filtered = originalSearchQuery.length > 0 - ? dummySuggestions.filter(s => s.toLowerCase().includes(originalSearchQuery.toLowerCase())) - : dummySuggestions; - - if (filtered.length === 0) { - return ( -
- 추천 검색어가 없습니다 -
- ); - } - - return filtered.map((suggestion, index) => ( + {suggestions.length === 0 ? ( +
+ 검색어를 입력하세요 +
+ ) : ( + suggestions.map((suggestion, index) => ( - )); - })()} + )) + )}
) : searchLoading ? (