import assert from "node:assert/strict"; import test from "node:test"; import { getLeadBlacklistStatusLabel, getLeadContactStatusLabel, getLeadDuplicateStatusLabel, getLeadPriorityLabel, leadBlacklistStatusOptions, leadContactStatusOptions, leadDuplicateStatusOptions, leadPriorityOptions, dashboardKpis, dashboardNavigation, groupLeadFunnelCards, leadFunnelStages, pipelineStages, toLeadFunnelCard, reviewQueue, } from "../lib/dashboard-model"; type NavigationItem = { label: string; href: string }; type PipelineStage = { title: string; count: number }; type ReviewQueueItem = { title: string }; test("dashboardNavigation contains the expected sidebar routes in order", () => { assert.deepEqual( dashboardNavigation.map((item: NavigationItem) => [item.label, item.href]), [ ["Übersicht", "/dashboard"], ["Kampagnen", "/dashboard/campaigns"], ["Leads", "/dashboard/leads"], ["Audits", "/dashboard/audits"], ["Review", "/dashboard/outreach"], ["Analytics", "/dashboard/analytics"], ["Sperrliste", "/dashboard/blacklist"], ["Einstellungen", "/dashboard/settings"], ], ); }); test("pipelineStages keep the first-screen workflow focused on pipeline overview", () => { assert.deepEqual( pipelineStages.map((stage: PipelineStage) => stage.title), ["Kampagnen", "Lead-Recherche", "Audit-Freigabe", "Outreach"], ); assert.equal( pipelineStages.every((stage: PipelineStage) => stage.count >= 0), true, ); }); test("leadFunnelStages expose the agreed German funnel columns", () => { assert.deepEqual( leadFunnelStages.map((stage) => stage.title), [ "Kontakt fehlt", "Audit bereit", "Freigabe offen", "Kontaktiert", "Follow-up", "Zurückgestellt", ], ); }); test("toLeadFunnelCard exposes scan data and derives missing contact next action", () => { const card = toLeadFunnelCard({ id: "lead-1", companyName: "Malerbetrieb Klein", niche: "Maler", city: "Freiburg", postalCode: "79098", priority: "high", contactStatus: "missing_contact", blacklistStatus: "clear", }); assert.equal(card.stageId, "missing_contact"); assert.equal(card.company, "Malerbetrieb Klein"); assert.equal(card.niche, "Maler"); assert.equal(card.location, "79098 Freiburg"); assert.equal(card.priorityLabel, "Hoch"); assert.equal(card.contactStatusLabel, "Kontakt fehlt"); assert.equal(card.nextAction, "Kontaktquelle recherchieren"); }); test("groupLeadFunnelCards derives review, follow-up, and deferred columns without schema migration", () => { const groups = groupLeadFunnelCards([ { id: "lead-review", companyName: "Physio am Park", city: "Freiburg", priority: "medium", contactStatus: "outreach_ready", blacklistStatus: "clear", outreach: { approvalStatus: "draft", sendStatus: "not_sent", responseStatus: "none", salesStatus: "follow_up_planned", }, }, { id: "lead-follow-up", companyName: "Tischlerei Weber", city: "Emmendingen", priority: "medium", contactStatus: "contacted", blacklistStatus: "clear", outreach: { approvalStatus: "approved", sendStatus: "sent", responseStatus: "follow_up_needed", salesStatus: "follow_up_planned", }, }, { id: "lead-replied", companyName: "Salon Licht", city: "Freiburg", priority: "low", contactStatus: "replied", blacklistStatus: "clear", }, { id: "lead-defer", companyName: "Cafe Morgen", city: "Basel", priority: "defer", contactStatus: "new", blacklistStatus: "clear", }, ]); assert.deepEqual( groups.map((group) => [group.stage.id, group.cards.map((card) => card.id)]), [ ["missing_contact", []], ["audit_ready", []], ["review_open", ["lead-review"]], ["contacted", ["lead-replied"]], ["follow_up", ["lead-follow-up"]], ["deferred", ["lead-defer"]], ], ); }); test("groupLeadFunnelCards keeps approved unsent outreach in the review-open funnel", () => { const groups = groupLeadFunnelCards([ { id: "lead-approved-unsent", companyName: "Optik Meyer", city: "Freiburg", priority: "medium", contactStatus: "new", blacklistStatus: "clear", outreach: { approvalStatus: "approved", sendStatus: "not_sent", responseStatus: "none", salesStatus: "follow_up_planned", }, }, ]); assert.deepEqual( groups.map((group) => [group.stage.id, group.cards.map((card) => card.id)]), [ ["missing_contact", []], ["audit_ready", []], ["review_open", ["lead-approved-unsent"]], ["contacted", []], ["follow_up", []], ["deferred", []], ], ); }); test("toLeadFunnelCard maps blocked priority to deferred stage with blocker label", () => { const card = toLeadFunnelCard({ id: "lead-blocked", companyName: "Sperr Beispiel", city: "Freiburg", priority: "blocked", contactStatus: "new", blacklistStatus: "blocked", }); assert.equal(card.stageId, "deferred"); assert.equal(card.priorityLabel, "Gesperrt"); assert.equal(card.nextAction, "Zurückstellung prüfen"); }); test("dashboard-model exposes stable lead label helpers for UI mapping", () => { assert.deepEqual(leadPriorityOptions, [ "high", "medium", "low", "defer", "blocked", ]); assert.equal(getLeadPriorityLabel("high"), "Hoch"); assert.equal(getLeadContactStatusLabel("missing_contact"), "Kontakt fehlt"); assert.equal(getLeadBlacklistStatusLabel("blocked"), "Gesperrt"); }); test("dashboard-model exposes duplicate status options and labels", () => { assert.deepEqual(leadDuplicateStatusOptions, [ "unchecked", "unique", "possible_duplicate", "duplicate", ]); assert.equal(getLeadDuplicateStatusLabel("duplicate"), "Duplikat"); }); test("dashboard-model exposes contact status options for lead review controls", () => { assert.equal(leadContactStatusOptions[1], "missing_contact"); assert.equal(leadBlacklistStatusOptions.length, 2); }); test("dashboardKpis and reviewQueue expose the above-the-fold dashboard summary", () => { assert.equal(dashboardKpis.length, 4); assert.equal(reviewQueue.length, 3); assert.equal( reviewQueue.some((item: ReviewQueueItem) => item.title.includes("Audit-Freigabe"), ), true, ); });