diff --git a/frontend/src/hooks/useContent.ts b/frontend/src/hooks/useContent.ts index 8f99efb..58ae5a7 100644 --- a/frontend/src/hooks/useContent.ts +++ b/frontend/src/hooks/useContent.ts @@ -102,25 +102,184 @@ export function useStreams(customUrl?: string): { error: string | null; } { const { isLoggedIn } = useAuth(); - const url = customUrl || (isLoggedIn ? "/api/streams/recommended" : "/api/streams/popular/4"); + const [streams, setStreams] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); - const { data, isLoading, error } = useFetchContent(url, processStreamData, [isLoggedIn, customUrl]); + useEffect(() => { + const fetchStreams = async () => { + setIsLoading(true); + try { + // Always fetch the recommended streams if logged in + if (isLoggedIn && !customUrl) { + const recommendedResponse = await fetch("/api/streams/recommended"); + if (!recommendedResponse.ok) { + throw new Error(`Error fetching recommended streams: ${recommendedResponse.status}`); + } - return { streams: data, isLoading, error }; + const recommendedData = await recommendedResponse.json(); + const processedRecommended = processStreamData(recommendedData); + + // If we have at least 4 recommended streams, use just those + if (processedRecommended.length >= 4) { + setStreams(processedRecommended); + } + // If we have fewer than 4, fetch popular streams to fill the gap + else { + const popularResponse = await fetch(`/api/streams/popular/8`); + + if (!popularResponse.ok) { + throw new Error(`Error fetching popular streams: ${popularResponse.status}`); + } + + const popularData = await popularResponse.json(); + const processedPopular = processStreamData(popularData); + + // Combine recommended and popular, ensuring no duplicates + const combinedStreams = [...processedRecommended]; + + // Add popular streams if they're not already in recommended + for (const popularStream of processedPopular) { + if (!combinedStreams.some((stream) => stream.id === popularStream.id)) { + combinedStreams.push(popularStream); + } + } + + setStreams(combinedStreams); + } + } + // For custom URL or not logged in, use the original approach + else { + const url = customUrl || "/api/streams/popular/4"; + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`Error fetching streams: ${response.status}`); + } + + const data = await response.json(); + setStreams(processStreamData(data)); + } + + setError(null); + } catch (err) { + console.error("Error in useStreams:", err); + setError(err instanceof Error ? err.message : "Unknown error"); + // Fallback to popular streams on error + if (!customUrl) { + try { + const fallbackResponse = await fetch("/api/streams/popular/4"); + if (fallbackResponse.ok) { + const fallbackData = await fallbackResponse.json(); + setStreams(processStreamData(fallbackData)); + } + } catch (fallbackErr) { + console.error("Error fetching fallback streams:", fallbackErr); + } + } + } finally { + setIsLoading(false); + } + }; + + fetchStreams(); + }, [isLoggedIn, customUrl]); + + return { streams, isLoading, error }; } export function useCategories(customUrl?: string): { categories: CategoryType[]; isLoading: boolean; error: string | null; -} { + } { const { isLoggedIn } = useAuth(); - const url = customUrl || (isLoggedIn ? "/api/categories/recommended" : "/api/categories/popular/4"); - - const { data, isLoading, error } = useFetchContent(url, processCategoryData, [isLoggedIn, customUrl]); - - return { categories: data, isLoading, error }; -} + const [categories, setCategories] = useState([]); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + const fetchCategories = async () => { + setIsLoading(true); + try { + // Always fetch the recommended categories if logged in + if (isLoggedIn && !customUrl) { + const recommendedResponse = await fetch("/api/categories/recommended"); + if (!recommendedResponse.ok) { + throw new Error(`Error fetching recommended categories: ${recommendedResponse.status}`); + } + + const recommendedData = await recommendedResponse.json(); + const processedRecommended = processCategoryData(recommendedData); + + // If we have at least 4 recommended categories, use just those + if (processedRecommended.length >= 4) { + setCategories(processedRecommended); + } + // If we have fewer than 4, fetch popular categories to fill the gap + else { + const popularResponse = await fetch(`/api/categories/popular/8`); + + if (!popularResponse.ok) { + throw new Error(`Error fetching popular categories: ${popularResponse.status}`); + } + + const popularData = await popularResponse.json(); + const processedPopular = processCategoryData(popularData); + + // Get IDs of recommended categories to avoid duplicates + const recommendedIds = processedRecommended.map(cat => cat.id); + + // Filter popular categories to only include ones not in recommended + const uniquePopularCategories = processedPopular.filter( + popularCat => !recommendedIds.includes(popularCat.id) + ); + + // Combine with recommended categories first to maintain priority + const combinedCategories = [...processedRecommended, ...uniquePopularCategories]; + + setCategories(combinedCategories); + } + } + // For custom URL or not logged in, use the original approach + else { + const url = customUrl || "/api/categories/popular/4"; + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`Error fetching categories: ${response.status}`); + } + + const data = await response.json(); + setCategories(processCategoryData(data)); + } + + setError(null); + } catch (err) { + console.error("Error in useCategories:", err); + setError(err instanceof Error ? err.message : "Unknown error"); + // Fallback to popular categories on error + if (!customUrl) { + try { + const fallbackResponse = await fetch("/api/categories/popular/4"); + if (fallbackResponse.ok) { + const fallbackData = await fallbackResponse.json(); + setCategories(processCategoryData(fallbackData)); + } + } catch (fallbackErr) { + console.error("Error fetching fallback categories:", fallbackErr); + } + } + } finally { + setIsLoading(false); + } + }; + + fetchCategories(); + }, [isLoggedIn, customUrl]); + + return { categories, isLoading, error }; + } export function useVods(customUrl?: string): { vods: VodType[];