diff --git a/src/pages/WalletDashboard.tsx b/src/pages/WalletDashboard.tsx index e83a58db..b95fdbd7 100644 --- a/src/pages/WalletDashboard.tsx +++ b/src/pages/WalletDashboard.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { usePolkadot } from '@/contexts/PolkadotContext'; import { AccountBalance } from '@/components/AccountBalance'; @@ -7,14 +7,142 @@ import { ReceiveModal } from '@/components/ReceiveModal'; import { TransactionHistory } from '@/components/TransactionHistory'; import { NftList } from '@/components/NftList'; import { Button } from '@/components/ui/button'; -import { ArrowUpRight, ArrowDownRight, History, ArrowLeft, Activity } from 'lucide-react'; +import { ArrowUpRight, ArrowDownRight, History, ArrowLeft, RefreshCw } from 'lucide-react'; + +interface Transaction { + blockNumber: number; + extrinsicIndex: number; + hash: string; + method: string; + section: string; + from: string; + to?: string; + amount?: string; + success: boolean; + timestamp?: number; +} const WalletDashboard: React.FC = () => { const navigate = useNavigate(); - const { selectedAccount } = usePolkadot(); + const { api, isApiReady, selectedAccount } = usePolkadot(); const [isTransferModalOpen, setIsTransferModalOpen] = useState(false); const [isReceiveModalOpen, setIsReceiveModalOpen] = useState(false); const [isHistoryModalOpen, setIsHistoryModalOpen] = useState(false); + const [recentTransactions, setRecentTransactions] = useState([]); + const [isLoadingRecent, setIsLoadingRecent] = useState(false); + + // Fetch recent transactions + const fetchRecentTransactions = async () => { + if (!api || !isApiReady || !selectedAccount) return; + + setIsLoadingRecent(true); + try { + const currentBlock = await api.rpc.chain.getBlock(); + const currentBlockNumber = currentBlock.block.header.number.toNumber(); + + const txList: Transaction[] = []; + const blocksToCheck = Math.min(100, currentBlockNumber); + + for (let i = 0; i < blocksToCheck && txList.length < 5; i++) { + const blockNumber = currentBlockNumber - i; + + try { + const blockHash = await api.rpc.chain.getBlockHash(blockNumber); + const block = await api.rpc.chain.getBlock(blockHash); + + let timestamp = 0; + try { + const ts = await api.query.timestamp.now.at(blockHash); + timestamp = ts.toNumber(); + } catch (error) { + timestamp = Date.now(); + } + + block.block.extrinsics.forEach((extrinsic, index) => { + if (!extrinsic.isSigned) return; + + const { method, signer } = extrinsic; + const fromAddress = signer.toString(); + const isFromOurAccount = fromAddress === selectedAccount.address; + + // Parse balances.transfer + if (method.section === 'balances' && + (method.method === 'transfer' || method.method === 'transferKeepAlive')) { + const [dest, value] = method.args; + const toAddress = dest.toString(); + const isToOurAccount = toAddress === selectedAccount.address; + + if (isFromOurAccount || isToOurAccount) { + txList.push({ + blockNumber, + extrinsicIndex: index, + hash: extrinsic.hash.toHex(), + method: method.method, + section: method.section, + from: fromAddress, + to: toAddress, + amount: value.toString(), + success: true, + timestamp: timestamp, + }); + } + } + + // Parse assets.transfer + if (method.section === 'assets' && method.method === 'transfer') { + const [assetId, dest, value] = method.args; + const toAddress = dest.toString(); + const isToOurAccount = toAddress === selectedAccount.address; + + if (isFromOurAccount || isToOurAccount) { + txList.push({ + blockNumber, + extrinsicIndex: index, + hash: extrinsic.hash.toHex(), + method: `${method.method} (Asset ${assetId.toString()})`, + section: method.section, + from: fromAddress, + to: toAddress, + amount: value.toString(), + success: true, + timestamp: timestamp, + }); + } + } + }); + } catch (blockError) { + // Continue to next block + } + } + + setRecentTransactions(txList); + } catch (error) { + console.error('Failed to fetch recent transactions:', error); + } finally { + setIsLoadingRecent(false); + } + }; + + useEffect(() => { + if (selectedAccount && api && isApiReady) { + fetchRecentTransactions(); + } + }, [selectedAccount, api, isApiReady]); + + const formatAmount = (amount: string, decimals: number = 12) => { + const value = parseInt(amount) / Math.pow(10, decimals); + return value.toFixed(4); + }; + + const formatTimestamp = (timestamp?: number) => { + if (!timestamp) return 'Unknown'; + const date = new Date(timestamp); + return date.toLocaleString(); + }; + + const isIncoming = (tx: Transaction) => { + return tx.to === selectedAccount?.address; + }; if (!selectedAccount) { return ( @@ -50,7 +178,7 @@ const WalletDashboard: React.FC = () => { {/* Right Column - Actions */}
{/* Quick Actions */} -
+
- -
- {/* Recent Activity Placeholder */} + {/* Recent Activity */}
-

Recent Activity

-
- -

No recent transactions

-

- Your transaction history will appear here -

+
+

Recent Activity

+ + {isLoadingRecent ? ( +
+ +

Loading transactions...

+
+ ) : recentTransactions.length === 0 ? ( +
+ +

No recent transactions

+

+ Your transaction history will appear here +

+
+ ) : ( +
+ {recentTransactions.map((tx, index) => ( +
+
+
+ {isIncoming(tx) ? ( +
+ +
+ ) : ( +
+ +
+ )} +
+
+ {isIncoming(tx) ? 'Received' : 'Sent'} +
+
+ Block #{tx.blockNumber} +
+
+
+
+
+ {isIncoming(tx) ? '+' : '-'}{formatAmount(tx.amount || '0')} +
+
+ {tx.section}.{tx.method} +
+
+
+
+ ))} +
+ )} + +
{/* NFT Collection */}