'use client'; import { useEffect, useState, Suspense } from 'react'; import { Plus, FileBarChart, Calendar, Target, TrendingUp, Clock } from 'lucide-react'; import dynamic from 'next/dynamic'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; // Lazy load TipTap report editor (~80KB) const ReportEditor = dynamic( () => import('@/components/reports/report-editor').then((m) => m.ReportEditor), { ssr: false, loading: () => (
Loading editor...
), } ); // Lazy load report templates const ReportTemplates = dynamic( () => import('@/components/reports/report-templates').then((m) => m.ReportTemplates), { ssr: false, loading: () => (
Loading templates...
), } ); interface Report { id: string; title: string; content: string; report_type: 'weekly' | 'monthly' | 'project' | 'habit' | 'custom'; date_range_start?: string; date_range_end?: string; domain: string; created: string; updated: string; } export default function ReportsPage() { const [reports, setReports] = useState([]); const [selectedReport, setSelectedReport] = useState(null); const [loading, setLoading] = useState(true); const [showTemplates, setShowTemplates] = useState(false); useEffect(() => { fetchReports(); }, []); async function fetchReports() { try { const response = await fetch('/api/reports?sort=-created'); if (response.ok) { const data = await response.json(); const reportsList = data.items || []; setReports(reportsList); if (reportsList.length > 0 && !selectedReport) { setSelectedReport(reportsList[0]); } } } catch (error) { console.error('Failed to fetch reports:', error); } finally { setLoading(false); } } async function createReport(overrides?: Partial) { try { const response = await fetch('/api/reports', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ title: 'Untitled report', content: '', report_type: 'custom', domain: 'personal', ...overrides, }), }); if (response.ok) { const newReport = await response.json(); setReports([newReport, ...reports]); setSelectedReport(newReport); setShowTemplates(false); } } catch (error) { console.error('Failed to create report:', error); } } async function updateReport(reportId: string, updates: Partial) { try { await fetch(`/api/reports/${reportId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updates), }); fetchReports(); } catch (error) { console.error('Failed to update report:', error); } } async function deleteReport(reportId: string) { if (!confirm('Are you sure you want to delete this report?')) return; try { await fetch(`/api/reports/${reportId}`, { method: 'DELETE' }); const updatedReports = reports.filter((r) => r.id !== reportId); setReports(updatedReports); if (selectedReport?.id === reportId) { setSelectedReport(updatedReports[0] || null); } } catch (error) { console.error('Failed to delete report:', error); } } function getReportTypeIcon(type: string) { switch (type) { case 'weekly': return ; case 'monthly': return ; case 'project': return ; case 'habit': return ; case 'custom': return ; default: return ; } } if (loading) { return

Loading reports...

; } if (showTemplates) { return (
Loading templates...
} > { createReport({ title: template.name, report_type: template.type, content: template.content, }); }} onCancel={() => setShowTemplates(false)} />
); } return (

Reports

Step back and see what changed.

{/* Reports list */}
{reports.length === 0 ? (

No reports yet

) : (
{reports.map((report) => ( ))}
)}
{/* Report editor */} {selectedReport ? (
setSelectedReport({ ...selectedReport, title: e.target.value }) } onBlur={() => updateReport(selectedReport.id, { title: selectedReport.title }) } className="w-full text-xl font-semibold outline-none" placeholder="Report title" />
{selectedReport.report_type} {selectedReport.domain} {selectedReport.date_range_start && selectedReport.date_range_end && ( {new Date(selectedReport.date_range_start).toLocaleDateString()} -{' '} {new Date(selectedReport.date_range_end).toLocaleDateString()} )}
Loading editor...
} > setSelectedReport({ ...selectedReport, content }) } onBlur={() => updateReport(selectedReport.id, { content: selectedReport.content }) } />
) : (

Select a report or create a new one

)}
); }