'use client' import { useEffect, useState } from 'react' import { useRouter } from 'next/navigation' import { Button } from '@/components/ui/button' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { Checkbox } from '@/components/ui/checkbox' import { Slider } from '@/components/ui/slider' import { Separator } from '@/components/ui/separator' import { ScrollArea } from '@/components/ui/scroll-area' import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/components/ui/collapsible' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table' import { Textarea } from '@/components/ui/textarea' import { Label } from '@/components/ui/label' import { Search, Loader2, ExternalLink, MessageSquare, Twitter, Users, HelpCircle, Filter, ChevronDown, ChevronUp, Target, Zap, AlertCircle, BarChart3, CheckCircle2, Eye, Copy } from 'lucide-react' import type { EnhancedProductAnalysis, Opportunity, PlatformConfig, SearchStrategy } from '@/lib/types' const STRATEGY_INFO: Record = { 'direct-keywords': { name: 'Direct Keywords', description: 'People looking for your product category' }, 'problem-pain': { name: 'Problem/Pain', description: 'People experiencing problems you solve' }, 'competitor-alternative': { name: 'Competitor Alternatives', description: 'People switching from competitors' }, 'how-to': { name: 'How-To/Tutorials', description: 'People learning about solutions' }, 'emotional-frustrated': { name: 'Frustration Posts', description: 'Emotional posts about pain points' }, 'comparison': { name: 'Comparisons', description: '"X vs Y" comparison posts' }, 'recommendation': { name: 'Recommendations', description: '"What do you use" requests' } } export default function OpportunitiesPage() { const router = useRouter() const [analysis, setAnalysis] = useState(null) const [platforms, setPlatforms] = useState([]) const [strategies, setStrategies] = useState([ 'direct-keywords', 'problem-pain', 'competitor-alternative' ]) const [intensity, setIntensity] = useState<'broad' | 'balanced' | 'targeted'>('balanced') const [isSearching, setIsSearching] = useState(false) const [opportunities, setOpportunities] = useState([]) const [generatedQueries, setGeneratedQueries] = useState([]) const [showQueries, setShowQueries] = useState(false) const [selectedOpportunity, setSelectedOpportunity] = useState(null) const [replyText, setReplyText] = useState('') const [stats, setStats] = useState(null) useEffect(() => { const stored = localStorage.getItem('productAnalysis') if (stored) { setAnalysis(JSON.parse(stored)) } else { router.push('/onboarding') } fetch('/api/opportunities') .then(r => r.json()) .then(data => setPlatforms(data.platforms)) }, [router]) const togglePlatform = (platformId: string) => { setPlatforms(prev => prev.map(p => p.id === platformId ? { ...p, enabled: !p.enabled } : p )) } const toggleStrategy = (strategy: SearchStrategy) => { setStrategies(prev => prev.includes(strategy) ? prev.filter(s => s !== strategy) : [...prev, strategy] ) } const executeSearch = async () => { if (!analysis) return setIsSearching(true) setOpportunities([]) try { const config = { platforms, strategies, intensity, maxResults: intensity === 'broad' ? 80 : intensity === 'balanced' ? 50 : 30 } const response = await fetch('/api/opportunities', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ analysis, config }) }) const data = await response.json() if (data.success) { setOpportunities(data.data.opportunities) setGeneratedQueries(data.data.queries) setStats(data.data.stats) } } catch (error) { console.error('Search error:', error) } finally { setIsSearching(false) } } const generateReply = (opp: Opportunity) => { const template = opp.softPitch ? `Hey, I saw your post about ${opp.matchedProblems[0] || 'your challenge'}. We faced something similar and ended up building ${analysis?.productName} specifically for this. Happy to share what worked for us.` : `Hi! I noticed you're looking for solutions to ${opp.matchedProblems[0]}. I work on ${analysis?.productName} that helps teams with this - specifically ${opp.matchedKeywords.slice(0, 2).join(' and ')}. Would love to show you how it works.` setReplyText(template) } const getIntentIcon = (intent: string) => { switch (intent) { case 'frustrated': return case 'comparing': return case 'learning': return default: return } } if (!analysis) return null return (
{/* Sidebar */}

Search Configuration

{/* Platforms */}
{platforms.map(platform => (
togglePlatform(platform.id)} />
))}
{/* Strategies */}
{(Object.keys(STRATEGY_INFO) as SearchStrategy[]).map(strategy => (
toggleStrategy(strategy)} />

{STRATEGY_INFO[strategy].description}

))}
{/* Intensity */}
setIntensity(v < 33 ? 'broad' : v < 66 ? 'balanced' : 'targeted')} max={100} step={50} />
Broad Targeted
{/* Main Content */}
{/* Header */}

Opportunity Finder

Discover potential customers for {analysis.productName}

{stats && (
{stats.opportunitiesFound}
Found
{stats.highRelevance}
High Quality
)}
{/* Generated Queries */} {generatedQueries.length > 0 && (
Generated Queries ({generatedQueries.length}) {showQueries ? : }
{generatedQueries.slice(0, 20).map((q, i) => (
{q.query}
))}
)} {/* Results Table */} {opportunities.length > 0 ? ( Platform Intent Score Post Actions {opportunities.slice(0, 50).map((opp) => ( {opp.platform}
{getIntentIcon(opp.intent)} {opp.intent}
= 0.8 ? 'bg-green-500/20 text-green-400' : opp.relevanceScore >= 0.6 ? 'bg-amber-500/20 text-amber-400' : 'bg-red-500/20 text-red-400'}> {Math.round(opp.relevanceScore * 100)}%

{opp.title}

{opp.snippet}

))}
) : isSearching ? (

Searching...

Scanning platforms for opportunities

) : (

Ready to Search

Select platforms and strategies, then click Find Opportunities

)}
{/* Detail Dialog */} setSelectedOpportunity(null)}> {selectedOpportunity && ( <>
= 0.8 ? 'bg-green-500/20 text-green-400' : selectedOpportunity.relevanceScore >= 0.6 ? 'bg-amber-500/20 text-amber-400' : 'bg-red-500/20 text-red-400'}> {Math.round(selectedOpportunity.relevanceScore * 100)}% Match {selectedOpportunity.platform} {selectedOpportunity.intent}
{selectedOpportunity.title} {selectedOpportunity.snippet}
{selectedOpportunity.matchedKeywords.length > 0 && (
{selectedOpportunity.matchedKeywords.map((kw, i) => ( {kw} ))}
)}

{selectedOpportunity.suggestedApproach}

{replyText && ( )}