feat: Kundensuche – Progressbar, SERP-Supplement, Dedup, Löschen, Neu-Filter
- Progressbar geht nie mehr rückwärts (Math.min-Cap entfernt) - E-Mails-suchen-Phase wird immer kurz angezeigt bevor Fertig - SERP-Supplement startet automatisch wenn Maps < Zielanzahl liefert - Suchergebnisse bleiben nach Abschluss sichtbar (kein Redirect) - Dedup in leadVault strikt nach Domain (verhindert Duplikate) - isNew-Flag pro Result (Batch-Query gegen bestehende Vault-Domains) - Nur-neue-Filter + vorhanden-Badge in Suchergebnissen - Einzeln und Bulk löschen aus Suchergebnissen + Leadspeicher - Fehlermeldung zeigt echten API-Fehler (z.B. 402 Anymailfinder) - SERP-Supplement aus /api/search entfernt (LoadingCard übernimmt) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -35,33 +35,25 @@ export async function sinkLeadToVault(
|
||||
const email = lead.email || null;
|
||||
|
||||
if (domain) {
|
||||
// Check for exact duplicate (same domain + same email)
|
||||
if (email) {
|
||||
const exact = await prisma.lead.findFirst({
|
||||
where: { domain, email },
|
||||
});
|
||||
if (exact) return exact.id; // already exists, skip
|
||||
}
|
||||
// Strict domain dedup: one lead per domain
|
||||
const existing = await prisma.lead.findFirst({ where: { domain } });
|
||||
|
||||
// Check if same domain exists without email and we now have one
|
||||
const existing = await prisma.lead.findFirst({
|
||||
where: { domain, email: null },
|
||||
});
|
||||
|
||||
if (existing && email) {
|
||||
// Upgrade: fill in email + other missing fields
|
||||
await prisma.lead.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
email,
|
||||
contactName: lead.contactName || existing.contactName,
|
||||
contactTitle: lead.contactTitle || existing.contactTitle,
|
||||
linkedinUrl: lead.linkedinUrl || existing.linkedinUrl,
|
||||
phone: lead.phone || existing.phone,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
return existing.id;
|
||||
if (existing) {
|
||||
if (email && !existing.email) {
|
||||
// Upgrade: fill in email + other missing fields
|
||||
await prisma.lead.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
email,
|
||||
contactName: lead.contactName || existing.contactName,
|
||||
contactTitle: lead.contactTitle || existing.contactTitle,
|
||||
linkedinUrl: lead.linkedinUrl || existing.linkedinUrl,
|
||||
phone: lead.phone || existing.phone,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
return existing.id; // domain already exists → skip or upgraded
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,25 +99,27 @@ export async function sinkLeadsToVault(
|
||||
const email = lead.email || null;
|
||||
|
||||
if (domain) {
|
||||
if (email) {
|
||||
const exact = await prisma.lead.findFirst({ where: { domain, email } });
|
||||
if (exact) { skipped++; continue; }
|
||||
}
|
||||
// Strict domain dedup: one lead per domain
|
||||
const existing = await prisma.lead.findFirst({ where: { domain } });
|
||||
|
||||
const existing = await prisma.lead.findFirst({ where: { domain, email: null } });
|
||||
if (existing && email) {
|
||||
await prisma.lead.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
email,
|
||||
if (existing) {
|
||||
if (email && !existing.email) {
|
||||
// Upgrade: existing has no email, new one does → fill it in
|
||||
await prisma.lead.update({
|
||||
where: { id: existing.id },
|
||||
data: {
|
||||
email,
|
||||
contactName: lead.contactName || existing.contactName,
|
||||
contactTitle: lead.contactTitle || existing.contactTitle,
|
||||
linkedinUrl: lead.linkedinUrl || existing.linkedinUrl,
|
||||
phone: lead.phone || existing.phone,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
updated++;
|
||||
contactTitle: lead.contactTitle || existing.contactTitle,
|
||||
linkedinUrl: lead.linkedinUrl || existing.linkedinUrl,
|
||||
phone: lead.phone || existing.phone,
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
updated++;
|
||||
} else {
|
||||
skipped++; // domain already exists → skip
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +134,7 @@ export async function sinkLeadsToVault(
|
||||
linkedinUrl: lead.linkedinUrl || null,
|
||||
phone: lead.phone || null,
|
||||
address: lead.address || null,
|
||||
serpTitle: lead.serpTitle || null,
|
||||
serpTitle: lead.serpTitle || null,
|
||||
serpSnippet: lead.serpSnippet || null,
|
||||
serpRank: lead.serpRank ?? null,
|
||||
serpUrl: lead.serpUrl || null,
|
||||
|
||||
Reference in New Issue
Block a user