FEAT: Results Page from Search Bar

This commit is contained in:
EvanLin3141
2025-02-12 14:33:14 +00:00
parent 4c9e329107
commit 01932c4db9
4 changed files with 103 additions and 26 deletions

View File

@@ -9,6 +9,7 @@ import UserPage from "./pages/UserPage";
import ResetPasswordPage from "./pages/ResetPasswordPage"; import ResetPasswordPage from "./pages/ResetPasswordPage";
import CategoryPage from "./pages/CategoryPage"; import CategoryPage from "./pages/CategoryPage";
import CategoriesPage from "./pages/CategoriesPage"; import CategoriesPage from "./pages/CategoriesPage";
import FoundPage from "./pages/FoundPage";
function App() { function App() {
const [isLoggedIn, setIsLoggedIn] = useState(false); const [isLoggedIn, setIsLoggedIn] = useState(false);
@@ -46,7 +47,7 @@ function App() {
<Route path="/reset_password/:token" element={<ResetPasswordPage />}></Route> <Route path="/reset_password/:token" element={<ResetPasswordPage />}></Route>
<Route path="/category/:category_name" element={<CategoryPage />}></Route> <Route path="/category/:category_name" element={<CategoryPage />}></Route>
<Route path="/category" element={<CategoriesPage />}></Route> <Route path="/category" element={<CategoriesPage />}></Route>
<Route path="/results" element={<FoundPage />}></Route>
<Route path="/404" element={<NotFoundPage />} /> <Route path="/404" element={<NotFoundPage />} />
</Routes> </Routes>
</BrowserRouter> </BrowserRouter>

View File

@@ -12,6 +12,7 @@ const Input: React.FC<InputProps> = ({
value = "", value = "",
extraClasses = "", extraClasses = "",
onChange = () => { }, onChange = () => { },
onKeyDown = () => { },
children, children,
...props // all other HTML input props ...props // all other HTML input props
}) => { }) => {
@@ -24,6 +25,7 @@ const Input: React.FC<InputProps> = ({
placeholder={placeholder} placeholder={placeholder}
value={value} value={value}
onChange={onChange} onChange={onChange}
onKeyDown={onKeyDown}
{...props} {...props}
className={`${extraClasses} relative p-2 rounded-[1rem] w-[20vw] focus:w-[21vw] bg-black/40 border border-gray-300 focus:border-purple-500 focus:outline-purple-500 text-center text-white text-xl transition-all`} className={`${extraClasses} relative p-2 rounded-[1rem] w-[20vw] focus:w-[21vw] bg-black/40 border border-gray-300 focus:border-purple-500 focus:outline-purple-500 text-center text-white text-xl transition-all`}
/> />

View File

@@ -1,44 +1,55 @@
import React, { useState, useEffect } from "react"; import React, { useState, useEffect } from "react";
import Input from "./Input"; import Input from "./Input";
import { Search as SearchIcon } from "lucide-react"; import { Search as SearchIcon } from "lucide-react";
import { useNavigate } from "react-router-dom";
const SearchBar: React.FC = () => { const SearchBar: React.FC = () => {
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const [debouncedQuery, setDebouncedQuery] = useState(searchQuery); //const [debouncedQuery, setDebouncedQuery] = useState(searchQuery);
const navigate = useNavigate();
// Debounce the search query // Debounce the search query
{/*
useEffect(() => { useEffect(() => {
const timer = setTimeout(() => { const timer = setTimeout(() => {
setDebouncedQuery(searchQuery); setDebouncedQuery(searchQuery);
}, 500); // Wait 500ms after user stops typing }, 500); // Wait 500ms after user stops typing
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [searchQuery]); }, [searchQuery]); */}
// Perform search when debounced query changes // Perform search when debounced query changes
useEffect(() => { const handleSearch = async () => {
if (debouncedQuery.trim()) { if (!searchQuery.trim()) return;
const fetchSearchResults = async () => {
try {
const response = await fetch("/api/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query: debouncedQuery }), // <-- Fixed payload
});
const data = await response.json(); try {
console.log("Search results:", data); const response = await fetch("/api/search", {
// Handle the search results here method: "POST",
} catch (error) { headers: {
console.error("Error performing search:", error); "Content-Type": "application/json",
} },
}; body: JSON.stringify({ query: searchQuery }), // <-- Fixed payload
});
fetchSearchResults(); // Call the async function const data = await response.json();
console.log("Search results:", data);
navigate("/results", { state: { searchResults: data, query: searchQuery } });
// Handle the search results here
} catch (error) {
console.error("Error performing search:", error);
} }
}, [debouncedQuery]); };
const handleKeyPress = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === "Enter") {
console.log("Key pressed:", e.key); // Debugging
e.preventDefault(); // Prevent unintended form submission
handleSearch(); // Trigger search when Enter key is pressed
}
};
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => { const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -52,9 +63,12 @@ const SearchBar: React.FC = () => {
placeholder="Search..." placeholder="Search..."
value={searchQuery} value={searchQuery}
onChange={handleSearchChange} onChange={handleSearchChange}
onKeyDown={handleKeyPress}
extraClasses="pr-[30px] focus:outline-none focus:border-purple-500 focus:w-[30vw]" extraClasses="pr-[30px] focus:outline-none focus:border-purple-500 focus:w-[30vw]"
/> />
<SearchIcon className="-translate-x-[28px] top-1/2 h-6 w-6 text-white" /> <SearchIcon className="-translate-x-[28px] top-1/2 h-6 w-6 text-white" />
</div> </div>
); );

View File

@@ -0,0 +1,60 @@
import React from 'react'
import { useLocation, useNavigate } from "react-router-dom";
const FoundPage: React.FC = ({}) => {
const location = useLocation();
const navigate = useNavigate();
const { searchResults, query } = location.state || { searchResults: null, query: "" };
if (!searchResults) {
return (
<div className="p-4">
<h2 className="text-xl font-bold">No results found for "{query}"</h2>
<button onClick={() => navigate(-1)} className="mt-4 px-4 py-2 bg-purple-500 text-white rounded">
Go Back
</button>
</div>
);
}
return (
<div className="p-4">
<h2 className="text-xl font-bold mb-4">Search Results for "{query}"</h2>
<div>
<h3 className="text-lg font-semibold">Categories</h3>
<ul>
{searchResults.categories.map((category: any, index: number) => (
<li key={index} className="border p-2 rounded my-2">{category.category_name}</li>
))}
</ul>
</div>
<div>
<h3 className="text-lg font-semibold">Users</h3>
<ul>
{searchResults.users.map((user: any, index: number) => (
<li key={index} className="border p-2 rounded my-2">{user.username} {user.is_live ? "🔴" : ""}</li>
))}
</ul>
</div>
<div>
<h3 className="text-lg font-semibold">Streams</h3>
<ul>
{searchResults.streams.map((stream: any, index: number) => (
<li key={index} className="border p-2 rounded my-2">
{stream.title} - {stream.num_viewers} viewers
</li>
))}
</ul>
</div>
<button onClick={() => navigate(-1)} className="mt-4 px-4 py-2 bg-purple-500 text-white rounded">
Go Back
</button>
</div>
);
};
export default FoundPage