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

View File

@@ -12,6 +12,7 @@ const Input: React.FC<InputProps> = ({
value = "",
extraClasses = "",
onChange = () => { },
onKeyDown = () => { },
children,
...props // all other HTML input props
}) => {
@@ -24,6 +25,7 @@ const Input: React.FC<InputProps> = ({
placeholder={placeholder}
value={value}
onChange={onChange}
onKeyDown={onKeyDown}
{...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`}
/>

View File

@@ -1,44 +1,55 @@
import React, { useState, useEffect } from "react";
import Input from "./Input";
import { Search as SearchIcon } from "lucide-react";
import { useNavigate } from "react-router-dom";
const SearchBar: React.FC = () => {
const [searchQuery, setSearchQuery] = useState("");
const [debouncedQuery, setDebouncedQuery] = useState(searchQuery);
//const [debouncedQuery, setDebouncedQuery] = useState(searchQuery);
const navigate = useNavigate();
// Debounce the search query
{/*
useEffect(() => {
const timer = setTimeout(() => {
setDebouncedQuery(searchQuery);
}, 500); // Wait 500ms after user stops typing
return () => clearTimeout(timer);
}, [searchQuery]);
}, [searchQuery]); */}
// Perform search when debounced query changes
useEffect(() => {
if (debouncedQuery.trim()) {
const fetchSearchResults = async () => {
const handleSearch = async () => {
if (!searchQuery.trim()) return;
try {
const response = await fetch("/api/search", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ query: debouncedQuery }), // <-- Fixed payload
body: JSON.stringify({ query: searchQuery }), // <-- Fixed payload
});
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);
}
};
fetchSearchResults(); // Call the async function
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
}
}, [debouncedQuery]);
};
const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
@@ -52,9 +63,12 @@ const SearchBar: React.FC = () => {
placeholder="Search..."
value={searchQuery}
onChange={handleSearchChange}
onKeyDown={handleKeyPress}
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" />
</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