import { useState, type ComponentType } from 'react'; import { toast } from 'sonner'; import { Database, Download, FileSpreadsheet, FileJson, AlertTriangle, CheckCircle2, XCircle, Loader2 } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { cn, errMessage } from '@/lib/utils'; import { downloadFile } from '@/lib/download'; import { SectionCard, type SectionCardProps } from './dataShared'; function ExportCard({ icon: Icon, title, description, filename, endpoint }: { icon: ComponentType<{ className?: string }>; title: string; description: string; filename: string; endpoint: string; }) { const [loading, setLoading] = useState(false); const handleDownload = async () => { setLoading(true); try { await downloadFile(endpoint, filename); toast.success(`${title} downloaded.`); } catch (err) { toast.error(errMessage(err, 'Download failed.')); } finally { setLoading(false); } }; return (

{title}

{description}

); } // Filtered payments export: current year by default, or a custom date range, as CSV or JSON. function PaymentsExport() { const [from, setFrom] = useState(''); const [to, setTo] = useState(''); const [format, setFormat] = useState('csv'); const [loading, setLoading] = useState(false); const handle = async () => { if ((from && !to) || (!from && to)) { toast.error('Enter both From and To dates, or leave both empty.'); return; } if (from && to && from > to) { toast.error('“From” must be on or before “To”.'); return; } const params = new URLSearchParams({ format }); if (from && to) { params.set('from', from); params.set('to', to); } setLoading(true); try { await downloadFile(`/api/export?${params.toString()}`, `bills.${format === 'json' ? 'json' : 'csv'}`); toast.success('Payments exported.'); } catch (err) { toast.error(errMessage(err, 'Export failed.')); } finally { setLoading(false); } }; return (

Payments export

Just your payment records — filter by date and choose a format. Leave dates empty for the current year.

setFrom(e.target.value)} className="mt-1 h-9 w-38" />
setTo(e.target.value)} className="mt-1 h-9 w-38" />
Format
{['csv', 'json'].map(f => ( ))}
); } export default function DownloadMyDataSection({ cardProps = {} }: { cardProps?: Partial }) { return (

Exports may contain sensitive account metadata (website URLs, usernames, account info). Store exported files securely and avoid sharing them unencrypted.

What's included

    {['Bills','Payments','Categories','Monthly bill state','Monthly starting amounts','History ranges','Notes','Export metadata'].map(i => (
  • {i}
  • ))}

What's not included

    {['Passwords','Sessions','Admin settings','Server configuration',"Other users' data",'Full system backup files'].map(i => (
  • {i}
  • ))}
); }