import { useState } from "react"; import ReactMarkdown from "react-markdown"; import { DownloadIcon, FileTextIcon, CheckCircle2Icon, XCircleIcon, AlertTriangleIcon, PrinterIcon, ShieldCheckIcon, CalendarIcon, } from "lucide-react"; import type { ComplianceRow, AnalysisSummary } from "../App"; interface Step3Props { extracted: Record; category: string; compliance: Record; summary: AnalysisSummary; rows: ComplianceRow[]; narration: string; onReset: () => void; } const API_BASE = "/api"; export function Step3Report({ extracted, category, compliance, summary, rows, narration, onReset, }: Step3Props) { const [downloading, setDownloading] = useState(false); const [generating, setGenerating] = useState(false); const [reportReady, setReportReady] = useState(false); const [markdownPreview, setMarkdownPreview] = useState(null); const [error, setError] = useState(null); const productName = (extracted?.nama_produk || extracted?.product_name || "Produk Tidak Diketahui") as string; const producer = (extracted?.produsen || extracted?.manufacturer || "-") as string; const batchNo = (extracted?.batch || extracted?.nomor_batch || "-") as string; const testDate = (extracted?.tanggal_uji || extracted?.test_date || "-") as string; const labName = (extracted?.laboratorium || extracted?.lab || "-") as string; const today = new Date().toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }); const handleGenerateReport = async () => { setGenerating(true); setError(null); try { const res = await fetch(`${API_BASE}/report`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ extracted, category, compliance, narration }), }); if (!res.ok) { const err = await res.json().catch(() => ({ detail: "Gagal generate report." })); throw new Error(err.detail); } const data = await res.json(); setMarkdownPreview(data.markdown); setReportReady(data.pdfReady); } catch (err: unknown) { setError(err instanceof Error ? err.message : "Terjadi kesalahan."); } finally { setGenerating(false); } }; const handleDownload = async () => { setDownloading(true); try { const res = await fetch(`${API_BASE}/download`); if (!res.ok) throw new Error("PDF tidak tersedia."); const blob = await res.blob(); const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "laporan_compliance_bpom.pdf"; a.click(); URL.revokeObjectURL(url); } catch (err) { console.error("Download failed:", err); } finally { setTimeout(() => setDownloading(false), 1000); } }; const handlePrint = () => window.print(); const StatusBadge = ({ status }: { status: "PASS" | "FAIL" | "MISSING" }) => { if (status === "PASS") return ( PASS ); if (status === "FAIL") return ( FAIL ); return ( N/A ); }; const isCompliant = summary.fail === 0; const compliancePct = summary.compliancePct; return (
{/* Header */}

Laporan Final

Tinjau hasil analisis kepatuhan dan unduh laporan PDF.

{!reportReady ? ( ) : ( )}
{/* Error */} {error && (
⚠️ {error}
)} {/* Verdict Banner */}
{isCompliant ? : }

{isCompliant ? "Memenuhi Syarat — Siap Diajukan" : "Tidak Memenuhi Syarat — Perbaikan Diperlukan"}

{isCompliant ? `Semua parameter memenuhi standar BPOM. Produk siap untuk proses registrasi.` : `Produk memiliki ${summary.fail} parameter yang tidak memenuhi batas regulasi BPOM. Perbaikan formulasi diperlukan sebelum pengajuan registrasi.` }

{compliancePct}%

Kepatuhan

{/* Report Preview Card */}
{/* Report Header */}
Laporan Kepatuhan BPOM

{productName}

{producer}{batchNo !== "-" ? ` — Batch ${batchNo}` : ""}

{today}

Kategori: {category}

{/* Report Body */}
{/* Product Info */}

Informasi Produk

{[ { label: "Nama Produk", value: productName }, { label: "Produsen", value: producer }, { label: "Nomor Batch", value: batchNo }, { label: "Kategori BPOM", value: category }, { label: "Tanggal Uji", value: testDate }, { label: "Laboratorium", value: labName }, { label: "Tanggal Laporan", value: today }, ].map((item, i) => (

{item.label}

{item.value || "-"}

))}
{/* Executive Summary */}

Ringkasan Eksekutif

{[ { label: "Total Parameter", value: String(summary.total), icon: null, color: "text-slate-700" }, { label: "Parameter PASS", value: String(summary.pass), icon: , color: "text-[#16A34A]" }, { label: "Parameter FAIL", value: String(summary.fail), icon: , color: "text-[#DC2626]" }, { label: "Data Tidak Ada", value: String(summary.missing), icon: , color: "text-[#D97706]" }, { label: "Tingkat Kepatuhan", value: `${compliancePct}%`, icon: null, color: "text-[#1E3A5F]" }, { label: "Rekomendasi", value: isCompliant ? "Siap Diajukan" : "Perbaikan Formulasi", icon: null, color: isCompliant ? "text-[#16A34A]" : "text-[#D97706]" }, ].map((s, i) => (
{s.icon &&
{s.icon}
}

{s.label}

{s.value}

))}
{narration && (

, h2: ({node, ...props}: any) =>

, h3: ({node, ...props}: any) =>

, p: ({node, ...props}: any) =>

, strong: ({node, ...props}: any) => , ul: ({node, ...props}: any) =>

    , ol: ({node, ...props}: any) =>
      , li: ({node, ...props}: any) =>
    1. , }} > {narration}

)}
{/* Detail Results Table */}

Detail Hasil Uji

{rows.map((row, i) => ( ))}
Parameter Nilai Uji Batas BPOM Status
{row.param} {row.found} {row.threshold}
{/* Report Footer */}
Dibuat oleh BPOM Compliance AI System — bukan pengganti konsultasi regulasi resmi. v2.4.1 · {today}
{/* Markdown Preview (if generated) */} {markdownPreview && (

Preview Laporan (Markdown)

            {markdownPreview}
          
)} {/* New Analysis Button */}
); }