109 lines
3.6 KiB
TypeScript
109 lines
3.6 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useCallback } from "react";
|
|
import { useRouter } from "next/navigation";
|
|
import { toast } from "sonner";
|
|
import { SearchCard } from "@/components/search/SearchCard";
|
|
import { LoadingCard } from "@/components/search/LoadingCard";
|
|
|
|
export default function SuchePage() {
|
|
const router = useRouter();
|
|
const [query, setQuery] = useState("");
|
|
const [region, setRegion] = useState("");
|
|
const [count, setCount] = useState(50);
|
|
const [loading, setLoading] = useState(false);
|
|
const [jobId, setJobId] = useState<string | null>(null);
|
|
|
|
function handleChange(field: "query" | "region" | "count", value: string | number) {
|
|
if (field === "query") setQuery(value as string);
|
|
if (field === "region") setRegion(value as string);
|
|
if (field === "count") setCount(value as number);
|
|
}
|
|
|
|
async function handleSubmit() {
|
|
if (!query.trim() || loading) return;
|
|
setLoading(true);
|
|
setJobId(null);
|
|
try {
|
|
const res = await fetch("/api/search", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ query: query.trim(), region: region.trim(), count }),
|
|
});
|
|
if (!res.ok) {
|
|
const err = await res.json() as { error?: string };
|
|
throw new Error(err.error || "Fehler beim Starten der Suche");
|
|
}
|
|
const data = await res.json() as { jobId: string };
|
|
setJobId(data.jobId);
|
|
} catch (err) {
|
|
const msg = err instanceof Error ? err.message : "Unbekannter Fehler";
|
|
toast.error(msg);
|
|
setLoading(false);
|
|
}
|
|
}
|
|
|
|
const handleDone = useCallback((total: number) => {
|
|
setLoading(false);
|
|
toast.success(`✓ ${total} Leads gefunden — Leadspeicher wird geöffnet`, {
|
|
duration: 3000,
|
|
});
|
|
setTimeout(() => {
|
|
router.push("/leadspeicher");
|
|
}, 1500);
|
|
}, [router]);
|
|
|
|
const handleError = useCallback(() => {
|
|
setLoading(false);
|
|
setJobId(null);
|
|
toast.error("Suche fehlgeschlagen. Bitte prüfe deine API-Einstellungen.");
|
|
}, []);
|
|
|
|
return (
|
|
<div
|
|
style={{
|
|
padding: "72px 120px",
|
|
maxWidth: 900,
|
|
margin: "0 auto",
|
|
}}
|
|
>
|
|
{/* Hero */}
|
|
<div className="relative rounded-2xl border border-[#1e1e2e] p-6 overflow-hidden mb-6"
|
|
style={{ background: "linear-gradient(135deg, rgba(59,130,246,0.08) 0%, rgba(139,92,246,0.08) 100%)" }}>
|
|
<div className="absolute inset-0" style={{ background: "linear-gradient(135deg, rgba(59,130,246,0.04) 0%, transparent 60%)" }} />
|
|
<div className="relative">
|
|
<div className="flex items-center gap-2 text-xs mb-2" style={{ color: "#3b82f6" }}>
|
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
|
|
<span>Lead-Suche</span>
|
|
</div>
|
|
<h1 style={{ fontSize: 22, fontWeight: 500, color: "#ffffff", margin: 0, marginBottom: 6 }}>
|
|
Leads finden
|
|
</h1>
|
|
<p style={{ fontSize: 13, color: "#9ca3af", margin: 0 }}>
|
|
Suchbegriff eingeben — wir finden passende Unternehmen mit Kontaktdaten.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Search Card */}
|
|
<SearchCard
|
|
query={query}
|
|
region={region}
|
|
count={count}
|
|
loading={loading}
|
|
onChange={handleChange}
|
|
onSubmit={handleSubmit}
|
|
/>
|
|
|
|
{/* Loading Card */}
|
|
{loading && jobId && (
|
|
<LoadingCard
|
|
jobId={jobId}
|
|
onDone={handleDone}
|
|
onError={handleError}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|