import React, { useState, useEffect, useCallback, useRef } from 'react' import { usePage } from '@inertiajs/react' import axios from 'axios' import PostCard from '../../Components/Feed/PostCard' import PostCardSkeleton from '../../Components/Feed/PostCardSkeleton' /* ── Trending hashtags sidebar ─────────────────────────────────────────────── */ function TrendingHashtagsSidebar({ hashtags }) { if (!hashtags || hashtags.length === 0) return null return (
Trending Tags
{hashtags.map((h) => ( #{h.tag} {h.post_count} ))}
) } /* ── Main page ─────────────────────────────────────────────────────────────── */ export default function SearchFeed() { const { props } = usePage() const { auth, initialQuery, trendingHashtags } = props const authUser = auth?.user ?? null const [query, setQuery] = useState(initialQuery ?? '') const [results, setResults] = useState([]) const [loading, setLoading] = useState(false) const [searched, setSearched] = useState(false) const [meta, setMeta] = useState(null) const [page, setPage] = useState(1) const debounceRef = useRef(null) const inputRef = useRef(null) /* ── Push query into URL without reload ──────────────────────────────────── */ const pushUrl = useCallback((q) => { const url = q.trim() ? `/feed/search?q=${encodeURIComponent(q.trim())}` : '/feed/search' window.history.replaceState({}, '', url) }, []) /* ── Fetch results ───────────────────────────────────────────────────────── */ const fetchResults = useCallback(async (q, p = 1) => { if (!q.trim() || q.trim().length < 2) { setResults([]) setMeta(null) setSearched(false) return } setLoading(true) try { const { data } = await axios.get('/api/feed/search', { params: { q: q.trim(), page: p }, }) setResults((prev) => p === 1 ? data.data : [...prev, ...data.data]) setMeta(data.meta) setPage(p) setSearched(true) } catch { // } finally { setLoading(false) } }, []) /* ── Debounce typing ─────────────────────────────────────────────────────── */ const handleChange = useCallback((e) => { const q = e.target.value setQuery(q) pushUrl(q) clearTimeout(debounceRef.current) debounceRef.current = setTimeout(() => { fetchResults(q, 1) }, 350) }, [fetchResults, pushUrl]) const handleSubmit = useCallback((e) => { e.preventDefault() clearTimeout(debounceRef.current) fetchResults(query, 1) }, [fetchResults, query]) const handleClear = useCallback(() => { setQuery('') setResults([]) setMeta(null) setSearched(false) pushUrl('') inputRef.current?.focus() }, [pushUrl]) /* ── Run initial query if pre-filled from URL ────────────────────────────── */ useEffect(() => { if (initialQuery?.trim().length >= 2) { fetchResults(initialQuery.trim(), 1) } // eslint-disable-next-line react-hooks/exhaustive-deps }, []) const handleDeleted = useCallback((id) => { setResults((prev) => prev.filter((p) => p.id !== id)) }, []) const hasMore = meta ? meta.current_page < meta.last_page : false const noResults = searched && !loading && results.length === 0 const hasResults = results.length > 0 return (
{/* ── Main ─────────────────────────────────────────────────────── */}
{/* Header */}

Search Posts

Search by keywords, hashtags, or phrases

{/* Search box */}
{query && ( )}
{/* Skeletons while first load */} {loading && !hasResults && ( <>{Array.from({ length: 3 }).map((_, i) => )} )} {/* Idle / too short */} {!searched && !loading && (

Type at least 2 characters to search posts

)} {/* No results */} {noResults && (

No results

Nothing matched “{query}”. Try different keywords or a hashtag.

)} {/* Results meta */} {hasResults && meta && (

{meta.total.toLocaleString()} result{meta.total !== 1 ? 's' : ''} for{' '} “{query}”

)} {/* Post cards */} {results.map((post) => ( ))} {/* Loading more indicator */} {loading && hasResults && (
)} {/* Load more */} {!loading && hasMore && (
)}
{/* ── Sidebar ──────────────────────────────────────────────────── */}
) }