import React, { useState, useEffect, useCallback } from 'react'; import { toast } from 'sonner'; import { api } from '@/api'; import { cn } from '@/lib/utils'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; import BankSyncSection from '@/components/data/BankSyncSection'; import BillRulesManager from '@/components/BillRulesManager'; import ImportTransactionCsvSection from '@/components/data/ImportTransactionCsvSection'; import TransactionMatchingSection from '@/components/data/TransactionMatchingSection'; import ImportSpreadsheetSection from '@/components/data/ImportSpreadsheetSection'; import ImportMyDataSection from '@/components/data/ImportMyDataSection'; import SeedDemoDataSection from '@/components/data/SeedDemoDataSection'; import DownloadMyDataSection from '@/components/data/DownloadMyDataSection'; import ImportHistorySection from '@/components/data/ImportHistorySection'; const DATA_TAB_STORAGE_KEY = 'billtracker:data.activeTab'; const DATA_TABS = [ { id: 'sync', label: 'Sync & Match', description: 'Bank connections, synced transactions, and CSV transaction imports.', }, { id: 'import', label: 'Import Data', description: 'Bring in spreadsheet history, restore an app export, or seed demo data.', }, { id: 'export', label: 'Export & History', description: 'Download your data and review previous import activity.', }, ]; function useStoredTab() { const [activeTab, setActiveTabState] = useState(() => { if (typeof window === 'undefined') return DATA_TABS[0].id; const stored = window.localStorage.getItem(DATA_TAB_STORAGE_KEY); return DATA_TABS.some(tab => tab.id === stored) ? stored : DATA_TABS[0].id; }); const setActiveTab = useCallback((tab) => { setActiveTabState(tab); if (typeof window !== 'undefined') { window.localStorage.setItem(DATA_TAB_STORAGE_KEY, tab); } }, []); return [activeTab, setActiveTab]; } function DataStatusStrip({ history, historyLoading, simplefinConn, syncLoading }) { const syncStatus = simplefinConn ? (simplefinConn.last_error ? 'Needs attention' : 'Connected') : syncLoading ? 'Loading…' : 'Not connected'; const syncTone = simplefinConn?.last_error ? 'text-amber-600 dark:text-amber-300' : simplefinConn ? 'text-emerald-600 dark:text-emerald-300' : 'text-muted-foreground'; return (

SimpleFIN

Open standard for syncing bank transactions
{simplefinConn?.last_error ? (

{syncStatus}

{simplefinConn.last_error}
) : (

{syncStatus}

)}

Last Sync

{simplefinConn?.last_sync_at ? new Date(simplefinConn.last_sync_at).toLocaleString([], { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }) : '—'}

Import History

{historyLoading ? 'Loading…' : `${history?.length || 0} record${(history?.length || 0) === 1 ? '' : 's'}`}

); } export default function DataPage() { const [history, setHistory] = useState(null); const [historyLoading, setHistoryLoading] = useState(true); const [transactionRefreshKey, setTransactionRefreshKey] = useState(0); const [simplefinConn, setSimplefinConn] = useState(null); const [syncLoading, setSyncLoading] = useState(true); const [activeTab, setActiveTab] = useStoredTab(); const loadHistory = async () => { setHistoryLoading(true); try { const { history } = await api.importHistory(); setHistory(history); } catch (err) { setHistory([]); toast.error(err.message || 'Failed to load import history.'); } finally { setHistoryLoading(false); } }; const loadSimplefinSummary = useCallback(async () => { setSyncLoading(true); try { const [status, sources] = await Promise.all([ api.simplefinStatus(), api.dataSources({ type: 'provider_sync' }), ]); if (!status.enabled) { setSimplefinConn(null); return; } const conns = Array.isArray(sources) ? sources.filter(source => source.provider === 'simplefin') : []; setSimplefinConn(conns[0] || null); } catch { setSimplefinConn(null); } finally { setSyncLoading(false); } }, []); useEffect(() => { loadHistory(); loadSimplefinSummary(); }, [loadSimplefinSummary]); const handleTransactionImportComplete = () => { loadHistory(); setTransactionRefreshKey(key => key + 1); }; // Called by BankSyncSection when connection state changes (connect/sync/disconnect) const handleConnectionChange = useCallback((conn) => { setSimplefinConn(conn || null); setSyncLoading(false); setTransactionRefreshKey(key => key + 1); }, []); return (

Data

Import, export, and review your user-owned bill tracker records.

User data only
This page only manages your own records — other users' data is not accessible here
{DATA_TABS.map(tab => { const active = activeTab === tab.id; return ( ); })}
{activeTab === 'sync' && (
)} {activeTab === 'import' && (
)} {activeTab === 'export' && (
)}
); }