From 9b6de000e794ffcdbb8176be5625ad835d8e8bf1 Mon Sep 17 00:00:00 2001 From: tejaspanchall Date: Thu, 5 Jun 2025 17:47:41 +0530 Subject: [PATCH] search working --- next.config.js | 1 - src/app/anime/[id]/page.js | 24 ++------- src/app/home/page.js | 41 ++++++++++----- src/app/search/page.js | 90 ++++++++++++++++---------------- src/components/Navbar.js | 6 ++- src/lib/api.js | 103 ++++++++++++++++++++++++++++++++----- 6 files changed, 173 insertions(+), 92 deletions(-) diff --git a/next.config.js b/next.config.js index a96bbc3..54b5db7 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { reactStrictMode: true, - swcMinify: true, env: { NEXT_PUBLIC_CORSPROXY_URL: process.env.CORSPROXY_URL, }, diff --git a/src/app/anime/[id]/page.js b/src/app/anime/[id]/page.js index 12635f9..d430982 100644 --- a/src/app/anime/[id]/page.js +++ b/src/app/anime/[id]/page.js @@ -72,30 +72,14 @@ const NotFoundState = () => ( // Main anime content component const AnimeContent = async ({ id }) => { try { - console.log('[Server] Fetching info for ID:', id); + console.log('[AnimeInfo] Fetching info for ID:', id); const anime = await fetchAnimeInfo(id); - console.log('[Server] API Response structure:', JSON.stringify({ - info: anime.info ? 'Present' : 'Missing', - moreInfo: anime.moreInfo ? 'Present' : 'Missing', - relatedAnime: Array.isArray(anime.relatedAnime) ? anime.relatedAnime.length : 'Not an array', - recommendations: Array.isArray(anime.recommendations) ? anime.recommendations.length : 'Not an array', - seasons: Array.isArray(anime.seasons) ? anime.seasons.length : 'Not an array', - mostPopular: Array.isArray(anime.mostPopular) ? anime.mostPopular.length : 'Not an array', - promotionalVideos: anime.info?.promotionalVideos ? anime.info.promotionalVideos.length : 'Missing', - characterVoiceActor: anime.info?.characterVoiceActor ? anime.info.characterVoiceActor.length : 'Missing' - }, null, 2)); - - // Explicitly log the characterVoiceActor data - console.log('[Server] Character Voice Actor data:', - anime.info?.characterVoiceActor - ? JSON.stringify(anime.info.characterVoiceActor.slice(0, 2)) - : 'Not available' - ); + console.log('[AnimeInfo] API Response received:', anime ? 'success' : 'empty'); if (!anime || !anime.info) { - console.error('[Server] Missing required anime data'); + console.error('[AnimeInfo] Missing required anime data'); return ; } @@ -105,7 +89,7 @@ const AnimeContent = async ({ id }) => { ); } catch (error) { - console.error('[Server Error]', error); + console.error('[AnimeInfo] Error:', error.message); return ; } }; diff --git a/src/app/home/page.js b/src/app/home/page.js index 2f02cfc..d263a5b 100644 --- a/src/app/home/page.js +++ b/src/app/home/page.js @@ -71,6 +71,8 @@ const AnimeGridSection = ({ title, animeList = [], viewMoreLink, isRecent = fals async function HomePage() { try { + console.log('[HomePage] Fetching home page data'); + // Fetch all data in parallel const [ spotlightData, @@ -85,47 +87,49 @@ async function HomePage() { trending ] = await Promise.all([ fetchSpotlightAnime().catch(err => { - console.error("Error fetching spotlight anime:", err); + console.error("[HomePage] Error fetching spotlight anime:", err.message); return []; }), fetchRecentEpisodes().catch(err => { - console.error("Error fetching recent episodes:", err); + console.error("[HomePage] Error fetching recent episodes:", err.message); return { results: [] }; }), fetchMostFavorite().catch(err => { - console.error("Error fetching most favorite:", err); + console.error("[HomePage] Error fetching most favorite:", err.message); return { results: [] }; }), fetchTopToday().catch(err => { - console.error("Error fetching top today:", err); + console.error("[HomePage] Error fetching top today:", err.message); return []; }), fetchTopWeek().catch(err => { - console.error("Error fetching top week:", err); + console.error("[HomePage] Error fetching top week:", err.message); return []; }), fetchTopMonth().catch(err => { - console.error("Error fetching top month:", err); + console.error("[HomePage] Error fetching top month:", err.message); return []; }), fetchTopAiring().catch(err => { - console.error("Error fetching top airing anime:", err); + console.error("[HomePage] Error fetching top airing anime:", err.message); return { results: [] }; }), fetchMostPopular().catch(err => { - console.error("Error fetching popular anime:", err); + console.error("[HomePage] Error fetching popular anime:", err.message); return { results: [] }; }), fetchLatestCompleted().catch(err => { - console.error("Error fetching latest completed anime:", err); + console.error("[HomePage] Error fetching latest completed anime:", err.message); return { results: [] }; }), fetchTrending().catch(err => { - console.error("Error fetching trending anime:", err); + console.error("[HomePage] Error fetching trending anime:", err.message); return { results: [] }; }) ]); + console.log('[HomePage] Data fetched successfully'); + return (
@@ -177,8 +181,21 @@ async function HomePage() {
); } catch (error) { - console.error('Error in HomePage:', error); - return
Error loading page
; + console.error('[HomePage] Error in HomePage:', error.message); + return ( +
+
+

Unable to load content

+

There was an error loading the home page content. Please try refreshing the page.

+ +
+
+ ); } } diff --git a/src/app/search/page.js b/src/app/search/page.js index b8d1cba..c127099 100644 --- a/src/app/search/page.js +++ b/src/app/search/page.js @@ -68,15 +68,14 @@ function SearchResults() { if (yearFilter !== 'all') filters.year = yearFilter; if (sortOrder !== 'default') filters.sort = sortOrder; - // Only add these filters if API supports them - // Currently, these may need to be handled client-side - // if (selectedSeasons.length > 0) filters.seasons = selectedSeasons; - // if (selectedTypes.length > 0) filters.types = selectedTypes; - // if (selectedStatus.length > 0) filters.status = selectedStatus; - // if (selectedLanguages.length > 0) filters.languages = selectedLanguages; + // Support all client-side filters in API call when possible + if (selectedSeasons.length > 0) filters.season = selectedSeasons.join(','); + if (selectedTypes.length > 0) filters.type = selectedTypes.join(','); + if (selectedStatus.length > 0) filters.status = selectedStatus.join(','); + if (selectedLanguages.length > 0) filters.language = selectedLanguages.join(','); return filters; - }, [selectedGenre, yearFilter, sortOrder]); + }, [selectedGenre, yearFilter, sortOrder, selectedSeasons, selectedTypes, selectedStatus, selectedLanguages]); // Apply client-side filters for things not supported by API const applyClientSideFilters = useCallback((animeList) => { @@ -199,20 +198,32 @@ function SearchResults() { try { const filters = getFiltersForApi(); - const data = await searchAnime(queryTerm, 1, filters); - const processedData = processAnimeData(data); + console.log(`[Search] Searching for: "${queryTerm}" with filters:`, filters); + const data = await searchAnime(queryTerm, 1, filters); + + // If no results but no error was thrown, show empty state + if (!data || (!data.results || data.results.length === 0)) { + console.log('[Search] No results found for search term:', queryTerm); + setError(`No results found for "${queryTerm}"`); + setAnimeList([]); + setFilteredList([]); + setIsLoading(false); + return; + } + + const processedData = processAnimeData(data); const results = processedData.results || []; setAnimeList(results); - // Apply client-side filters + // Only apply client-side filters for things not supported by API const filteredResults = applyClientSideFilters(results); setFilteredList(filteredResults); setHasNextPage(processedData.hasNextPage || false); } catch (error) { - console.error('Error searching anime:', error); - setError('Failed to search anime. Please try again later.'); + console.error('[Search] Error searching anime:', error); + setError('Failed to search anime. Please try again later or check your internet connection.'); setAnimeList([]); setFilteredList([]); } finally { @@ -249,7 +260,7 @@ function SearchResults() { setHasNextPage(processedData.hasNextPage || false); } else { - // Load more search results + // For search results, include filters const filters = getFiltersForApi(); const data = await searchAnime(queryTerm, currentPage, filters); const processedData = processAnimeData(data); @@ -257,7 +268,7 @@ function SearchResults() { const newResults = processedData.results || []; setAnimeList(prev => [...prev, ...newResults]); - // Apply client-side filters to new results + // Only apply client-side filters for things not supported by API const filteredNewResults = applyClientSideFilters(newResults); setFilteredList(prev => [...prev, ...filteredNewResults]); @@ -272,7 +283,7 @@ function SearchResults() { }; loadMoreData(); - }, [currentPage, queryTerm, getFiltersForApi, processAnimeData, applyClientSideFilters, isEmptySearch]); + }, [currentPage, queryTerm, isEmptySearch, getFiltersForApi, processAnimeData, applyClientSideFilters]); // Re-apply client-side filters when filters change but don't need API refetch useEffect(() => { @@ -361,39 +372,39 @@ function SearchResults() {
- {isLoading && currentPage === 1 ? ( -
-
+ {error ? ( +
+

{error}

- ) : error ? ( -
-

Error

-

{error}

+ ) : isLoading && currentPage === 1 ? ( +
+ {/* Loading skeleton */} + {[...Array(24)].map((_, index) => ( +
+ ))}
- ) : !queryTerm && !isEmptySearch ? ( -
-

Start Searching

-

Enter a keyword in the search box above to find anime

+ ) : filteredList.length === 0 ? ( +
+

No anime found matching your filters.

- ) : filteredList.length > 0 ? ( + ) : ( <> -
+
{filteredList.map((anime) => ( ))}
+ {/* Load more button */} {hasNextPage && ( -
+
)} - ) : ( -
-

No results found

-

- We couldn't find any anime matching your search criteria. Please try different filters or a different search term. -

-
)}
@@ -422,11 +426,7 @@ function SearchResults() { export default function SearchPage() { return ( - -
-
- }> + Loading...
}> ); diff --git a/src/components/Navbar.js b/src/components/Navbar.js index fc48f4e..be281e9 100644 --- a/src/components/Navbar.js +++ b/src/components/Navbar.js @@ -60,7 +60,8 @@ export default function Navbar() { setSearchSuggestions([{ id: searchQuery.toLowerCase().replace(/\s+/g, '-'), title: `Search for "${searchQuery}"`, - type: "SEARCH" + type: "SEARCH", + image: null }]); } } catch (error) { @@ -69,7 +70,8 @@ export default function Navbar() { setSearchSuggestions([{ id: searchQuery.toLowerCase().replace(/\s+/g, '-'), title: `Search for "${searchQuery}"`, - type: "SEARCH" + type: "SEARCH", + image: null }]); } finally { setIsLoading(false); diff --git a/src/lib/api.js b/src/lib/api.js index 2852dfd..7d12b17 100644 --- a/src/lib/api.js +++ b/src/lib/api.js @@ -1,4 +1,8 @@ -const API_BASE_URL = process.env.ANIWATCH_API || "https://justaniwatchapi.vercel.app/api/v2/hianime"; +// Use absolute URL for server components and relative URL for client components +const isServer = typeof window === 'undefined'; +const API_BASE_URL = isServer + ? "https://justaniwatchapi.vercel.app/api/v2/hianime" // Use absolute URL for server-side + : "/api/v2/hianime"; // Use relative URL for client-side // Common headers for all API requests const API_HEADERS = { @@ -484,19 +488,69 @@ export const fetchEpisodeSources = async (episodeId, dub = false) => { } }; -export const searchAnime = async (query, page = 1) => { +export const searchAnime = async (query, page = 1, filters = {}) => { try { - const response = await fetch(`${API_BASE_URL}/search?q=${encodeURIComponent(query)}&page=${page}`); - if (!response.ok) throw new Error('Failed to search anime'); + // Build the URL with query and page parameters + let url = `${API_BASE_URL}/search?q=${encodeURIComponent(query)}&page=${page}`; + + // Add any additional filters to the URL + if (filters && Object.keys(filters).length > 0) { + Object.entries(filters).forEach(([key, value]) => { + if (value) { + url += `&${encodeURIComponent(key)}=${encodeURIComponent(value)}`; + } + }); + } + + console.log("[API] Searching anime at:", url); + + // Make the request + const response = await fetch(url, { + headers: API_HEADERS, + next: { revalidate: 60 }, // Cache for 60 seconds + cache: 'no-cache' // Don't use browser cache + }); + + if (!response.ok) { + console.error(`[API] Search error: ${response.status} ${response.statusText}`); + throw new Error(`Failed to search anime: ${response.status} ${response.statusText}`); + } + const data = await response.json(); + console.log("[API] Search response:", data); + + // Check if the response is valid and matches expected format + if (!data.data) { + console.error('[API] Invalid response format from search API:', data); + return { + results: [], + mostPopularResults: [], + currentPage: page, + hasNextPage: false, + searchQuery: query, + searchFilters: filters + }; + } + return { results: data.data.animes || [], - currentPage: data.data.currentPage, - hasNextPage: data.data.hasNextPage + mostPopularResults: data.data.mostPopularAnimes || [], + currentPage: data.data.currentPage || page, + hasNextPage: data.data.hasNextPage || false, + totalPages: data.data.totalPages || 1, + searchQuery: data.data.searchQuery || query, + searchFilters: data.data.searchFilters || filters }; } catch (error) { - console.error('Error searching anime:', error); - return { results: [] }; + console.error('[API] Error searching anime:', error); + return { + results: [], + mostPopularResults: [], + currentPage: page, + hasNextPage: false, + searchQuery: query, + searchFilters: filters + }; } }; @@ -530,12 +584,37 @@ export const fetchGenreAnime = async (genre, page = 1) => { export const fetchSearchSuggestions = async (query) => { try { - const response = await fetch(`${API_BASE_URL}/search/suggestion?q=${encodeURIComponent(query)}`); - if (!response.ok) throw new Error('Failed to fetch search suggestions'); + console.log("[API] Fetching search suggestions for:", query); + const response = await fetch(`${API_BASE_URL}/search/suggestion?q=${encodeURIComponent(query)}`, { + headers: API_HEADERS, + next: { revalidate: 60 }, // Cache for 60 seconds + cache: 'no-cache' // Don't use browser cache + }); + + if (!response.ok) { + console.error(`[API] Search suggestions error: ${response.status} ${response.statusText}`); + throw new Error(`Failed to fetch search suggestions: ${response.status} ${response.statusText}`); + } + const data = await response.json(); - return data.data.suggestions || []; + console.log("[API] Search suggestions response:", data); + + if (!data.data) { + console.error('[API] Invalid response format from search suggestions API:', data); + return []; + } + + // Map the suggestions to include required fields + return (data.data.suggestions || []).map(suggestion => ({ + id: suggestion.id, + title: suggestion.name || suggestion.title, + image: suggestion.poster || suggestion.image, + // Include additional fields that might be useful for display + type: suggestion.type || 'ANIME', + jname: suggestion.jname || '' + })); } catch (error) { - console.error('Error fetching search suggestions:', error); + console.error('[API] Error fetching search suggestions:', error); return []; } };