|
"use client"; |
|
import { useState, useEffect, useRef } from "react"; |
|
import { useRouter } from "next/navigation"; |
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; |
|
import { |
|
faSearch, |
|
faCaretLeft, |
|
faCaretRight, |
|
} from "@fortawesome/free-solid-svg-icons"; |
|
import { search } from "@/api/searchApi"; |
|
import "./searchPage.css"; |
|
import MovieCard from "@/components/MovieCard"; |
|
import TvShowCard from "@/components/TvShowCard"; |
|
|
|
const SearchPage = () => { |
|
const [query, setQuery] = useState(""); |
|
const [results, setResults] = useState({ films: [], tv_series: [] }); |
|
const [loading, setLoading] = useState(false); |
|
const [error, setError] = useState(null); |
|
const [debouncedQuery, setDebouncedQuery] = useState(""); |
|
const [loadingDelay, setLoadingDelay] = useState(null); |
|
|
|
const router = useRouter(); |
|
const timeoutRef = useRef(null); |
|
const moviesRef = useRef(null); |
|
const seriesRef = useRef(null); |
|
|
|
useEffect(() => { |
|
if (timeoutRef.current) { |
|
clearTimeout(timeoutRef.current); |
|
} |
|
|
|
timeoutRef.current = setTimeout(() => { |
|
if (debouncedQuery) { |
|
handleSearch(); |
|
} |
|
}, 200); |
|
|
|
return () => { |
|
if (timeoutRef.current) { |
|
clearTimeout(timeoutRef.current); |
|
} |
|
}; |
|
}, [debouncedQuery]); |
|
|
|
const handleSearch = async () => { |
|
setLoading(true); |
|
setError(null); |
|
|
|
try { |
|
const data = await search(debouncedQuery); |
|
setResults(data); |
|
} catch (err) { |
|
setError("Failed to fetch search results."); |
|
} finally { |
|
if (loadingDelay) { |
|
clearTimeout(loadingDelay); |
|
} |
|
setLoadingDelay(setTimeout(() => setLoading(false), 800)); |
|
} |
|
}; |
|
|
|
const handleChange = (e) => { |
|
setQuery(e.target.value); |
|
setDebouncedQuery(e.target.value); |
|
}; |
|
|
|
const handleItemClick = (path) => { |
|
router.push(path); |
|
}; |
|
|
|
const scroll = (ref, direction) => { |
|
if (ref.current) { |
|
const scrollAmount = direction === "left" ? -400 : 400; |
|
ref.current.scrollBy({ left: scrollAmount, behavior: "smooth" }); |
|
} |
|
}; |
|
|
|
return ( |
|
<div className="search-page"> |
|
<div className="search-container"> |
|
<input |
|
type="text" |
|
value={query} |
|
onChange={handleChange} |
|
placeholder="Search for films or TV shows..." |
|
className="search-input" |
|
/> |
|
{loading && ( |
|
<div className="loading-indicator"> |
|
<div className="search-icon"> |
|
<FontAwesomeIcon icon={faSearch} size="xl" /> |
|
</div> |
|
<div className="spinner"></div> |
|
</div> |
|
)} |
|
</div> |
|
{error && <div className="error-message">{error}</div>} |
|
<div className="results-container"> |
|
{results.films.length > 0 && ( |
|
<div className="results-section"> |
|
<div className="result-scroll"> |
|
<h2>Films</h2> |
|
<div className="scroll-controls"> |
|
<button |
|
onClick={() => scroll(moviesRef, "left")} |
|
className="scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretLeft} size="2xl" /> |
|
</button> |
|
<button |
|
onClick={() => scroll(moviesRef, "right")} |
|
className="scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretRight} size="2xl" /> |
|
</button> |
|
</div> |
|
</div> |
|
<ul className="results-list" ref={moviesRef}> |
|
{results.films.map((film, index) => ( |
|
<li |
|
key={index} |
|
className="result-item" |
|
onClick={() => |
|
handleItemClick(`/movie/${encodeURIComponent(film)}`) |
|
} |
|
> |
|
<MovieCard title={film} /> |
|
</li> |
|
))} |
|
</ul> |
|
</div> |
|
)} |
|
{results.tv_series.length > 0 && ( |
|
<div className="results-section"> |
|
<div className="result-scroll"> |
|
<h2>TV Series</h2> |
|
<div className="scroll-controls"> |
|
<button |
|
onClick={() => scroll(seriesRef, "left")} |
|
className="scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretLeft} size="2xl" /> |
|
</button> |
|
<button |
|
onClick={() => scroll(seriesRef, "right")} |
|
className="scroll-button" |
|
> |
|
<FontAwesomeIcon icon={faCaretRight} size="2xl" /> |
|
</button> |
|
</div> |
|
</div> |
|
<ul className="results-list" ref={seriesRef}> |
|
{results.tv_series.map((series, index) => ( |
|
<li |
|
key={index} |
|
className="result-item" |
|
onClick={() => |
|
handleItemClick(`/tvshow/${encodeURIComponent(series)}`) |
|
} |
|
> |
|
<TvShowCard title={series} /> |
|
</li> |
|
))} |
|
</ul> |
|
</div> |
|
)} |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
export default SearchPage; |
|
|