import React from "react"; import { Document, Page, Text, View } from "@react-pdf/renderer"; import { sharedStyles } from "../ui/sharedPdfStyles"; interface ThreatsSummaryPdfDocumentProps { threatsData: any[]; reportDateStr: string; } interface TableColumn { header: string; width: string; align?: "center" | "right" | "left"; cell: (row: any) => string | number; } function formatIndonesiaTime(dateStr: string | Date): string { if (!dateStr) return "Never"; try { const d = new Date(dateStr); return d.toLocaleString("id-ID", { timeZone: "Asia/Jakarta", day: "2-digit", month: "2-digit", year: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit", }) + " WIB"; } catch (e) { return String(dateStr); } } function RenderPdfTable({ title, columns, data }: { title: string; columns: TableColumn[]; data: any[] }) { return ( {title} {columns.map((col, idx) => ( {col.header} ))} {data.length === 0 ? ( No Data ) : ( data.map((row, rowIdx) => ( {columns.map((col, colIdx) => ( {col.cell(row)} ))} )) )} ); } export default function ThreatsSummaryPdfDocument({ threatsData, reportDateStr, }: ThreatsSummaryPdfDocumentProps) { const total = threatsData.length; const criticalHigh = threatsData.filter( (t) => { const s = (t.severity || "").toLowerCase(); return s.includes("high") || s.includes("critical"); } ).length; const medium = threatsData.filter( (t) => (t.severity || "").toLowerCase().includes("med") ).length; const lowInfo = total - criticalHigh - medium; // Group by threat type const typeCounts: { [key: string]: number } = {}; threatsData.forEach((t) => { const key = t.threat_type || "Unknown Alert"; typeCounts[key] = (typeCounts[key] || 0) + 1; }); const topTypes = Object.entries(typeCounts) .map(([type, count]) => ({ type, count })) .sort((a, b) => b.count - a.count) .slice(0, 10); // Group by source IP const ipCounts: { [key: string]: number } = {}; threatsData.forEach((t) => { const key = t.ip_address || "Unknown IP"; ipCounts[key] = (ipCounts[key] || 0) + 1; }); const topIps = Object.entries(ipCounts) .map(([ip, count]) => ({ ip, count })) .sort((a, b) => b.count - a.count) .slice(0, 10); // Sort incidents by severity (Critical > High > Medium > Low > Info) for PDF export const SEVERITY_RANK: Record = { critical: 0, high: 1, medium: 2, med: 2, low: 3, info: 4, }; const getSeverityRank = (sev: string): number => { const s = (sev || "").toLowerCase(); const match = Object.entries(SEVERITY_RANK).find(([k]) => s.includes(k)); return match ? match[1] : 5; }; const incidents = [...threatsData] .sort((a, b) => getSeverityRank(a.severity) - getSeverityRank(b.severity)) .slice(0, 50); return ( {/* Header */} Deep Package Inspection Security & Traffic Analytics Dashboard Threat Intelligence Summary Generated at: {reportDateStr} {/* Threat Counters */} Threat Metrics Summary CRITICAL / HIGH THREATS {criticalHigh} MEDIUM THREATS {medium} LOW / INFO THREATS {lowInfo} {/* Threat Types & Targets */} r.type }, { header: "Incidents", width: "30%", align: "right", cell: (r) => r.count }, ]} /> r.ip }, { header: "Incidents", width: "30%", align: "right", cell: (r) => r.count }, ]} /> {/* Detailed Incidents List */} r.detected_at ? formatIndonesiaTime(r.detected_at) : "N/A" }, { header: "Threat Type", width: "25%", cell: (r) => r.threat_type || "Security Alert" }, { header: "Severity", width: "15%", align: "center", cell: (r) => (r.severity || "Unknown").toUpperCase() }, { header: "Host IP", width: "15%", cell: (r) => r.ip_address || "—" }, { header: "Target Destination", width: "20%", cell: (r) => r.dst_ip || r.domain || "—" }, ]} /> ); }