From d08809dc4d16e5af8ac4def2e68f72992464da5a Mon Sep 17 00:00:00 2001 From: Chris-1010 <122332721@umail.ucc.ie> Date: Mon, 3 Mar 2025 17:05:18 +0000 Subject: [PATCH] FIX: Search from `ResultsPage` --- frontend/src/components/Input/SearchBar.tsx | 104 ++++++----- frontend/src/pages/ResultsPage.tsx | 183 ++++++++++---------- 2 files changed, 149 insertions(+), 138 deletions(-) diff --git a/frontend/src/components/Input/SearchBar.tsx b/frontend/src/components/Input/SearchBar.tsx index 708888d..c565d50 100644 --- a/frontend/src/components/Input/SearchBar.tsx +++ b/frontend/src/components/Input/SearchBar.tsx @@ -1,66 +1,76 @@ -import React, { useState } from "react"; +// In SearchBar.tsx +import React, { useState, useEffect } from "react"; import Input from "./Input"; import { SearchIcon } from "lucide-react"; import { useNavigate } from "react-router-dom"; interface SearchBarProps { - value?: string; + value?: string; + onSearchResults?: (results: any, query: string) => void; } -const SearchBar: React.FC = ({ value = "" }) => { - const [searchQuery, setSearchQuery] = useState(value); - //const [debouncedQuery, setDebouncedQuery] = useState(searchQuery); - const navigate = useNavigate(); +const SearchBar: React.FC = ({ value = "", onSearchResults }) => { + const [searchQuery, setSearchQuery] = useState(value); + const navigate = useNavigate(); - const handleSearch = async () => { - if (!searchQuery.trim()) return; + // Update searchQuery when value prop changes + useEffect(() => { + setSearchQuery(value); + }, [value]); - try { - const response = await fetch("/api/search", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ query: searchQuery }), - }); + const handleSearch = async () => { + if (!searchQuery.trim()) return; - const data = await response.json(); + try { + const response = await fetch("/api/search", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ query: searchQuery }), + }); - navigate("/results", { - state: { searchResults: data, query: searchQuery }, - }); + const data = await response.json(); - // Handle the search results here - } catch (error) { - console.error("Error performing search:", error); - } - }; + // If we have a callback for search results, use that instead of navigating + if (onSearchResults) { + onSearchResults(data, searchQuery); + } else { + // Otherwise navigate to results page with the data + navigate("/results", { + state: { searchResults: data, query: searchQuery }, + }); + } + } catch (error) { + console.error("Error performing search:", error); + } + }; - const handleKeyPress = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - e.preventDefault(); - handleSearch(); - } - }; + const handleKeyPress = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + e.preventDefault(); + handleSearch(); + } + }; - const handleSearchChange = (e: React.ChangeEvent) => { - setSearchQuery(e.target.value); - }; + const handleSearchChange = (e: React.ChangeEvent) => { + setSearchQuery(e.target.value); + }; - return ( - + ); }; export default SearchBar; diff --git a/frontend/src/pages/ResultsPage.tsx b/frontend/src/pages/ResultsPage.tsx index bb3addc..712f400 100644 --- a/frontend/src/pages/ResultsPage.tsx +++ b/frontend/src/pages/ResultsPage.tsx @@ -1,3 +1,4 @@ +// In ResultsPage.tsx import React, { useEffect, useState } from "react"; import { useLocation, useNavigate } from "react-router-dom"; import SearchBar from "../components/Input/SearchBar"; @@ -5,105 +6,105 @@ import ListRow from "../components/Layout/ListRow"; import DynamicPageContent from "../components/Layout/DynamicPageContent"; import { getCategoryThumbnail } from "../utils/thumbnailUtils"; -const ResultsPage: React.FC = ({ }) => { - const [overflow, setOverflow] = useState(false); - const location = useLocation(); - const navigate = useNavigate(); - const { searchResults, query } = location.state || { - searchResults: { categories: [], users: [], streams: [] }, - query: "", - }; +const ResultsPage: React.FC = () => { + const [overflow, setOverflow] = useState(false); + const location = useLocation(); + const navigate = useNavigate(); - useEffect(() => { - const checkHeight = () => { - setOverflow( - document.documentElement.scrollHeight + 20 > window.innerHeight - ); - }; + // Initialize with state from navigation, or empty defaults + const [searchState, setSearchState] = useState({ + searchResults: location.state?.searchResults || { categories: [], users: [], streams: [] }, + query: location.state?.query || "", + }); - checkHeight(); - window.addEventListener("resize", checkHeight); + // Handle new search results + const handleSearchResults = (results: any, newQuery: string) => { + console.log("New search results:", results); + setSearchState({ + searchResults: results, + query: newQuery, + }); - return () => window.removeEventListener("resize", checkHeight); - }, []); + // Update URL state without navigation + window.history.replaceState({ searchResults: results, query: newQuery }, "", "/results"); + }; - return ( - -
-

- Search results for "{query}" -

- + useEffect(() => { + // If location state changes, update our internal state + if (location.state) { + setSearchState({ + searchResults: location.state.searchResults, + query: location.state.query, + }); + } + }, [location.state]); -
- ({ - id: stream.user_id, - type: "stream", - title: stream.title, - username: stream.username, - streamCategory: stream.category_name, - viewers: stream.num_viewers, - thumbnail: stream.thumbnail_url, - }))} - title="Streams" - onItemClick={(streamer_name: string) => - (window.location.href = `/${streamer_name}`) - } - extraClasses="min-h-[calc((20vw+20vh)/4)] bg-[var(--liveNow)]" - itemExtraClasses="min-w-[calc(12vw+12vh/2)]" - amountForScroll={3} - /> + return ( + +
+

Search results for "{searchState.query}"

+ handleSearchResults(results, query)} /> - ({ - id: category.category_id, - type: "category", - title: category.category_name, - viewers: 0, - thumbnail: getCategoryThumbnail(category.category_name), - }))} - title="Categories" - onItemClick={(category_name: string) => - navigate(`/category/${category_name}`) - } - titleClickable={true} - extraClasses="min-h-[calc((20vw+20vh)/4)] bg-[var(--liveNow)]" - itemExtraClasses="min-w-[calc(12vw+12vh/2)]" - amountForScroll={3} - /> +
+ ({ + id: stream.user_id, + type: "stream", + title: stream.title, + username: stream.username, + streamCategory: stream.category_name, + viewers: stream.num_viewers, + thumbnail: stream.thumbnail_url, + }))} + title="Streams" + onItemClick={(streamer_name: string) => (window.location.href = `/${streamer_name}`)} + extraClasses="min-h-[calc((20vw+20vh)/4)] bg-[var(--liveNow)]" + itemExtraClasses="min-w-[calc(12vw+12vh/2)]" + amountForScroll={3} + /> - ({ - id: user.user_id, - type: "user", - title: `${user.is_live ? "🔴" : ""} ${user.username}`, - username: user.username - }))} - title="Users" - onItemClick={(username: string) => - (window.location.href = `/user/${username}`) - } - amountForScroll={3} - extraClasses="min-h-[calc((20vw+20vh)/4)] bg-[var(--liveNow)]" - itemExtraClasses="min-w-[calc(12vw+12vh/2)]" - /> -
+ ({ + id: category.category_id, + type: "category", + title: category.category_name, + viewers: 0, + thumbnail: getCategoryThumbnail(category.category_name), + }))} + title="Categories" + onItemClick={(category_name: string) => navigate(`/category/${category_name}`)} + titleClickable={true} + extraClasses="min-h-[calc((20vw+20vh)/4)] bg-[var(--liveNow)]" + itemExtraClasses="min-w-[calc(12vw+12vh/2)]" + amountForScroll={3} + /> -
-
-
-
- ); + ({ + id: user.user_id, + type: "user", + title: `${user.is_live ? "🔴" : ""} ${user.username}`, + username: user.username, + }))} + title="Users" + onItemClick={(username: string) => (window.location.href = `/user/${username}`)} + amountForScroll={3} + extraClasses="min-h-[calc((20vw+20vh)/4)] bg-[var(--liveNow)]" + itemExtraClasses="min-w-[calc(12vw+12vh/2)]" + /> +
+
+
+ ); }; export default ResultsPage;