import { useState, useEffect } from "react"; import { useSearchParams } from "react-router-dom"; import { useQuery } from "@tanstack/react-query"; import { search } from "../api"; import VideoCard from "../components/VideoCard"; import ChannelCard from "../components/ChannelCard"; function Badge({ label }) { return ( {label} ); } function Spinner() { return (
); } const PAGE_SIZE = 20; export default function SearchResults() { const [params] = useSearchParams(); const q = params.get("q") || ""; const [visibleCount, setVisibleCount] = useState(PAGE_SIZE); // Reset pagination when query changes useEffect(() => { setVisibleCount(PAGE_SIZE); }, [q]); // Local search — fast, appears immediately const localQuery = useQuery({ queryKey: ["search", q, false], queryFn: () => search(q, false).then((r) => r.data), enabled: q.length > 0, staleTime: 30_000, }); // Live search — always runs in parallel, merges YouTube results in when ready const liveQuery = useQuery({ queryKey: ["search", q, true], queryFn: () => search(q, true).then((r) => r.data), enabled: q.length > 0, staleTime: 60_000, }); // Show live data when available (superset of local), fall back to local while waiting const data = liveQuery.data ?? localQuery.data; const isLoading = localQuery.isLoading; const isLiveLoading = liveQuery.isLoading && !liveQuery.isError; const source = data?.source; if (!q) { return

Type something in the search bar above.

; } if (isLoading) return ; const videos = data?.videos ?? []; const allChannels = data?.channels ?? []; // Cap channels shown — when they're synthesized from 40 video results it's too many const channels = allChannels.slice(0, 6); const visibleVideos = videos.slice(0, visibleCount); const hasMore = visibleCount < videos.length; // Show channels first only when they're the primary result (few videos or FTS hit) const channelsFirst = channels.length > 0 && (videos.length === 0 || source === "local"); return (

Results for "{q}"

{source === "live" && } {source === "local" && } {source === "mixed" && } {isLiveLoading && ( searching YouTube… )}
{/* Channels first when they're the primary result */} {channelsFirst && channels.length > 0 && (

Channels

{channels.map((c) => ( ))}
)} {/* Video results */} {videos.length > 0 ? (

Videos {hasMore ? `${visibleCount} of ${videos.length}` : videos.length}

{visibleVideos.map((v) => ( ))}
{hasMore && ( )}
) : ( !isLoading && !channels.length && (

No results found for "{q}".

) )} {/* Channels after videos when videos dominate */} {!channelsFirst && channels.length > 0 && (

Channels

{channels.map((c) => ( ))}
)}
); }