Spaces:
Running
Running
import React, { useState, useEffect } from 'react'; | |
import { useSearchParams } from 'react-router-dom'; | |
import { useToast } from '@/hooks/use-toast'; | |
import { searchAPI } from '../lib/search-api'; | |
import PageHeader from '../components/PageHeader'; | |
import ContentGrid from '../components/ContentGrid'; | |
import ContentCard from '../components/ContentCard'; | |
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; | |
import { Loader2 } from 'lucide-react'; | |
const SearchPage = () => { | |
const [searchParams] = useSearchParams(); | |
const query = searchParams.get('q') || ''; | |
const [searchResults, setSearchResults] = useState<{ | |
movies: string[]; | |
shows: string[]; | |
episodes: { | |
series: string; | |
title: string; | |
path: string; | |
season: string; | |
}[]; | |
}>({ | |
movies: [], | |
shows: [], | |
episodes: [] | |
}); | |
const [loading, setLoading] = useState(false); | |
const [activeTab, setActiveTab] = useState('all'); | |
const { toast } = useToast(); | |
useEffect(() => { | |
const fetchSearchResults = async () => { | |
if (!query) return; | |
try { | |
setLoading(true); | |
const results = await searchAPI.search(query); | |
setSearchResults({ | |
movies: results.films || [], | |
shows: results.series || [], | |
episodes: results.episodes || [] | |
}); | |
} catch (error) { | |
console.error('Search error:', error); | |
toast({ | |
title: "Search Failed", | |
description: "Unable to perform search. Please try again.", | |
variant: "destructive" | |
}); | |
} finally { | |
setLoading(false); | |
} | |
}; | |
fetchSearchResults(); | |
}, [query, toast]); | |
const getTotalResultsCount = () => { | |
return searchResults.movies.length + searchResults.shows.length + searchResults.episodes.length; | |
}; | |
const renderMovieResults = () => { | |
if (searchResults.movies.length === 0) { | |
return <p className="text-center text-gray-400 my-8">No movies found matching "{query}"</p>; | |
} | |
return ( | |
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> | |
{searchResults.movies.map((title, index) => ( | |
<ContentCard | |
key={`movie-${title}-${index}`} | |
type="movie" | |
title={title.split('/')[1]} | |
prefetchData={true} | |
/> | |
))} | |
</div> | |
); | |
}; | |
const renderShowResults = () => { | |
if (searchResults.shows.length === 0) { | |
return <p className="text-center text-gray-400 my-8">No TV shows found matching "{query}"</p>; | |
} | |
return ( | |
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> | |
{searchResults.shows.map((title, index) => ( | |
<ContentCard | |
key={`show-${title}-${index}`} | |
type="tvshow" | |
title={title} | |
prefetchData={true} | |
/> | |
))} | |
</div> | |
); | |
}; | |
const renderEpisodeResults = () => { | |
if (searchResults.episodes.length === 0) { | |
return <p className="text-center text-gray-400 my-8">No episodes found matching "{query}"</p>; | |
} | |
return ( | |
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"> | |
{searchResults.episodes.map((episode, index) => ( | |
<div key={`episode-${index}`} className="bg-theme-card p-4 rounded-md hover:bg-theme-card-hover transition-colors"> | |
<h3 className="font-semibold">{episode.title}</h3> | |
<p className="text-sm text-gray-400"> | |
{episode.series} • Season {episode.season} | |
</p> | |
</div> | |
))} | |
</div> | |
); | |
}; | |
return ( | |
<div className="container mx-auto px-4 py-8"> | |
<PageHeader | |
title={query ? `Search Results for "${query}"` : "Search"} | |
subtitle={query ? `${getTotalResultsCount()} results found` : "Enter a search term in the search box"} | |
/> | |
{loading ? ( | |
<div className="flex justify-center items-center py-12"> | |
<Loader2 className="w-12 h-12 animate-spin text-theme-primary/70" /> | |
</div> | |
) : query ? ( | |
<Tabs defaultValue={activeTab} onValueChange={setActiveTab} className="w-full mt-6"> | |
<TabsList className="mb-6"> | |
<TabsTrigger value="all"> | |
All Results ({getTotalResultsCount()}) | |
</TabsTrigger> | |
<TabsTrigger value="movies"> | |
Movies ({searchResults.movies.length}) | |
</TabsTrigger> | |
<TabsTrigger value="shows"> | |
TV Shows ({searchResults.shows.length}) | |
</TabsTrigger> | |
<TabsTrigger value="episodes"> | |
Episodes ({searchResults.episodes.length}) | |
</TabsTrigger> | |
</TabsList> | |
<TabsContent value="all"> | |
{getTotalResultsCount() === 0 ? ( | |
<p className="text-center text-gray-400 my-8">No results found matching "{query}"</p> | |
) : ( | |
<> | |
{searchResults.movies.length > 0 && ( | |
<div className="mb-8"> | |
<h2 className="text-xl font-semibold mb-4">Movies</h2> | |
{renderMovieResults()} | |
</div> | |
)} | |
{searchResults.shows.length > 0 && ( | |
<div className="mb-8"> | |
<h2 className="text-xl font-semibold mb-4">TV Shows</h2> | |
{renderShowResults()} | |
</div> | |
)} | |
{searchResults.episodes.length > 0 && ( | |
<div> | |
<h2 className="text-xl font-semibold mb-4">Episodes</h2> | |
{renderEpisodeResults()} | |
</div> | |
)} | |
</> | |
)} | |
</TabsContent> | |
<TabsContent value="movies"> | |
{renderMovieResults()} | |
</TabsContent> | |
<TabsContent value="shows"> | |
{renderShowResults()} | |
</TabsContent> | |
<TabsContent value="episodes"> | |
{renderEpisodeResults()} | |
</TabsContent> | |
</Tabs> | |
) : ( | |
<div className="text-center py-12"> | |
<p className="text-gray-400">Enter a search term to find movies, TV shows, and episodes.</p> | |
</div> | |
)} | |
</div> | |
); | |
}; | |
export default SearchPage; | |