import React, { useCallback, useEffect, useMemo, useState } from 'react'; import * as need from 'lib/need'; import * as ob from 'urbit-ob'; import { useWallet } from 'store/wallet'; import useRoller from 'lib/useRoller'; import { useLocalRouter } from 'lib/LocalRouter'; import View from 'components/View'; import L2BackHeader from 'components/L2/Headers/L2BackHeader'; import Window from 'components/L2/Window/Window'; import HeaderPane from 'components/L2/Window/HeaderPane'; import BodyPane from 'components/L2/Window/BodyPane'; import { RollerTransaction } from '@urbit/roller-api'; import './TransactionHistory.scss'; import { TransactionRow } from './TransactionRow'; import { Box, LoadingSpinner, Row } from '@tlon/indigo-react'; import { PatpRow } from './PatpRow'; import Dropdown from 'components/L2/Dropdowns/Dropdown'; import Sigil from 'components/Sigil'; import { AddressRow } from './AddressRow'; interface GroupedTransactions { [ship: string]: RollerTransaction[]; } const TransactionHistory = () => { const { pop, data }: any = useLocalRouter(); const { api } = useRoller(); const { wallet }: any = useWallet(); const address = need.addressFromWallet(wallet); const [loading, setLoading] = useState(true); const [transactions, setTransactions] = useState([]); const [dropdownOpen, setDropdownOpen] = useState(false); const [selectedPatp, setSelectedPatp] = useState(); // Pre-filter the results if navigating from Point view const filterByPoint = useMemo(() => { return data?.filterByPoint.matchWith({ Nothing: () => null, Just: (p: any) => ob.patp(p.value), }); }, [data]); const shortAddress = useMemo(() => { return address.slice(0, 6); }, [address]); const fetchTransactions = useCallback(async () => { const txns = await api.getHistory(address); setTransactions(txns); if (filterByPoint) { setSelectedPatp(filterByPoint.slice(1)); } setLoading(false); }, [address, api, filterByPoint]); const selectPatp = useCallback(patp => { setSelectedPatp(patp); setDropdownOpen(false); }, []); const txnsByPatp = useMemo(() => { return transactions.reduce((memo, tx) => { const patp = tx.ship; if (patp && Object.keys(memo).includes(patp as string)) { memo[patp].push(tx); } else { memo[patp || '~'] = [tx]; } return memo; }, {} as GroupedTransactions); }, [transactions]); const txPatps = useMemo(() => { return Object.keys(txnsByPatp).sort((a, b) => { return ob.patp2dec(`~${a}`) - ob.patp2dec(`~${b}`); }); }, [txnsByPatp]); const filteredPatps = useMemo(() => { if (!selectedPatp) { return txPatps; } return txPatps.filter(p => p === selectedPatp); }, [selectedPatp, txPatps]); useEffect(() => { fetchTransactions(); // Load the TX history only once }, []); // eslint-disable-line react-hooks/exhaustive-deps return ( }> <>
Transactions
setDropdownOpen(!dropdownOpen)}> selectPatp(null)}> {shortAddress} {txPatps.map(patp => { return ( selectPatp(patp)} key={patp}> ~{patp} ); })}
{loading ? ( ) : ( {!selectedPatp && } {filteredPatps && filteredPatps.length > 0 ? ( filteredPatps.map(patp => { return ( {txnsByPatp[patp] .sort((a, b) => { return (b?.time || 0) - (a?.time || 0); }) .map(tx => ( ))} ); }) ) : ( No transactions yet )} )}
); }; export default TransactionHistory;