File size: 2,724 Bytes
dd4a03a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | import { useCallback, useState } from 'react'
import type { FormEvent } from 'react'
import { scrapeAndIndex } from '../api/client.ts'
import { useSession } from '../context/SessionContext.tsx'
import { useToast } from './shared/Toast.tsx'
import Loading from './shared/Loading.tsx'
import './web.css'
interface WebImportViewProps {
onIndexed: () => void
}
export default function WebImportView({ onIndexed }: WebImportViewProps) {
const [url, setUrl] = useState('')
const [isSubmitting, setIsSubmitting] = useState(false)
const [result, setResult] = useState<{ message: string; type: 'success' | 'error' } | null>(null)
const { sessionId } = useSession()
const { showToast } = useToast()
const handleSubmit = useCallback(
async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault()
if (!url.trim()) return
setIsSubmitting(true)
setResult(null)
try {
const res = await scrapeAndIndex({ url: url.trim(), session_id: sessionId })
setResult({ message: res.message, type: 'success' })
showToast(res.message, 'success')
setUrl('')
onIndexed()
} catch (err) {
const message = err instanceof Error ? err.message : 'Scraping failed'
setResult({ message, type: 'error' })
showToast(message, 'error')
} finally {
setIsSubmitting(false)
}
},
[url, sessionId, showToast, onIndexed],
)
return (
<div className="view-container active">
<div className="view-header">
<h2 className="view-title">Import from Web</h2>
<p className="view-description">Extract and index content from any webpage</p>
</div>
<div className="content-card">
<form className="web-form" onSubmit={handleSubmit}>
<div className="input-group">
<span className="input-icon">🔗</span>
<input
type="url"
className="input-field"
placeholder="https://example.com/article"
value={url}
onChange={(e) => setUrl(e.target.value)}
required
/>
</div>
<button type="submit" className="btn-primary btn-large" disabled={isSubmitting}>
{isSubmitting ? (
<>
<Loading />
<span>Fetching…</span>
</>
) : (
<>
<span>Fetch & Index Content</span>
<span className="btn-arrow">→</span>
</>
)}
</button>
</form>
{result && (
<div className={`result-message show ${result.type}`}>{result.message}</div>
)}
</div>
</div>
)
}
|