'use client'; import { useEffect, useRef, useState, Suspense } from 'react'; import { Plus, FileBarChart, Calendar, Target, TrendingUp, Clock, Trash2 } from 'lucide-react'; import dynamic from 'next/dynamic'; import { toast } from 'sonner'; import { Button } from '@/components/ui/button'; import { Card } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog'; // 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); const [error, setError] = useState(null); const [saveStatus, setSaveStatus] = useState<'Saved' | 'Saving' | 'Failed'>('Saved'); const [domainMap, setDomainMap] = useState>(new Map()); const [reportToDelete, setReportToDelete] = useState(null); const [deleting, setDeleting] = useState(false); const pendingSave = useRef<{ id: string; updates: Partial } | null>(null); const saveTimer = useRef | null>(null); const saveVersion = useRef(0); useEffect(() => { fetchReports(); fetchDomains(); return () => { if (saveTimer.current) clearTimeout(saveTimer.current); }; }, []); async function fetchDomains() { try { const res = await fetch('/api/domains?sort=sort_order'); if (res.ok) { const data = await res.json(); const map = new Map(); for (const d of data.items || []) map.set(d.id, d.name); setDomainMap(map); } } catch {} } async function fetchReports() { setLoading(true); setError(null); try { const response = await fetch('/api/reports?sort=-created'); if (!response.ok) throw new Error('Unable to load reports.'); const data = await response.json(); const reportsList = data.items || []; setReports(reportsList); setSelectedReport((current) => current || reportsList[0] || null); } catch (error) { console.error('Failed to fetch reports:', error); setError('Unable to load reports. Please try again.'); } 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) throw new Error('Unable to create report.'); const newReport = await response.json(); setReports((current) => [newReport, ...current]); setSelectedReport(newReport); setShowTemplates(false); toast.success('Report created'); } catch (error) { console.error('Failed to create report:', error); toast.error('Unable to create report'); } } function scheduleSave(reportId: string, updates: Partial) { const version = ++saveVersion.current; pendingSave.current = { id: reportId, updates: { ...(pendingSave.current?.id === reportId ? pendingSave.current.updates : {}), ...updates }, }; if (saveTimer.current) clearTimeout(saveTimer.current); setSaveStatus('Saving'); saveTimer.current = setTimeout(() => { const save = pendingSave.current; pendingSave.current = null; if (save) updateReport(save.id, save.updates, version); }, 700); } async function updateReport(reportId: string, updates: Partial, version: number) { try { const response = await fetch(`/api/reports/${reportId}`, { method: 'PATCH', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(updates), }); if (!response.ok) throw new Error('Unable to save report.'); const updated = await response.json(); setReports((current) => current.map((report) => (report.id === reportId ? updated : report))); if (saveVersion.current === version) setSaveStatus('Saved'); } catch (error) { console.error('Failed to update report:', error); if (saveVersion.current === version) setSaveStatus('Failed'); toast.error('Unable to save report'); } } async function deleteReport() { if (!reportToDelete) return; if (pendingSave.current?.id === reportToDelete.id && saveTimer.current) { clearTimeout(saveTimer.current); pendingSave.current = null; } ++saveVersion.current; setDeleting(true); try { const response = await fetch(`/api/reports/${reportToDelete.id}`, { method: 'DELETE' }); if (!response.ok) throw new Error('Unable to delete report.'); setReports((current) => current.filter((report) => report.id !== reportToDelete.id)); setSelectedReport((selected) => selected?.id === reportToDelete.id ? reports.find((report) => report.id !== reportToDelete.id) || null : selected ); setReportToDelete(null); toast.success('Report deleted'); } catch (error) { console.error('Failed to delete report:', error); toast.error('Unable to delete report'); } finally { setDeleting(false); } } 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 (error) { return

{error}

; } 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 ? (
{ const title = e.target.value; setSelectedReport({ ...selectedReport, title }); scheduleSave(selectedReport.id, { title }); }} className="min-w-0 flex-1 text-xl font-semibold outline-none" placeholder="Report title" /> {saveStatus} !open && setReportToDelete(null)}> Delete {reportToDelete?.title}?This permanently deletes this report. Cancel{deleting ? 'Deleting...' : 'Delete report'}
{selectedReport.report_type} {domainMap.get(selectedReport.domain) || 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 }); scheduleSave(selectedReport.id, { content }); }} />
) : (

Select a report or create a new one

)}
); }