import { useState, useEffect, useCallback } from 'react'; import type { Transaction, Account, Category, PaginatedResponse, GetTransactionsParams, } from '@family-budget/shared'; import { getTransactions } from '../api/transactions'; import { getAccounts } from '../api/accounts'; import { getCategories } from '../api/categories'; import { TransactionFilters, type FiltersState, } from '../components/TransactionFilters'; import { TransactionTable } from '../components/TransactionTable'; import { Pagination } from '../components/Pagination'; import { EditTransactionModal } from '../components/EditTransactionModal'; import { ImportModal } from '../components/ImportModal'; import { toISODate } from '../utils/format'; function getDefaultFilters(): FiltersState { const now = new Date(); const from = new Date(now.getFullYear(), now.getMonth(), 1); return { from: toISODate(from), to: toISODate(now), accountId: '', direction: '', categoryId: '', search: '', amountMin: '', amountMax: '', onlyUnconfirmed: false, sortBy: 'date', sortOrder: 'desc', }; } export function HistoryPage() { const [filters, setFilters] = useState(getDefaultFilters); const [page, setPage] = useState(1); const [pageSize, setPageSize] = useState(50); const [data, setData] = useState | null>( null, ); const [loading, setLoading] = useState(false); const [accounts, setAccounts] = useState([]); const [categories, setCategories] = useState([]); const [editingTx, setEditingTx] = useState(null); const [showImport, setShowImport] = useState(false); useEffect(() => { getAccounts().then(setAccounts).catch(() => {}); getCategories().then(setCategories).catch(() => {}); }, []); const fetchData = useCallback(async () => { setLoading(true); try { const params: GetTransactionsParams = { page, pageSize, sortBy: filters.sortBy, sortOrder: filters.sortOrder, }; if (filters.from) params.from = filters.from; if (filters.to) params.to = filters.to; if (filters.accountId) params.accountId = Number(filters.accountId); if (filters.direction) params.direction = filters.direction; if (filters.categoryId) params.categoryId = Number(filters.categoryId); if (filters.search) params.search = filters.search; if (filters.amountMin) params.amountMin = Math.round(Number(filters.amountMin) * 100); if (filters.amountMax) params.amountMax = Math.round(Number(filters.amountMax) * 100); if (filters.onlyUnconfirmed) params.onlyUnconfirmed = true; const result = await getTransactions(params); setData(result); } catch { // 401 handled by interceptor } finally { setLoading(false); } }, [filters, page, pageSize]); useEffect(() => { fetchData(); }, [fetchData]); const handleFiltersChange = (newFilters: FiltersState) => { setFilters(newFilters); setPage(1); }; const handleEditSave = () => { setEditingTx(null); fetchData(); }; const handleImportDone = () => { setShowImport(false); fetchData(); getAccounts().then(setAccounts).catch(() => {}); }; return (

История операций

{data && ( { setPageSize(size); setPage(1); }} /> )} {editingTx && ( setEditingTx(null)} onSave={handleEditSave} /> )} {showImport && ( setShowImport(false)} onDone={handleImportDone} /> )}
); }