'use client'; import { ArrowLeft, Download, Loader2, AlertTriangle, FileText, } from 'lucide-react'; import { useParams } from 'next/navigation'; import * as React from 'react'; import { ReportChartsGrid } from '@/components/reports/report-chart'; import { ReportStatusBadge } from '@/components/reports/report-status-badge'; import { ReportTypeBadge } from '@/components/reports/report-type-badge'; import { Button } from '@/components/ui/button'; import { Link } from '@/i18n/navigation'; import { useReport, useReportStatus } from '@/lib/hooks/use-reports'; // ─── Types for report content ────────────────────────── interface SectionData { title?: string; content?: string; data?: Record>; charts?: Record>; projects?: Array>; summary?: Record; } // ─── Component ───────────────────────────────────────── export default function BaoCaoDetailPage() { const params = useParams<{ id: string }>(); const reportId = params.id; const { data: report, isLoading, isError, refetch } = useReport(reportId); // Poll status while generating const isGenerating = report?.status === 'GENERATING'; const { data: statusData } = useReportStatus( isGenerating ? reportId : null, isGenerating, ); // Refetch full report when status changes to READY React.useEffect(() => { if (statusData?.status === 'READY' || statusData?.status === 'FAILED') { refetch(); } }, [statusData?.status, refetch]); if (isLoading) { return (
); } if (isError || !report) { return (

Không tìm thấy báo cáo

Báo cáo không tồn tại hoặc đã bị xóa.

); } const createdDate = new Date(report.createdAt).toLocaleDateString('vi-VN', { year: 'numeric', month: 'long', day: 'numeric', hour: '2-digit', minute: '2-digit', }); const sections = (report.content?.['sections'] as Record) ?? {}; return (
{/* Back link */} Danh sách báo cáo {/* Header */}

{report.title}

{createdDate}

{report.pdfUrl && ( )}
{/* Generating state */} {report.status === 'GENERATING' && (

Đang tạo báo cáo...

Hệ thống AI đang phân tích dữ liệu và tạo báo cáo. Quá trình này có thể mất 1-3 phút.

)} {/* Failed state */} {report.status === 'FAILED' && (

Tạo báo cáo thất bại

{report.errorMsg && (

{report.errorMsg}

)}
)} {/* Report content */} {report.status === 'READY' && report.content && (
{Object.entries(sections).map(([key, section]) => ( ))}
)}
); } // ─── Section renderer ────────────────────────────────── function ReportSection({ sectionKey, section, }: { sectionKey: string; section: SectionData; }) { const title = section.title || sectionKey; return (

{title}

{/* Narrative text */} {section.content && (
{section.content.split('\n').map((paragraph, i) => (

{paragraph}

))}
)} {/* Charts */} {section.charts && } {/* Data tables */} {section.data && } {/* Infrastructure projects */} {section.projects && section.projects.length > 0 && ( )} {/* Summary */} {section.summary && }
); } // ─── Data tables ─────────────────────────────────────── function DataTablesSection({ data, }: { data: Record>; }) { const entries = Object.entries(data).filter( ([, arr]) => Array.isArray(arr) && arr.length > 0, ); if (entries.length === 0) return null; return (
{entries.map(([key, items]) => { const label = key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()); return (
{items.map((item, i) => ( ))}
{label}
Kỳ Giá trị Đơn vị
{item.period} {typeof item.value === 'number' ? item.value.toLocaleString('vi-VN') : String(item.value)} {item.unit}
); })}
); } // ─── Projects table ──────────────────────────────────── function ProjectsTable({ projects, }: { projects: Array>; }) { return (
{projects.map((p, i) => ( ))}
Dự án Danh mục Trạng thái Vốn đầu tư (VND)
{String(p['name'] ?? '')} {String(p['category'] ?? '')} {String(p['status'] ?? '')} {p['investmentVND'] ? Number(p['investmentVND']).toLocaleString('vi-VN') : '—'}
); } // ─── Summary block ───────────────────────────────────── function SummaryBlock({ summary }: { summary: Record }) { return (
{Object.entries(summary).map(([key, val]) => { const label = key.replace(/_/g, ' ').replace(/\b\w/g, (c) => c.toUpperCase()); if (typeof val === 'number') { return (

{label}:{' '} {val.toLocaleString('vi-VN')}

); } if (typeof val === 'object' && val !== null) { return (

{label}:

    {Object.entries(val as Record).map(([k, v]) => (
  • {k}: {String(v)}
  • ))}
); } return null; })}
); }