← back to Goodquestion
src/components/search/SearchForm.tsx
348 lines
'use client'
import { useState } from 'react'
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'
import { Badge } from '@/components/ui/badge'
import { Search, MapPin, Briefcase, Navigation } from 'lucide-react'
interface SearchFormProps {
onSearch: (data: SearchFormData) => void
isLoading?: boolean
}
export interface SearchFormData {
location: string
businessType: string
radiusMiles: number
capitalOnHand?: number
searchMode?: 'single' | 'opportunities'
}
const topTrendingIdeas = [
{ business: 'AI-powered SaaS startup', location: 'San Francisco, CA', description: 'Build the next unicorn with GPT wrappers' },
{ business: 'Craft Coffee Roastery', location: 'Austin, TX', description: 'Single-origin artisan beans for hipsters' },
{ business: 'Ghost Kitchen (Cloud Kitchen)', location: 'Miami, FL', description: 'Virtual restaurants, real profits' },
{ business: 'Electric Vehicle Charging Station', location: 'Los Angeles, CA', description: 'Capitalize on the EV revolution' },
{ business: 'Premium Pet Care & Grooming', location: 'Seattle, WA', description: 'Pamper those fur babies' },
]
export function SearchForm({ onSearch, isLoading = false }: SearchFormProps) {
const [location, setLocation] = useState('')
const [businessType, setBusinessType] = useState('')
const [radiusMiles, setRadiusMiles] = useState(10)
const [capitalOnHand, setCapitalOnHand] = useState('')
const [showSuggestions, setShowSuggestions] = useState(false)
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault()
// If both fields are empty, show suggestions
if (!location.trim() && !businessType.trim()) {
setShowSuggestions(true)
return
}
// If location is provided but no business type, find opportunities
if (location.trim() && !businessType.trim()) {
onSearch({
location: location.trim(),
businessType: '',
radiusMiles,
capitalOnHand: capitalOnHand ? parseInt(capitalOnHand) : undefined,
searchMode: 'opportunities',
})
return
}
// Use defaults if location is empty
const finalLocation = location.trim() || 'San Francisco, CA'
const finalBusinessType = businessType.trim()
onSearch({
location: finalLocation,
businessType: finalBusinessType,
radiusMiles,
capitalOnHand: capitalOnHand ? parseInt(capitalOnHand) : undefined,
searchMode: 'single',
})
}
const handleFindOpportunities = () => {
if (!location.trim()) {
alert('Please enter a location to search for opportunities')
return
}
if (!capitalOnHand || parseInt(capitalOnHand) <= 0) {
alert('Please enter your available capital amount')
return
}
onSearch({
location: location.trim(),
businessType: '',
radiusMiles,
capitalOnHand: parseInt(capitalOnHand),
searchMode: 'opportunities',
})
}
const handleSurprise = (idea: typeof topTrendingIdeas[0]) => {
setLocation(idea.location)
setBusinessType(idea.business)
setShowSuggestions(false)
onSearch({
location: idea.location,
businessType: idea.business,
radiusMiles,
})
}
const exampleBusinessTypes = [
'Coffee Shop',
'Restaurant',
'Retail Store',
'Gym/Fitness',
'Bakery',
'Salon',
'Tech Startup',
'Consulting',
]
return (
<Card className="w-full">
<CardHeader>
<CardTitle className="flex items-center gap-2 text-2xl">
<Search className="h-6 w-6" />
Search Business Ideas in Your Area
</CardTitle>
<CardDescription>
Enter your location and business idea to get an AI-powered SWOT analysis
</CardDescription>
</CardHeader>
<CardContent>
<form onSubmit={handleSubmit} className="space-y-6">
{/* Location Input */}
<div className="space-y-2">
<label
htmlFor="location"
className="flex items-center gap-2 text-sm font-medium"
>
<MapPin className="h-4 w-4" />
Location (City, State)
</label>
<input
id="location"
type="text"
value={location}
onChange={(e) => setLocation(e.target.value)}
placeholder="e.g., Portland, OR (leave blank for San Francisco, CA)"
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
/>
<p className="text-xs text-muted-foreground">
Leave blank to analyze the best trending location
</p>
</div>
{/* Business Type Input */}
<div className="space-y-2">
<label
htmlFor="businessType"
className="flex items-center gap-2 text-sm font-medium"
>
<Briefcase className="h-4 w-4" />
Business Idea or Occupation
</label>
<input
id="businessType"
type="text"
value={businessType}
onChange={(e) => setBusinessType(e.target.value)}
placeholder="e.g., Specialty Coffee Roastery (leave blank for AI SaaS)"
className="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
/>
<div className="flex flex-wrap gap-2 mt-2">
{exampleBusinessTypes.map((type) => (
<Badge
key={type}
variant="outline"
className="cursor-pointer hover:bg-blue-50 transition-colors"
onClick={() => setBusinessType(type)}
>
{type}
</Badge>
))}
</div>
<p className="text-xs text-muted-foreground">
Click a suggestion, type your own, or leave blank for best AI idea
</p>
</div>
{/* Radius Input */}
<div className="space-y-2">
<label
htmlFor="radius"
className="flex items-center gap-2 text-sm font-medium"
>
<Navigation className="h-4 w-4" />
Search Radius: {radiusMiles} miles
</label>
<div className="flex items-center gap-4">
<input
id="radius"
type="range"
min="1"
max="50"
step="1"
value={radiusMiles}
onChange={(e) => setRadiusMiles(parseInt(e.target.value))}
className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-blue-500"
/>
<div className="text-sm font-medium bg-blue-50 px-3 py-1 rounded-lg min-w-[60px] text-center">
{radiusMiles} mi
</div>
</div>
<div className="flex justify-between text-xs text-muted-foreground">
<span>1 mile</span>
<span>50 miles</span>
</div>
<p className="text-xs text-muted-foreground">
Search for competitors and opportunities within this radius
</p>
</div>
{/* Capital on Hand Input */}
<div className="space-y-2">
<label
htmlFor="capital"
className="flex items-center gap-2 text-sm font-medium"
>
<Briefcase className="h-4 w-4" />
Capital on Hand (Optional)
</label>
<div className="relative">
<span className="absolute left-4 top-3 text-gray-500">$</span>
<input
id="capital"
type="number"
value={capitalOnHand}
onChange={(e) => setCapitalOnHand(e.target.value)}
placeholder="25000"
min="0"
step="1000"
className="w-full pl-8 pr-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none transition-all"
/>
</div>
<p className="text-xs text-muted-foreground">
Enter your available capital to find opportunities that match your budget
</p>
</div>
{/* Submit Buttons */}
<div className="space-y-3">
{/* Regular Analysis Button */}
<button
type="submit"
disabled={isLoading}
className="w-full bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 text-white font-semibold py-4 px-6 rounded-lg transition-all duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
>
{isLoading ? (
<>
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div>
Analyzing...
</>
) : (
<>
<Search className="h-5 w-5" />
{!location.trim() && !businessType.trim() ? 'Show Top 5 Trending Ideas' : 'Analyze Business Opportunity'}
</>
)}
</button>
{/* Find Opportunities Button */}
<button
type="button"
onClick={handleFindOpportunities}
disabled={isLoading}
className="w-full bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-700 hover:to-emerald-700 disabled:bg-gray-400 text-white font-semibold py-4 px-6 rounded-lg transition-all duration-200 flex items-center justify-center gap-2 shadow-lg hover:shadow-xl"
>
<MapPin className="h-5 w-5" />
Find Top 10 Opportunities in My Area
</button>
</div>
{/* Top 5 Suggestions Modal */}
{showSuggestions && (
<div className="fixed inset-0 bg-black/60 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-xl shadow-2xl max-w-3xl w-full max-h-[90vh] overflow-y-auto">
<div className="p-6 border-b sticky top-0 bg-white">
<h2 className="text-2xl font-bold text-gray-900">🔥 Top 5 Trending Business Ideas</h2>
<p className="text-sm text-gray-600 mt-1">Click any idea to analyze it, or close to enter your own</p>
</div>
<div className="p-6 space-y-4">
{topTrendingIdeas.map((idea, index) => (
<button
key={index}
onClick={() => handleSurprise(idea)}
className="w-full text-left p-5 border-2 border-gray-200 rounded-lg hover:border-blue-500 hover:bg-blue-50 transition-all duration-200 group"
>
<div className="flex items-start justify-between">
<div className="flex-1">
<div className="flex items-center gap-3 mb-2">
<span className="text-2xl font-bold text-blue-600 group-hover:scale-110 transition-transform">
#{index + 1}
</span>
<h3 className="text-lg font-bold text-gray-900">{idea.business}</h3>
</div>
<p className="text-sm text-gray-600 mb-2">{idea.description}</p>
<div className="flex items-center gap-2 text-sm text-gray-500">
<MapPin className="h-4 w-4" />
{idea.location}
</div>
</div>
<div className="ml-4 text-blue-600 group-hover:translate-x-1 transition-transform">
→
</div>
</div>
</button>
))}
</div>
<div className="p-6 border-t bg-gray-50 flex gap-3">
<button
onClick={() => setShowSuggestions(false)}
className="flex-1 bg-gray-200 hover:bg-gray-300 text-gray-800 font-semibold py-3 px-6 rounded-lg transition-all duration-200"
>
Close
</button>
<button
onClick={() => {
const randomIdea = topTrendingIdeas[Math.floor(Math.random() * topTrendingIdeas.length)]
handleSurprise(randomIdea)
}}
className="flex-1 bg-gradient-to-r from-purple-600 to-pink-600 hover:from-purple-700 hover:to-pink-700 text-white font-semibold py-3 px-6 rounded-lg transition-all duration-200 shadow-lg hover:shadow-xl"
>
🎲 Surprise Me!
</button>
</div>
</div>
</div>
)}
{/* Help Text */}
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4 text-sm">
<p className="font-medium text-blue-900 mb-1">How it works:</p>
<ol className="list-decimal list-inside space-y-1 text-blue-800">
<li>Enter your target location and business idea</li>
<li>AI analyzes local competitors, demographics, and market data</li>
<li>Get a comprehensive SWOT analysis with visualizations</li>
<li>Review action plan and income projections</li>
</ol>
</div>
</form>
</CardContent>
</Card>
)
}