Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import React, { useState, useEffect, useRef, useCallback } from "react";
- import { FaSearch } from "react-icons/fa";
- import { useNavigate, useLocation } from "react-router-dom";
- import useDebounce from "../hooks/useDebounce";
- import { generateBaseURL } from "../utils";
- import "./SearchBar.css";
- function SearchBar() {
- const [searchText, setSearchText] = useState("");
- const [searchResults, setSearchResults] = useState([]);
- const [isDropdownOpen, setIsDropdownOpen] = useState(false);
- const searchRef = useRef(null);
- const navigate = useNavigate();
- const location = useLocation();
- const debouncedSearchText = useDebounce(searchText, 300);
- // Fetch search results based on location text
- const fetchSearchResults = useCallback(async (value) => {
- if (value.length > 0) {
- try {
- const baseURL = generateBaseURL();
- const response = await fetch(
- `${baseURL}/api/apartments/search?location=${value}`
- );
- if (!response.ok) {
- throw new Error("Network response was not ok");
- }
- const data = await response.json();
- setSearchResults(data);
- setIsDropdownOpen(true);
- } catch (error) {
- console.error("Error retrieving search results:", error);
- setSearchResults([]);
- setIsDropdownOpen(false);
- }
- } else {
- setSearchResults([]);
- setIsDropdownOpen(false);
- }
- }, []);
- // Debounced search execution
- useEffect(() => {
- fetchSearchResults(debouncedSearchText);
- }, [debouncedSearchText, fetchSearchResults]);
- // Close dropdown on route change
- useEffect(() => {
- setIsDropdownOpen(false);
- }, [location]);
- // Click outside handler
- useEffect(() => {
- const handleClickOutside = (event) => {
- if (
- searchRef.current &&
- !searchRef.current.contains(event.target)
- ) {
- setIsDropdownOpen(false);
- }
- };
- document.addEventListener("mousedown", handleClickOutside);
- return () => {
- document.removeEventListener("mousedown", handleClickOutside);
- };
- }, []);
- // Navigate on result click
- const handleResultClick = (result) => {
- navigate(`/details/${result.id}`);
- setIsDropdownOpen(false);
- };
- return (
- <div ref={searchRef} className="search-container relative w-full max-w-xl mx-auto">
- <div
- className="search-input-wrapper flex items-center border border-gray-300 rounded px-3 py-2 bg-white"
- data-testid="search-div"
- >
- <FaSearch className="text-gray-500 mr-2" />
- <input
- type="text"
- className="w-full bg-transparent focus:outline-none text-sm"
- placeholder="Search apartments..."
- value={searchText}
- onChange={(e) => setSearchText(e.target.value)}
- onFocus={() => {
- if (searchResults.length > 0) setIsDropdownOpen(true);
- }}
- data-testid="search-input"
- />
- </div>
- {isDropdownOpen && (
- <div
- className="dropdown absolute top-full mt-2 w-full bg-white border border-gray-200 rounded shadow z-10"
- data-testid="auth-dropdown-btn"
- >
- {searchResults.length > 0 ? (
- searchResults.map((result, index) => (
- <div
- key={index}
- className="px-4 py-2 hover:bg-gray-100 cursor-pointer text-sm"
- onClick={() => handleResultClick(result)}
- >
- {result.name}
- </div>
- ))
- ) : (
- <div className="px-4 py-2 text-sm text-gray-500">No results found</div>
- )}
- </div>
- )}
- </div>
- );
- }
- export default SearchBar;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement