admin / Bid-Sentinel
publicBid Scrape and Tracking Application with AI Capability
Bid-Sentinel / bid-sentinel-v2 / frontend / src / utils / export.js
2348 B · main
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | import jsPDF from "jspdf"; import autoTable from "jspdf-autotable"; import { formatDate, formatValue } from "./format"; const COLUMNS = [ "Opportunity Name", "Buyer", "Fit %", "Certifications", "Published", "Closing", "Value (£)", "Duration", "Bid Status", "Outcome", "URL", ]; function toRow(t) { return [ t.title || "", t.buyer || "", t.fit_score == null ? "" : `${t.fit_score}%`, t.required_certs || "", formatDate(t.published_date), formatDate(t.closing_date), formatValue(t), t.duration || "", t.bid_status || "", t.outcome || "", t.url || "", ]; } export function buildCsvBlob(tenders) { const escape = (v) => `"${String(v ?? "").replace(/"/g, '""')}"`; const lines = [ COLUMNS.map(escape).join(","), ...tenders.map((t) => toRow(t).map(escape).join(",")), ]; return new Blob([lines.join("\r\n")], { type: "text/csv;charset=utf-8;" }); } export function exportCsv(tenders, filename = "bid-sentinel-tenders.csv") { triggerDownload(buildCsvBlob(tenders), filename); } function _buildPdfDoc(tenders) { const doc = new jsPDF({ orientation: "landscape", unit: "pt", format: "a4" }); doc.setFontSize(16); doc.setTextColor(11, 61, 145); doc.text("BID SENTINEL", 40, 36); doc.setFontSize(11); doc.setTextColor(71, 85, 105); doc.text("UK Cyber Security Tender Opportunities", 40, 52); doc.setFontSize(9); doc.text(`Generated ${new Date().toLocaleString("en-GB")}`, 40, 66); doc.setTextColor(0, 0, 0); autoTable(doc, { startY: 80, head: [COLUMNS.slice(0, 10)], // omit raw URL column in PDF for readability body: tenders.map((t) => toRow(t).slice(0, 10)), styles: { fontSize: 6.5, cellPadding: 2.5, overflow: "linebreak" }, headStyles: { fillColor: [11, 61, 145] }, columnStyles: { 0: { cellWidth: 150 } }, }); return doc; } export function buildPdfBlob(tenders) { return _buildPdfDoc(tenders).output("blob"); } export function exportPdf(tenders, filename = "bid-sentinel-tenders.pdf") { _buildPdfDoc(tenders).save(filename); } function triggerDownload(blob, filename) { const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } |