import { useCallback, useEffect, useMemo, useState } from "react"; import { useStore } from "../../store/AppStore"; import TransactionsTable from "./TransactionsTable"; import { SkippedLines } from "./SkippedLines"; import ImportBar from "./ImportBar"; import { type ImportOptions, type Transaction } from "../../types/api"; import { getDateRangedTransactions, getLatestTransactions, submitTransactions } from "../../services/api.service"; import { useLoader } from "../../hooks/useLoader"; import { FilterPanel, type FilterData } from "./FilterPanel"; import dayjs from "dayjs"; import { ExistingTransactions } from "./ExistingTransactions"; import classNames from "classnames"; import { useDebounce } from "../../hooks/useDebounce"; export default function PrepareTransactionsPage() { const { state, dispatch } = useStore(); const [userFilter, setUserFilter] = useState({}); const debouncedUserFilter = useDebounce(userFilter, 700); const [deselected, setDeselected] = useState([]); const [enabledExistingTransactions, setEnabledExistingTransactions] = useState(true); const [existingTransactions, setExistingTransactions] = useState([]); const select = useCallback((index: number) => setDeselected(deselected.filter(x => x !== index)), [deselected, setDeselected]); const deselect = useCallback((index: number) => setDeselected([...deselected, index]), [deselected, setDeselected]); const filteredTransactions = useMemo(() => state.transactions .filter(t => { if (!userFilter.from) { return true; } const date = dayjs(t.date); return date.isAfter(userFilter.from, 'day') || date.isSame(userFilter.from, 'day'); }) .filter(t => { if (!userFilter.to) { return true; } const date = dayjs(t.date); return date.isBefore(userFilter.to, 'day') || date.isSame(userFilter.to, 'day'); }) .slice().reverse() , [state.transactions, userFilter]); const selectedTransactions = useMemo(() => filteredTransactions.filter((_, i) => !deselected.includes(i)), [filteredTransactions, deselected]); const { fn: handleSubmit, loading } = useLoader(async (opts: ImportOptions) => { if(!state.server) { return; } const response = await submitTransactions(selectedTransactions.slice().reverse(), state.server, opts); dispatch({ type: 'SET_RESULT', payload: response }); dispatch({ type: 'MOVE_STEP', payload: { offset: 1 } }); }, [selectedTransactions, state]); const { fn: refreshExistingTransactions, loading: loadingExistingTransactions } = useLoader(async () => { if (!state.server || !enabledExistingTransactions) { setExistingTransactions([]); return; } // If no "from" filter active, pull the latest 10 transactions if (!debouncedUserFilter.from) { const transactions = await getLatestTransactions(state.server, 10, state.profile); setExistingTransactions(transactions); return; } const start = debouncedUserFilter.from.format("YYYY-MM-DD"); const end = (debouncedUserFilter.to ?? dayjs()).format("YYYY-MM-DD"); const transactions = await getDateRangedTransactions(state.server, start, end, state.profile); setExistingTransactions(transactions); }, [enabledExistingTransactions, state.server, debouncedUserFilter]); useEffect(() => { setDeselected([]) }, [filteredTransactions]); useEffect(() => { refreshExistingTransactions() }, [enabledExistingTransactions, state.server, debouncedUserFilter]); return (

Prepare Transactions

Filters

If enabled, the existing transactions will be fetched automatically basing on date filter. If "from" is filled, the existing transactions will be fetched basing on set date (if "to" is not filled, the todays date will be considered). Otherwise, the latest 10 raw transactions will be fetched. Because of transfer consolidation, the ultimate number of transactions can be lower.

Considered transactions ({selectedTransactions.length}/{filteredTransactions.length})

{enabledExistingTransactions &&

Existing transactions ({existingTransactions.length})

}

Skipped lines ({state.skipped.length})

location.reload()}/>
); }