Improve the UI of the transaction modal

This commit is contained in:
Justin Starry 2020-04-05 17:47:57 +08:00 committed by Michael Vines
parent bcb10b0536
commit ed470564e6
2 changed files with 105 additions and 19 deletions

View File

@ -6,6 +6,7 @@ import {
Selected Selected
} from "../providers/transactions"; } from "../providers/transactions";
import { useBlocks } from "../providers/blocks"; import { useBlocks } from "../providers/blocks";
import { LAMPORTS_PER_SOL } from "@solana/web3.js";
function TransactionModal() { function TransactionModal() {
const { selected } = useTransactions(); const { selected } = useTransactions();
@ -16,14 +17,16 @@ function TransactionModal() {
const renderContent = () => { const renderContent = () => {
if (!selected) return null; if (!selected) return null;
return ( return (
<div className="modal-dialog modal-dialog-center"> <div className="modal-dialog modal-dialog-centered">
<div className="modal-content"> <div className="modal-content" onClick={e => e.stopPropagation()}>
<div className="modal-body" onClick={e => e.stopPropagation()}> <div className="modal-card card">
<span className="close" onClick={onClose}> <div className="card-header">
&times; <h4 className="card-header-title">Transaction Details</h4>
</span>
<h2 className="text-center mb-4 mt-4">Transaction Details</h2> <button type="button" className="close" onClick={onClose}>
<span aria-hidden="true">&times;</span>
</button>
</div>
<TransactionDetails selected={selected} /> <TransactionDetails selected={selected} />
</div> </div>
@ -33,10 +36,7 @@ function TransactionModal() {
}; };
return ( return (
<div <div className={`modal fade${show ? " show" : ""}`} onClick={onClose}>
className={`modal fade fixed-right${show ? " show" : ""}`}
onClick={onClose}
>
{renderContent()} {renderContent()}
</div> </div>
); );
@ -45,16 +45,73 @@ function TransactionModal() {
function TransactionDetails({ selected }: { selected: Selected }) { function TransactionDetails({ selected }: { selected: Selected }) {
const { blocks } = useBlocks(); const { blocks } = useBlocks();
const block = blocks[selected.slot]; const block = blocks[selected.slot];
if (!block) return <span>{"block not found"}</span>; if (!block)
return <span className="text-info">{"Transaction block not found"}</span>;
if (!block.transactions) { if (!block.transactions) {
return <span>loading</span>; return (
<span className="text-info">
<span className="spinner-grow spinner-grow-sm mr-2"></span>
Loading
</span>
);
} }
const tx = block.transactions[selected.signature]; const details = block.transactions[selected.signature];
if (!tx) return <span>{"sig not found"}</span>; if (!details)
return <span className="text-info">{"Transaction not found"}</span>;
return <code>{JSON.stringify(tx)}</code>; if (details.transfers.length === 0)
return <span className="text-info">{"No transfers"}</span>;
let i = 0;
return (
<>
{details.transfers.map(transfer => {
return (
<div key={++i}>
{i > 1 ? <hr className="mb-4"></hr> : null}
<div className="card-body">
<div className="list-group list-group-flush my-n3">
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">From</h5>
</div>
<div className="col-auto">
<code>{transfer.fromPubkey.toBase58()}</code>
</div>
</div>
</div>
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">To</h5>
</div>
<div className="col-auto">
<code>{transfer.toPubkey.toBase58()}</code>
</div>
</div>
</div>
<div className="list-group-item">
<div className="row align-items-center">
<div className="col">
<h5 className="mb-0">Amount (SOL)</h5>
</div>
<div className="col-auto">
{`${(1.0 * transfer.lamports) / LAMPORTS_PER_SOL}`}
</div>
</div>
</div>
</div>
</div>
</div>
);
})}
</>
);
} }
export default TransactionModal; export default TransactionModal;

View File

@ -1,6 +1,12 @@
import React from "react"; import React from "react";
import bs58 from "bs58"; import bs58 from "bs58";
import { Connection, Transaction } from "@solana/web3.js"; import {
Connection,
Transaction,
TransferParams,
SystemProgram,
SystemInstruction
} from "@solana/web3.js";
import { useCluster, ClusterStatus } from "./cluster"; import { useCluster, ClusterStatus } from "./cluster";
import { useTransactions } from "./transactions"; import { useTransactions } from "./transactions";
@ -10,7 +16,12 @@ export enum Status {
Success Success
} }
type Transactions = { [signature: string]: Transaction }; export interface TransactionDetails {
transaction: Transaction;
transfers: Array<TransferParams>;
}
type Transactions = { [signature: string]: TransactionDetails };
export interface Block { export interface Block {
status: Status; status: Status;
transactions?: Transactions; transactions?: Transactions;
@ -155,8 +166,26 @@ async function fetchBlock(dispatch: Dispatch, slot: number, url: string) {
block.transactions.forEach(({ transaction }) => { block.transactions.forEach(({ transaction }) => {
const signature = transaction.signature; const signature = transaction.signature;
if (signature) { if (signature) {
const transferInstructions = transaction.instructions
.filter(ix => ix.programId.equals(SystemProgram.programId))
.filter(
ix => SystemInstruction.decodeInstructionType(ix) === "Transfer"
);
let transfers: TransferParams[] = [];
transferInstructions.forEach(ix => {
try {
transfers.push(SystemInstruction.decodeTransfer(ix));
} catch (err) {
console.log(ix, err);
}
});
const sig = bs58.encode(signature); const sig = bs58.encode(signature);
transactions[sig] = transaction; transactions[sig] = {
transaction,
transfers
};
} }
}); });
status = Status.Success; status = Status.Success;