feat: add working export buttons for Leads Finder (HTML download + CSV export)

- exportLeadsReport function: downloads HTML file or extracts table to CSV
- Inline export buttons in chat messages when leads data exists
- Canvas action bar export buttons for leads agent
- HTML export: downloads full leads-report.html
- CSV export: parses HTML table, extracts Name/Platform/Followers/Region/Bio/Link
This commit is contained in:
admin
2026-03-19 05:56:30 +00:00
Unverified
parent 4677246b4c
commit 4193839f7f

View File

@@ -937,6 +937,50 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
downloadSeoReport(seoAuditData, format); downloadSeoReport(seoAuditData, format);
}; };
const exportLeadsReport = (format: "html" | "csv") => {
const htmlContent = previewData?.data;
if (!htmlContent) return;
if (format === "html") {
const blob = new Blob([htmlContent], { type: "text/html" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "leads-report.html";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
} else {
// Extract table rows from HTML and convert to CSV
const parser = new DOMParser();
const doc = parser.parseFromString(htmlContent, "text/html");
const rows = doc.querySelectorAll("tbody tr");
if (rows.length === 0) return;
let csv = "Name,Platform,Followers,Region,Bio,Link\n";
rows.forEach((row) => {
const cells = row.querySelectorAll("td");
if (cells.length >= 7) {
const name = cells[1]?.textContent?.trim().replace(/,/g, ";") || "";
const platform = cells[2]?.textContent?.trim() || "";
const followers = cells[3]?.textContent?.trim() || "";
const region = cells[4]?.textContent?.trim().replace(/,/g, ";") || "";
const bio = cells[5]?.textContent?.trim().replace(/,/g, ";") || "";
const link = cells[6]?.querySelector("a")?.href || "";
csv += `"${name}","${platform}","${followers}","${region}","${bio}","${link}"\n`;
}
});
const blob = new Blob([csv], { type: "text/csv" });
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "leads-report.csv";
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
};
const clearHistory = () => { const clearHistory = () => {
updateActiveTab({ updateActiveTab({
@@ -1440,6 +1484,24 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
</Button> </Button>
</div> </div>
)} )}
{currentAgent === "leads" && previewData?.data && (
<div className="mt-2 flex gap-2 animate-in zoom-in-95 duration-300">
<Button
onClick={() => exportLeadsReport("html")}
variant="outline"
className="flex-1 bg-emerald-500/10 hover:bg-emerald-500/20 border-emerald-500/20 text-emerald-300 font-black uppercase text-[9px] tracking-wider py-3 rounded-xl min-w-0"
>
<Download className="h-3.5 w-3.5 mr-1" /> <span className="truncate">Export HTML</span>
</Button>
<Button
onClick={() => exportLeadsReport("csv")}
variant="outline"
className="flex-1 bg-blue-500/10 hover:bg-blue-500/20 border-blue-500/20 text-blue-300 font-black uppercase text-[9px] tracking-wider py-3 rounded-xl min-w-0"
>
<FileText className="h-3.5 w-3.5 mr-1" /> <span className="truncate">Export CSV</span>
</Button>
</div>
)}
</> </>
)} )}
{/* Inline SEO Export - always visible in chat when SEO data exists */} {/* Inline SEO Export - always visible in chat when SEO data exists */}
@@ -1461,6 +1523,25 @@ export default function AIAssist({ vibeMode = false }: { vibeMode?: boolean } =
</Button> </Button>
</div> </div>
)} )}
{/* Inline Leads Export - always visible in chat when leads data exists */}
{msg.role === "assistant" && msg.agent === "leads" && msg.preview?.data && (
<div className="mt-3 flex gap-2 animate-in zoom-in-95 duration-300">
<Button
onClick={() => { setPreviewData(msg.preview as any); setTimeout(() => exportLeadsReport("html"), 100); }}
variant="outline"
className="flex-1 bg-emerald-500/10 hover:bg-emerald-500/20 border-emerald-500/30 text-emerald-300 font-black uppercase text-[9px] tracking-wider py-2.5 rounded-xl min-w-0"
>
<Download className="h-3 w-3 mr-1.5" /> <span className="truncate">Export HTML</span>
</Button>
<Button
onClick={() => { setPreviewData(msg.preview as any); setTimeout(() => exportLeadsReport("csv"), 100); }}
variant="outline"
className="flex-1 bg-blue-500/10 hover:bg-blue-500/20 border-blue-500/30 text-blue-300 font-black uppercase text-[9px] tracking-wider py-2.5 rounded-xl min-w-0"
>
<FileText className="h-3 w-3 mr-1.5" /> <span className="truncate">Export CSV</span>
</Button>
</div>
)}
</div> </div>
{msg.role === "assistant" && isProcessing && i === aiAssistHistory.length - 1 && status && ( {msg.role === "assistant" && isProcessing && i === aiAssistHistory.length - 1 && status && (