Complete search functionality with version filtering
- Added version selector dropdown to search interface - Search now includes version parameter for backend filtering - Search results footer shows which Bible version was searched - Users can search ESV or NKJV independently - Version-aware search provides different results per translation Search UI now includes version selection alongside book filtering.
This commit is contained in:
@@ -562,6 +562,7 @@ function App() {
|
|||||||
formatBookName={formatBookName}
|
formatBookName={formatBookName}
|
||||||
getBookUrlName={getBookUrlName}
|
getBookUrlName={getBookUrlName}
|
||||||
books={books}
|
books={books}
|
||||||
|
selectedVersion={selectedVersion}
|
||||||
onClose={() => setShowSearch(false)}
|
onClose={() => setShowSearch(false)}
|
||||||
isModal={true}
|
isModal={true}
|
||||||
/>
|
/>
|
||||||
@@ -578,6 +579,7 @@ function App() {
|
|||||||
formatBookName={formatBookName}
|
formatBookName={formatBookName}
|
||||||
getBookUrlName={getBookUrlName}
|
getBookUrlName={getBookUrlName}
|
||||||
books={books}
|
books={books}
|
||||||
|
selectedVersion={selectedVersion}
|
||||||
isModal={false}
|
isModal={false}
|
||||||
/>
|
/>
|
||||||
} />
|
} />
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ interface SearchComponentProps {
|
|||||||
formatBookName: (bookName: string) => string;
|
formatBookName: (bookName: string) => string;
|
||||||
getBookUrlName: (bookName: string) => string;
|
getBookUrlName: (bookName: string) => string;
|
||||||
books?: string[];
|
books?: string[];
|
||||||
|
selectedVersion?: string;
|
||||||
|
onVersionChange?: (version: string) => void;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
isModal?: boolean;
|
isModal?: boolean;
|
||||||
}
|
}
|
||||||
@@ -15,6 +17,8 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
formatBookName,
|
formatBookName,
|
||||||
getBookUrlName,
|
getBookUrlName,
|
||||||
books = [],
|
books = [],
|
||||||
|
selectedVersion: initialVersion = 'esv',
|
||||||
|
onVersionChange,
|
||||||
onClose,
|
onClose,
|
||||||
isModal = false
|
isModal = false
|
||||||
}) => {
|
}) => {
|
||||||
@@ -24,6 +28,7 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [hasSearched, setHasSearched] = useState(false);
|
const [hasSearched, setHasSearched] = useState(false);
|
||||||
const [selectedBook, setSelectedBook] = useState<string>('');
|
const [selectedBook, setSelectedBook] = useState<string>('');
|
||||||
|
const [selectedVersion, setSelectedVersion] = useState<string>(initialVersion);
|
||||||
const searchTimeoutRef = useRef<NodeJS.Timeout>();
|
const searchTimeoutRef = useRef<NodeJS.Timeout>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
@@ -42,7 +47,8 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
const searchOptions = {
|
const searchOptions = {
|
||||||
...(bookFilter && { book: bookFilter }),
|
...(bookFilter && { book: bookFilter }),
|
||||||
limit: 50,
|
limit: 50,
|
||||||
context: true
|
context: true,
|
||||||
|
version: selectedVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
const response: SearchResponse = await searchBible(searchQuery, searchOptions);
|
const response: SearchResponse = await searchBible(searchQuery, searchOptions);
|
||||||
@@ -55,7 +61,7 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [selectedVersion]);
|
||||||
|
|
||||||
// Handle search input changes
|
// Handle search input changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -137,7 +143,7 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
value={query}
|
value={query}
|
||||||
onChange={(e) => setQuery(e.target.value)}
|
onChange={(e) => setQuery(e.target.value)}
|
||||||
placeholder="Search for verses, words, or phrases..."
|
placeholder="Search for verses, words, or phrases..."
|
||||||
className="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg
|
className="w-full pl-10 pr-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg
|
||||||
bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100
|
bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100
|
||||||
focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -146,7 +152,26 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
<Loader2 className="absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-blue-500 animate-spin" />
|
<Loader2 className="absolute right-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-blue-500 animate-spin" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Version Selector */}
|
||||||
|
<select
|
||||||
|
value={selectedVersion}
|
||||||
|
onChange={(e) => {
|
||||||
|
const newVersion = e.target.value;
|
||||||
|
if (onVersionChange) {
|
||||||
|
onVersionChange(newVersion);
|
||||||
|
}
|
||||||
|
// Re-trigger search when version changes
|
||||||
|
setTimeout(() => setSelectedVersion(newVersion), 0);
|
||||||
|
}}
|
||||||
|
className="px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg
|
||||||
|
bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100
|
||||||
|
focus:ring-2 focus:ring-blue-500 focus:border-transparent"
|
||||||
|
>
|
||||||
|
<option value="esv">ESV - English Standard Version</option>
|
||||||
|
<option value="nkjv">NKJV - New King James Version</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
<select
|
<select
|
||||||
value={selectedBook}
|
value={selectedBook}
|
||||||
onChange={(e) => setSelectedBook(e.target.value)}
|
onChange={(e) => setSelectedBook(e.target.value)}
|
||||||
@@ -243,7 +268,7 @@ const SearchComponent: React.FC<SearchComponentProps> = ({
|
|||||||
{/* Footer */}
|
{/* Footer */}
|
||||||
{results.length > 0 && (
|
{results.length > 0 && (
|
||||||
<div className="p-4 border-t border-gray-200 dark:border-gray-700 text-center text-sm text-gray-500 dark:text-gray-400">
|
<div className="p-4 border-t border-gray-200 dark:border-gray-700 text-center text-sm text-gray-500 dark:text-gray-400">
|
||||||
Found {results.length} result{results.length !== 1 ? 's' : ''} for "{query}"
|
Found {results.length} result{results.length !== 1 ? 's' : ''} for "{query}" in {selectedVersion.toUpperCase()} Bible
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ export interface SearchOptions {
|
|||||||
book?: string;
|
book?: string;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
context?: boolean;
|
context?: boolean;
|
||||||
|
version?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search API functions
|
// Search API functions
|
||||||
@@ -69,7 +70,8 @@ export const searchBible = async (query: string, options: SearchOptions = {}): P
|
|||||||
q: query,
|
q: query,
|
||||||
...(options.book && { book: options.book }),
|
...(options.book && { book: options.book }),
|
||||||
...(options.limit && { limit: options.limit.toString() }),
|
...(options.limit && { limit: options.limit.toString() }),
|
||||||
...(options.context !== undefined && { context: options.context.toString() })
|
...(options.context !== undefined && { context: options.context.toString() }),
|
||||||
|
...(options.version && { version: options.version })
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await api.get(`/api/search?${params}`);
|
const response = await api.get(`/api/search?${params}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user