Skip to content

Commit

Permalink
display transaction detail page
Browse files Browse the repository at this point in the history
  • Loading branch information
vorujack committed Sep 4, 2024
1 parent ed466ae commit 6b629f3
Show file tree
Hide file tree
Showing 15 changed files with 325 additions and 88 deletions.
15 changes: 15 additions & 0 deletions apps/wallet/src/action/transaction.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { createEmptyArrayWithIndex } from '@/utils/functions';
import { deserialize } from './box';
import { AddressDbAction, BoxDbAction } from './db';

Expand All @@ -6,6 +7,7 @@ interface WalletTransactionType {
date: Date;
ergIn: bigint;
ergOut: bigint;
tokens: Map<string, bigint>;
}

const getWalletTransactionsTotal = async (
Expand All @@ -31,6 +33,7 @@ const getWalletTransactions = async (
date: new Date(),
ergIn: 0n,
ergOut: 0n,
tokens: new Map<string, bigint>(),
txId: item.txId,
}));
for (const txRaw of result) {
Expand All @@ -40,6 +43,18 @@ const getWalletTransactions = async (
);
for (const box of boxes) {
const boxWasm = deserialize(box.serialized);
const tokens = boxWasm.tokens();
const sign = boxWasm.tx_id().to_str() === txRaw.txId ? 1n : -1n;
createEmptyArrayWithIndex(tokens.len()).forEach((index) => {
const token = tokens.get(index);
const total =
(txRaw.tokens.get(token.id().to_str()) ?? 0n) +
sign * BigInt(token.amount().as_i64().to_str());
txRaw.tokens.set(token.id().to_str(), total);
if (total === 0n) {
txRaw.tokens.delete(token.id().to_str());
}
});
if (boxWasm.tx_id().to_str() === txRaw.txId) {
txRaw.ergIn += BigInt(boxWasm.value().as_i64().to_str());
txRaw.date = new Date(box.create_timestamp);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box } from '@mui/material';
import { ReceiverTokenType } from '../../../types/sign-modal';
import { ReceiverTokenType } from '@/types/sign-modal';
import DisplayId from '../../display-id/DisplayId';
import TokenAmount from '../../token-amount/TokenAmount';
import { StateWallet } from '@/store/reducer/wallet';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ const TransactionBoxes = (props: TransactionBoxesPropsType) => {
props.boxes ?? context.boxes,
props.signed ?? context.tx,
);
const networkType = context.networkType
? context.networkType
: (props.wallet?.networkType ?? '');
return (
<Drawer
anchor="bottom"
Expand Down Expand Up @@ -50,7 +53,7 @@ const TransactionBoxes = (props: TransactionBoxesPropsType) => {
{inputBoxes.map((item, index) => (
<BoxItem
tokens={item.tokens}
networkType={context.networkType}
networkType={networkType}
address={item.address}
amount={item.amount}
key={index}
Expand All @@ -69,7 +72,7 @@ const TransactionBoxes = (props: TransactionBoxesPropsType) => {
{outputBoxes.map((item, index) => (
<BoxItem
tokens={item.tokens}
networkType={context.networkType}
networkType={networkType}
address={item.address}
amount={item.amount}
key={index}
Expand Down
48 changes: 48 additions & 0 deletions apps/wallet/src/hooks/useTransactionData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { StateWallet } from '@/store/reducer/wallet';
import getChain from '@/utils/networks';
import { useEffect, useState } from 'react';
import * as wasm from 'ergo-lib-wasm-browser';

const useTransactionData = (txId: string, wallet: StateWallet) => {
const [loadedTx, setLoadedTx] = useState<string>('');
const [loadedWalletId, setLoadedWalletId] = useState<string>('');
const [loading, setLoading] = useState<boolean>(false);
const [tx, setTx] = useState<wasm.Transaction>();
const [date, setDate] = useState('');
const [boxes, setBoxes] = useState<Array<wasm.ErgoBox>>([]);

useEffect(() => {
if (!loading) {
const processingTxId = txId;
if (loadedWalletId !== `${wallet.id}` || txId !== loadedTx) {
console.log(loadedWalletId, loadedTx, txId);
setLoading(true);
const chain = getChain(wallet.networkType);
chain
.getNetwork()
.getTransaction(processingTxId)
.then((tx) => {
setLoadedTx(processingTxId);
setLoadedWalletId(`${wallet.id}`);
setTx(tx.tx);
setDate(tx.date);
setBoxes(tx.boxes);
setLoading(false);
})
.catch((e) => {
console.log(e);
setTimeout(() => setLoading(false), 1000);
// setLoading(false)
});
}
}
}, [loadedTx, loadedWalletId, loading, txId, wallet.id, wallet.networkType]);
return {
tx,
boxes,
date,
loading,
};
};

export default useTransactionData;
50 changes: 50 additions & 0 deletions apps/wallet/src/hooks/useTxValues.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { extractErgAndTokenSpent } from '@/action/tx';
import { StateWallet } from '@/store/reducer/wallet';
import { useEffect, useState } from 'react';
import * as wasm from 'ergo-lib-wasm-browser';

interface Values {
total: bigint;
txId: string;
tokens: { [tokenId: string]: bigint };
}

const useTxValues = (
tx: wasm.Transaction | wasm.UnsignedTransaction,
boxes: Array<wasm.ErgoBox>,
wallet: StateWallet,
) => {
const [txValues, setTxValues] = useState<Values>({
total: 0n,
txId: '',
tokens: {},
});
const [valuesDirection, setValuesDirection] = useState({
incoming: false,
outgoing: false,
});
useEffect(() => {
const unsigned = tx;
if (txValues.txId !== unsigned.id().to_str()) {
const values = extractErgAndTokenSpent(wallet, boxes, unsigned);
const incoming =
values.value < 0n ||
Object.values(values.tokens).filter((amount) => amount < 0n).length > 0;
const outgoing =
values.value > 0n ||
Object.values(values.tokens).filter((amount) => amount > 0n).length > 0;
setValuesDirection({ incoming, outgoing });
setTxValues({
total: values.value,
tokens: values.tokens,
txId: unsigned.id().to_str(),
});
}
}, [txValues.txId, tx, wallet, boxes]);
return {
txValues,
valuesDirection,
};
};

export default useTxValues;
5 changes: 5 additions & 0 deletions apps/wallet/src/pages/wallet-page/WalletPage.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import WalletTransactionDetails from '@/pages/wallet-page/transaction/WalletTransactionDetail';
import { useEffect, useState } from 'react';
import { GlobalStateType } from '@/store';
import { useSelector } from 'react-redux';
Expand Down Expand Up @@ -59,6 +60,10 @@ const WalletPage = () => {
path={WalletPageSuffix.WalletTransaction}
element={<WalletTransaction wallet={wallet} />}
/>
<Route
path={WalletPageSuffix.WalletTransactionDetail}
element={<WalletTransactionDetails wallet={wallet} />}
/>
<Route
path={WalletPageSuffix.WalletAddress}
element={<WalletAddress wallet={wallet} />}
Expand Down
10 changes: 3 additions & 7 deletions apps/wallet/src/pages/wallet-page/home/RecentTransactions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import useWalletTransaction from '@/hooks/useWalletTransaction';
import { Box, Divider, Stack } from '@mui/material';
import { Box, Stack } from '@mui/material';
import StateMessage from '@/components/state-message/StateMessage';
import SvgIcon from '@/icons/SvgIcon';
import TransactionItem from '../transaction/TransactionItem';
Expand All @@ -25,13 +25,9 @@ const RecentTransactions = (props: RecentTransactionsPropsType) => {
disabled={transactions.length === 0}
/>
{transactions.length > 0 ? (
<Stack divider={<Divider />} spacing={1}>
<Stack spacing={1}>
{transactions.map((item, index) => (
<TransactionItem
tx={item}
key={index}
network_type={props.wallet.networkType}
/>
<TransactionItem tx={item} key={index} wallet={props.wallet} />
))}
</Stack>
) : loading ? (
Expand Down
77 changes: 34 additions & 43 deletions apps/wallet/src/pages/wallet-page/send/sign-tx/TxSignValues.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Box, FormHelperText, Typography } from '@mui/material';
import { openTxInBrowser } from '@/action/tx';
import useTxValues from '@/hooks/useTxValues';
import { Box, FormHelperText, IconButton, Typography } from '@mui/material';
import { OpenInNew } from '@mui/icons-material';
import { ErgoBox } from 'ergo-lib-wasm-browser';
import * as wasm from 'ergo-lib-wasm-browser';
import React, { useEffect, useState } from 'react';
import { extractErgAndTokenSpent } from '@/action/tx';
import React from 'react';
import TokenAmount from '@/components/token-amount/TokenAmount';
import { StateWallet } from '@/store/reducer/wallet';
import useIssuedAndBurntTokens from '@/hooks/useIssuedAndBurntTokens';
Expand All @@ -12,47 +14,18 @@ interface WalletSignNormalPropsType {
tx: wasm.UnsignedTransaction | wasm.Transaction;
boxes: Array<ErgoBox>;
wallet: StateWallet;
}

interface Values {
total: bigint;
txId: string;
tokens: { [tokenId: string]: bigint };
date?: string;
}

const TxSignValues = (props: WalletSignNormalPropsType) => {
const [txValues, setTxValues] = useState<Values>({
total: 0n,
txId: '',
tokens: {},
});
const issuedAndBurnt = useIssuedAndBurntTokens(props.tx, props.boxes);
const [valuesDirection, setValuesDirection] = useState({
incoming: false,
outgoing: false,
});
useEffect(() => {
const unsigned = props.tx;
if (txValues.txId !== unsigned.id().to_str()) {
const values = extractErgAndTokenSpent(
props.wallet,
props.boxes,
unsigned,
);
const incoming =
values.value < 0n ||
Object.values(values.tokens).filter((amount) => amount < 0n).length > 0;
const outgoing =
values.value > 0n ||
Object.values(values.tokens).filter((amount) => amount > 0n).length > 0;
setValuesDirection({ incoming, outgoing });
setTxValues({
total: values.value,
tokens: values.tokens,
txId: unsigned.id().to_str(),
});
}
}, [txValues.txId, props.tx, props.wallet, props.boxes]);
const { txValues, valuesDirection } = useTxValues(
props.tx,
props.boxes,
props.wallet,
);
const openTx = () =>
openTxInBrowser(props.wallet.networkType, props.tx.id().to_str());
return (
<Box>
{valuesDirection.outgoing ? (
Expand Down Expand Up @@ -103,9 +76,27 @@ const TxSignValues = (props: WalletSignNormalPropsType) => {
)}
</React.Fragment>
) : null}
<FormHelperText sx={{ mb: 2 }}>
These amount will be spent when transaction proceed.
</FormHelperText>
{props.date ? (
<React.Fragment>
<Typography variant="body2" color="textSecondary" mt={2}>
Received on
</Typography>
<Typography mb={2}>{props.date}</Typography>
<Typography variant="body2" color="textSecondary">
Transaction Id
</Typography>
<Typography mb={2} sx={{ overflowWrap: 'anywhere' }} onClick={openTx}>
{props.tx.id().to_str()}
<IconButton>
<OpenInNew />
</IconButton>
</Typography>
</React.Fragment>
) : (
<FormHelperText sx={{ mb: 2 }}>
These amount will be spent when transaction proceed.
</FormHelperText>
)}
<UnBalancedTokensAmount
amounts={issuedAndBurnt.burnt}
color="error"
Expand Down
63 changes: 41 additions & 22 deletions apps/wallet/src/pages/wallet-page/transaction/TransactionItem.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { Box, Typography, useTheme } from '@mui/material';
import { getRoute, RouteMap } from '@/router/routerMap';
import { StateWallet } from '@/store/reducer/wallet';
import {
Box,
Card,
CardActionArea,
CardContent,
Typography,
useTheme,
} from '@mui/material';
import { WalletTransactionType } from '@/action/transaction';
import { openTxInBrowser } from '@/action/tx';
import DisplayId from '@/components/display-id/DisplayId';
import ErgAmountDisplay from '@/components/amounts-display/ErgAmount';
import { useNavigate } from 'react-router-dom';
// import getChain from '@/utils/networks';
// import openInBrowser from '@/utils/browser';

interface TransactionItemPropsType {
tx: WalletTransactionType;
network_type: string;
wallet: StateWallet;
}

const TransactionItem = (props: TransactionItemPropsType) => {
Expand All @@ -29,28 +38,38 @@ const TransactionItem = (props: TransactionItemPropsType) => {
sign: '-',
color: theme.palette.error.main,
};
const navigate = useNavigate();
const openTx = () => {
openTxInBrowser(props.network_type, props.tx.txId);
navigate(
getRoute(RouteMap.WalletTransactionDetail, {
txId: props.tx.txId,
id: `${props.wallet.id}`,
}),
);
};
return (
<Box>
<Box display="flex">
<Typography sx={{ flexGrow: 1 }}>{values.title}</Typography>
<Typography color={values.color}>
{values.sign}
<ErgAmountDisplay amount={amount} /> <small>ERG</small>
</Typography>
</Box>
<Typography variant="body2" color="textSecondary">
{props.tx.date.toLocaleString()}
</Typography>
<DisplayId
variant="body2"
color="textSecondary"
id={props.tx.txId}
onClick={openTx}
/>
</Box>
<Card>
<CardActionArea onClick={openTx}>
<CardContent>
<Box display="flex">
<Typography sx={{ flexGrow: 1 }}>{values.title}</Typography>
<Typography color={values.color}>
{values.sign}
<ErgAmountDisplay amount={amount} /> <small>ERG</small>
</Typography>
</Box>
<Typography variant="body2" color="textSecondary">
{props.tx.date.toLocaleString()}
</Typography>
{props.tx.tokens.size > 0 ? (
<Typography variant="body2" color="textSecondary">
Includes {props.tx.tokens.size} tokens
</Typography>
) : null}
<DisplayId variant="body2" color="textSecondary" id={props.tx.txId} />
</CardContent>
</CardActionArea>
</Card>
);
};

Expand Down
Loading

0 comments on commit 6b629f3

Please sign in to comment.