From 6264ebf786024e57e0d6840a85e9734d739c3295 Mon Sep 17 00:00:00 2001 From: TimoUttenweiler Date: Wed, 1 Apr 2026 10:56:30 +0200 Subject: [PATCH] feat: Alle/Nur-neue Tabs + Option Nur neue Leads speichern MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Suchergebnis-Filter als Tabs: [Alle (46)] [Nur neue (X)] — beide klickbar - Checkbox "Nur neue Leads speichern" erscheint vor der Suche - Bei aktivierter Option: nach Abschluss werden vorhandene Leads automatisch aus dem Leadspeicher gelöscht, Toast zeigt Bilanz Co-Authored-By: Claude Sonnet 4.6 --- app/suche/page.tsx | 102 +++++++++++++++++++++++++++++++++------------ 1 file changed, 76 insertions(+), 26 deletions(-) diff --git a/app/suche/page.tsx b/app/suche/page.tsx index 8faac7e..edb0202 100644 --- a/app/suche/page.tsx +++ b/app/suche/page.tsx @@ -17,6 +17,7 @@ export default function SuchePage() { const [selected, setSelected] = useState>(new Set()); const [deleting, setDeleting] = useState(false); const [onlyNew, setOnlyNew] = useState(false); + const [saveOnlyNew, setSaveOnlyNew] = useState(false); function handleChange(field: "query" | "region" | "count", value: string | number) { if (field === "query") setQuery(value as string); @@ -32,6 +33,7 @@ export default function SuchePage() { setSearchDone(false); setSelected(new Set()); setOnlyNew(false); + // saveOnlyNew intentionally kept — user setting persists across searches try { const res = await fetch("/api/search", { method: "POST", @@ -51,16 +53,33 @@ export default function SuchePage() { } } - const handleDone = useCallback((result: LeadResult[], warning?: string) => { + const handleDone = useCallback(async (result: LeadResult[], warning?: string) => { setLoading(false); setLeads(result); setSearchDone(true); + + // Auto-delete existing (non-new) leads from vault if "Nur neue speichern" is active + const existingIds = result.filter(l => !l.isNew).map(l => l.id); + if (saveOnlyNew && existingIds.length > 0) { + try { + await fetch("/api/leads/delete-from-results", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ resultIds: existingIds }), + }); + // Mark them as deleted in local state (isNew stays false, they remain visible but are gone from vault) + } catch { /* silent — vault cleanup best-effort */ } + } + + const newCount = result.filter(l => l.isNew).length; if (warning) { toast.warning(`${result.length} Unternehmen gefunden — E-Mail-Anreicherung fehlgeschlagen: ${warning}`, { duration: 6000 }); + } else if (saveOnlyNew && existingIds.length > 0) { + toast.success(`✓ ${newCount} neue Leads gespeichert, ${existingIds.length} bereits vorhandene verworfen`, { duration: 5000 }); } else { toast.success(`✓ ${result.length} Leads gefunden und im Leadspeicher gespeichert`, { duration: 4000 }); } - }, []); + }, [saveOnlyNew]); async function handleDelete(ids: string[]) { if (!ids.length || deleting) return; @@ -127,6 +146,29 @@ export default function SuchePage() { onSubmit={handleSubmit} /> + {/* Save option */} + {!loading && !searchDone && ( + + )} + {/* Loading Card */} {loading && jobId && ( - {/* Nur neue Filter */} - + {/* Filter tabs */} +
+ {[ + { label: `Alle (${leads.length})`, value: false }, + { label: `Nur neue (${newCount})`, value: true }, + ].map(tab => ( + + ))} +