From 4c73fc37258453314f36b315e576160b1c89982c Mon Sep 17 00:00:00 2001 From: austinkelsay Date: Sun, 27 Apr 2025 12:10:08 -0500 Subject: [PATCH] fixes for search and character matching and the state updates around it in the searchbar --- src/components/search/SearchBar.js | 78 ++++++++++++++++++++++++++---- src/hooks/useCommunitySearch.js | 37 +++++++++++--- src/hooks/useContentSearch.js | 20 +++++--- 3 files changed, 111 insertions(+), 24 deletions(-) diff --git a/src/components/search/SearchBar.js b/src/components/search/SearchBar.js index 55848b6..82e5f2e 100644 --- a/src/components/search/SearchBar.js +++ b/src/components/search/SearchBar.js @@ -9,6 +9,7 @@ import { useCommunitySearch } from '@/hooks/useCommunitySearch'; import { useRouter } from 'next/router'; import useWindowWidth from '@/hooks/useWindowWidth'; import { useNDKContext } from '@/context/NDKContext'; +import { ProgressSpinner } from 'primereact/progressspinner'; const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { const { searchContent, searchResults: contentResults } = useContentSearch(); @@ -26,8 +27,10 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { ]; const [searchTerm, setSearchTerm] = useState(''); const [searchResults, setSearchResults] = useState([]); + const [isSearching, setIsSearching] = useState(false); const op = useRef(null); const { ndk, reInitializeNDK } = useNDKContext(); + const searchTimeout = useRef(null); const selectedOptionTemplate = (option, props) => { if (isDesktopNav) { @@ -54,14 +57,29 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { const term = e.target.value; setSearchTerm(term); - if (selectedSearchOption.code === 'content') { - searchContent(term); - setSearchResults(contentResults); - } else if (selectedSearchOption.code === 'community' && ndk) { - searchCommunity(term); - setSearchResults(communityResults); + // Clear any existing timeout to avoid unnecessary API calls + if (searchTimeout.current) { + clearTimeout(searchTimeout.current); } + // Set loading state if term length is sufficient + if (term.length > 2) { + setIsSearching(true); + } + + // Set a timeout to avoid searching on each keystroke + searchTimeout.current = setTimeout(() => { + if (term.length > 2) { + if (selectedSearchOption.code === 'content') { + searchContent(term); + } else if (selectedSearchOption.code === 'community' && ndk) { + searchCommunity(term); + } + } else { + setIsSearching(false); + } + }, 300); + if (!isMobileSearch && term.length > 2) { op.current.show(e); } else if (!isMobileSearch) { @@ -75,7 +93,21 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { } else if (selectedSearchOption.code === 'community') { setSearchResults(communityResults); } - }, [selectedSearchOption, contentResults, communityResults]); + + // Once we have results, set isSearching to false + if (searchTerm.length > 2) { + setIsSearching(false); + } + }, [selectedSearchOption, contentResults, communityResults, searchTerm]); + + // Cleanup the timeout on component unmount + useEffect(() => { + return () => { + if (searchTimeout.current) { + clearTimeout(searchTimeout.current); + } + }; + }, []); useEffect(() => { const handleError = event => { @@ -115,6 +147,7 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { searchContent(''); searchCommunity(''); setSearchResults([]); + setIsSearching(false); if (op.current) { op.current.hide(); @@ -134,6 +167,16 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { }; const renderSearchResults = () => { + // Show loading spinner while searching + if (isSearching) { + return ( +
+ +
+ ); + } + + // Show no results message if (searchResults.length === 0 && searchTerm.length > 2) { return
No results found
; } @@ -147,6 +190,21 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { ); }; + // When search option changes, trigger search with current term + const handleSearchOptionChange = e => { + setSelectedSearchOption(e.value); + + // If there's a search term, run the search again with the new option + if (searchTerm.length > 2) { + setIsSearching(true); + if (e.value.code === 'content') { + searchContent(searchTerm); + } else if (e.value.code === 'community' && ndk) { + searchCommunity(searchTerm); + } + } + }; + return ( <>
@@ -185,7 +243,7 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { }, }} value={selectedSearchOption} - onChange={e => setSelectedSearchOption(e.value)} + onChange={handleSearchOptionChange} options={searchOptions} optionLabel="name" dropdownIcon={} @@ -227,7 +285,7 @@ const SearchBar = ({ isMobileSearch, isDesktopNav, onCloseSearch }) => { {searchOptions.map(option => (