142 lines
4.8 KiB
TypeScript
142 lines
4.8 KiB
TypeScript
import { useState } from "react"
|
|
import type { NextPage } from "next"
|
|
import Head from "next/head"
|
|
import Link from "next/link"
|
|
|
|
const SearchPage: NextPage = () => {
|
|
const [query, setQuery] = useState("")
|
|
const [category, setCategory] = useState("")
|
|
const [riskLevel, setRiskLevel] = useState({ min: '', max: '' })
|
|
const [results, setResults] = useState<any[]>([])
|
|
const [loading, setLoading] = useState(false)
|
|
const [pagination, setPagination] = useState<any>(null)
|
|
|
|
const handleSearch = async (page = 1) => {
|
|
if (!query.trim()) return
|
|
|
|
setLoading(true)
|
|
const params = new URLSearchParams({
|
|
q: query,
|
|
page: page.toString(),
|
|
limit: '10'
|
|
})
|
|
|
|
if (category) params.set('category', category)
|
|
if (riskLevel.min) params.set('risk_level_min', riskLevel.min)
|
|
if (riskLevel.max) params.set('risk_level_max', riskLevel.max)
|
|
|
|
try {
|
|
const response = await fetch(`/api/search/advanced?${params}`)
|
|
const data = await response.json()
|
|
setResults(data.results || [])
|
|
setPagination(data.pagination)
|
|
} catch (error) {
|
|
console.error('Search error:', error)
|
|
}
|
|
setLoading(false)
|
|
}
|
|
|
|
return (
|
|
<div>
|
|
<Head>
|
|
<title>Advanced Search - Infohliadka</title>
|
|
</Head>
|
|
|
|
<div style={{ padding: '20px' }}>
|
|
<div style={{ marginBottom: '20px' }}>
|
|
<Link href="/">← Home</Link>
|
|
</div>
|
|
|
|
<h1>Advanced Search</h1>
|
|
|
|
<div style={{ marginBottom: '20px' }}>
|
|
<div style={{ marginBottom: '10px' }}>
|
|
<input
|
|
type="text"
|
|
placeholder="Search domains, titles, descriptions..."
|
|
value={query}
|
|
onChange={(e) => setQuery(e.target.value)}
|
|
style={{ width: '400px', padding: '8px', marginRight: '10px' }}
|
|
/>
|
|
<button onClick={() => handleSearch()} disabled={loading}>
|
|
{loading ? 'Searching...' : 'Search'}
|
|
</button>
|
|
</div>
|
|
|
|
<div>
|
|
<select
|
|
value={category}
|
|
onChange={(e) => setCategory(e.target.value)}
|
|
style={{ marginRight: '10px', padding: '5px' }}
|
|
>
|
|
<option value="">All Categories</option>
|
|
<option value="hoax">Hoax</option>
|
|
<option value="hate_speech">Hate Speech</option>
|
|
<option value="spam">Spam</option>
|
|
</select>
|
|
|
|
<input
|
|
type="number"
|
|
placeholder="Min Risk"
|
|
value={riskLevel.min}
|
|
onChange={(e) => setRiskLevel({...riskLevel, min: e.target.value})}
|
|
style={{ width: '80px', padding: '5px', marginRight: '5px' }}
|
|
min="1" max="5"
|
|
/>
|
|
<input
|
|
type="number"
|
|
placeholder="Max Risk"
|
|
value={riskLevel.max}
|
|
onChange={(e) => setRiskLevel({...riskLevel, max: e.target.value})}
|
|
style={{ width: '80px', padding: '5px' }}
|
|
min="1" max="5"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
{results.length > 0 && (
|
|
<div>
|
|
<h3>Search Results ({pagination?.total || 0})</h3>
|
|
{results.map((result) => (
|
|
<div key={result.id} style={{
|
|
border: '1px solid #ddd',
|
|
padding: '15px',
|
|
marginBottom: '10px',
|
|
backgroundColor: '#f9f9f9'
|
|
}}>
|
|
<h4>{result.domain}</h4>
|
|
<p><strong>Risk Level:</strong> {result.risk_level}/5</p>
|
|
<p><strong>Categories:</strong> {result.categories.join(', ')}</p>
|
|
{result.description && <p>{result.description}</p>}
|
|
<small>{new Date(result.created_at).toLocaleDateString()}</small>
|
|
</div>
|
|
))}
|
|
|
|
{pagination && pagination.totalPages > 1 && (
|
|
<div style={{ marginTop: '20px', textAlign: 'center' }}>
|
|
{Array.from({length: pagination.totalPages}, (_, i) => i + 1).map(page => (
|
|
<button
|
|
key={page}
|
|
onClick={() => handleSearch(page)}
|
|
disabled={page === pagination.page}
|
|
style={{
|
|
margin: '0 5px',
|
|
padding: '5px 10px',
|
|
backgroundColor: page === pagination.page ? '#007bff' : '#f8f9fa',
|
|
color: page === pagination.page ? 'white' : 'black',
|
|
border: '1px solid #ddd'
|
|
}}
|
|
>
|
|
{page}
|
|
</button>
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default SearchPage |