'use client'; import { useState, useEffect, useMemo, Suspense } from 'react'; import { useSearchParams } from 'next/navigation'; import SearchBar from '../components/SearchBar'; import ResultCard from '../components/ResultCard'; import SafetyBanner from '../components/SafetyBanner'; import FilterPanel from '../components/FilterPanel'; import SkeletonCard from '../components/SkeletonCard'; import ResultModal from '../components/ResultModal'; import ClarificationPrompt from '../components/ClarificationPrompt'; import useSearchHistory from '../hooks/useSearchHistory'; import { useToast } from '../contexts/ToastContext'; import { search } from '../api/client'; import { useGeolocation } from '../hooks/useGeolocation'; import './Home.css'; function SearchContent() { const [results, setResults] = useState([]); const [intent, setIntent] = useState(null); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [meta, setMeta] = useState(null); const [loadingMsg, setLoadingMsg] = useState('Parsing intent...'); const [hasSearched, setHasSearched] = useState(false); const [filters, setFilters] = useState({}); const [dynamicFilters, setDynamicFilters] = useState([]); const [selectedResult, setSelectedResult] = useState(null); const [scopeMessage, setScopeMessage] = useState(null); const [clarification, setClarification] = useState(null); const [easterEgg, setEasterEgg] = useState(null); const { addEntry, history } = useSearchHistory(); const { addToast } = useToast(); const searchParams = useSearchParams(); const { location: userLocation, error: locationError, isLoading: locationLoading, requestLocation, clearLocation } = useGeolocation(); useEffect(() => { const rerunQuery = searchParams.get('rerunQuery'); if (rerunQuery) { handleSearch(rerunQuery); } }, [searchParams]); const handleClarificationSubmit = (answer) => { if (clarification) { const context = { originalQuery: clarification.originalQuery, question: clarification.question, answer: answer }; setClarification(null); handleSearch(clarification.originalQuery, context); } }; const handleClarificationCancel = () => { setClarification(null); }; async function handleSearch(query, clarificationContext = null) { setLoading(true); setLoadingMsg('Searching...'); setError(null); setScopeMessage(null); setClarification(null); setEasterEgg(null); setHasSearched(true); const timeoutId = setTimeout(() => { setLoadingMsg('Scraping fresh data from the web (this may take 10-15s)...'); }, 3000); try { const data = await search(query, null, filters, userLocation, clarificationContext); clearTimeout(timeoutId); if (data.isOutOfScope) { setScopeMessage(data.scopeMessage); setResults([]); setLoading(false); return; } if (data.needsClarification) { setClarification({ originalQuery: query, question: data.clarificationQuestion }); setResults([]); setLoading(false); return; } setClarification(null); const res = data.results || []; setResults(res); setIntent(data.intent || null); setMeta(data.meta || null); setEasterEgg(data.easterEgg || null); setDynamicFilters(data.dynamicFilters || []); setFilters({}); addEntry(query, data.intent, res.length); } catch (err) { clearTimeout(timeoutId); const errorMsg = err.data?.error || err.message || 'Something went wrong'; setError(errorMsg); addToast(errorMsg, 'error'); setResults([]); } finally { setLoading(false); } } const filteredResults = useMemo(() => { let filtered = [...results]; dynamicFilters.forEach(schema => { const val = filters[schema.id]; if (!val) return; if (schema.type === 'range') { const max = parseInt(val, 10); filtered = filtered.filter(r => { const match = r.priceRange?.match(/([₹$£€])(\d+)/); return match ? parseInt(match[2], 10) <= max : true; }); } else if (schema.type === 'select') { if (val.length > 0) { filtered = filtered.filter(r => val.every(selectedOpt => { const optL = selectedOpt.toLowerCase(); const inFeatures = (r.features || []).some(f => f.toLowerCase().includes(optL)); const inName = r.name?.toLowerCase().includes(optL); const inSummary = r.reviewSummary?.toLowerCase().includes(optL); const inCat = r.category?.toLowerCase().includes(optL); return inFeatures || inName || inSummary || inCat; }) ); } } else if (schema.type === 'sort') { if (val === 'rating') { filtered.sort((a, b) => (b.rating === 'N/A' ? 0 : parseFloat(b.rating)) - (a.rating === 'N/A' ? 0 : parseFloat(a.rating))); } else if (val === 'price_low') { filtered.sort((a, b) => { const pa = parseInt(a.priceRange?.match(/([₹$£€])(\d+)/)?.[2] || '0', 10); const pb = parseInt(b.priceRange?.match(/([₹$£€])(\d+)/)?.[2] || '0', 10); if (!pa) return 1; if (!pb) return -1; return pa - pb; }); } } }); return filtered; }, [results, filters, dynamicFilters]); return (

AI that thinks
before it searches

Describe what you want naturally — RedThread interprets your intent, adapts to context, and finds results that actually match.

{!hasSearched && history.length > 0 && (
Your Recent Searches:
{history.slice(0, 3).map((entry) => ( ))}
)} {clarification && !loading && (
)}
{scopeMessage && !loading && (
💡

Platform Guidance

{scopeMessage}

)} {error && (
{error} {error.toLowerCase().includes('location') && !userLocation && ( )}
)} {intent && !error && (

Parsed Intent

AI Reasoning: {intent.reasoning} Category: {intent.category} {intent.location && ( Location: {intent.location} )} {intent.budget?.max && ( Budget: up to {intent.budget.currency}{intent.budget.max} )} {intent.occasion && ( Occasion: {intent.occasion} )}
)} {loading && (

{loadingMsg}

{[1, 2, 3, 4].map(i => )}
)} {easterEgg && !loading && (

"{easterEgg}"

— Kimi no Na wa (Your Name)
)} {!loading && hasSearched && results.length > 0 && (

Results

{meta && ( {filteredResults.length} of {meta.total} · {meta.source} )}
{filteredResults.map((r, i) => ( setSelectedResult(r)} /> ))}
{filteredResults.length === 0 && (

No results match your filters. Try adjusting them.

)}
)} {hasSearched && !loading && results.length === 0 && !error && (

No results found. Try a different query or location.

)} {selectedResult && ( setSelectedResult(null)} /> )}
); } export default function Home() { return (

Initializing RedThread...

}>
); }