Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
0e6c23f
create chain page and added header with link to blocks
MicahMaphet Jun 28, 2025
8ff3057
Merge branch 'master' into chain-details
MicahMaphet Jul 8, 2025
0150419
added block list to chain page
MicahMaphet Jul 8, 2025
56ba11e
[REF] replace oneinch with coingecko for token lists
gabrielbazan7 Jul 7, 2025
180c2a1
v10.10.6
nitsujlangston Jul 8, 2025
6bcac67
prevent redefine _getX/Y
Sayrix Jul 1, 2025
ce76c31
verify prePublishRaw tx
leolambo Jul 3, 2025
6ccb7d9
Adding sourceAddress for SPL proposals
leolambo Jul 3, 2025
46ebbd7
add all recipients by default
leolambo Jul 3, 2025
b324db6
feedback
leolambo Jul 3, 2025
8c2b6bb
v10.10.7
nitsujlangston Jul 21, 2025
c5506ee
feat(templates): removes horizontal rule from email
mahume Jul 15, 2025
9a891a6
[FIX] select inputs when replaceTxByFee - reuse one original input
gabrielbazan7 Jul 21, 2025
f77b083
removed unused lodash imports
MicahMaphet Jul 14, 2025
e5dcf28
v10.10.8
nitsujlangston Jul 22, 2025
cd2a8ae
add feePerKb to Solana getFee
leolambo Jul 25, 2025
06bee9f
add solana base fee to defaults
leolambo Jul 25, 2025
3814bee
lint
leolambo Jul 25, 2025
2f8941f
v10.10.9
nitsujlangston Jul 25, 2025
1ae8b3b
Merge branch 'master' of https://github.com/bitpay/bitcore into chain…
MicahMaphet Jul 29, 2025
ec13fa5
moved block list (now 10 blocks) to the right and linting
MicahMaphet Jul 29, 2025
fc181a1
Merge branch 'fee-data' into chain-details
MicahMaphet Jul 29, 2025
aa43033
added view blocks buton to bottom of transactions and fee data block
MicahMaphet Jul 29, 2025
158b008
replaced table with block chain
MicahMaphet Jul 29, 2025
09435bd
added fee chart
MicahMaphet Aug 7, 2025
cf28776
refactored chain-details page and added block tip fee
MicahMaphet Aug 8, 2025
b332934
Merge branch 'master' of https://github.com/bitpay/bitcore into chain…
MicahMaphet Aug 8, 2025
554f259
added median fee to block data display (WIP: removing Promise nesting…
MicahMaphet Aug 11, 2025
dd837ef
refactored nested promises to use feeData on block route
MicahMaphet Sep 23, 2025
3120ea0
added price labels to chart and aesthetic changes
MicahMaphet Sep 27, 2025
8956bd6
removed y title from price chart
MicahMaphet Sep 29, 2025
cbd7484
added fee data graph
MicahMaphet Sep 29, 2025
e1552a7
started 'idle' version of block sample expand viewer
MicahMaphet Sep 29, 2025
0feaabb
added data expansion to the currency block rows
MicahMaphet Oct 2, 2025
edada1f
moved currency colored chip label to top when expanded
MicahMaphet Oct 2, 2025
f5f7cb5
added sats/byte to fee data using new FeeBox element
MicahMaphet Oct 6, 2025
8b74526
replaced boxes with tables broken up into two columns for most data e…
MicahMaphet Oct 7, 2025
5f7cee3
made some text not bold
MicahMaphet Oct 7, 2025
eac648e
added block chip darken on hover
MicahMaphet Oct 7, 2025
b392e21
incorporated background darkening into the date of the BlockChipHeader
MicahMaphet Oct 7, 2025
05569e4
added light mode
MicahMaphet Oct 8, 2025
eedb2f3
fixed bug messing up data-box children
MicahMaphet Oct 8, 2025
0a521d4
Merge branch 'master' into chain-details
MicahMaphet Oct 30, 2025
7ea4da1
redid chain details header, put graphs next to each other, redid colo…
MicahMaphet Oct 30, 2025
71e2056
redid block listing making it more like a data table and numerous sty…
MicahMaphet Oct 31, 2025
5c9f03c
added the rest of the data to the block expansion, refactoring with i…
MicahMaphet Oct 31, 2025
6010234
improved color scheme, especially dark mode and added details in the …
MicahMaphet Oct 31, 2025
6e3cbf3
added InfiniteScroll to blocks list in chain page
MicahMaphet Oct 31, 2025
dc71645
added view transactions and next block links to blocks list; changed …
MicahMaphet Oct 31, 2025
1f678b3
removed unnecessary container in chain page
MicahMaphet Nov 4, 2025
67db607
fixed ETH error on chain-page: handle no fee data (as well as other d…
MicahMaphet Nov 4, 2025
16f4d7e
Merge branch 'master' into chain-details
MicahMaphet Nov 4, 2025
c562399
renamed block-sample -> block-list and removed blocks page
MicahMaphet Nov 4, 2025
bad27d5
renamed chain page to blocks page; renamed InfoCard -> info-card
MicahMaphet Nov 4, 2025
fb66c40
refactored expanded data with a list of all data that can be showed a…
MicahMaphet Nov 5, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/insight/src/Routing.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, {lazy, Suspense} from 'react';
import {lazy, Suspense} from 'react';
import {Navigate, Route, Routes} from 'react-router-dom';
import Home from './pages';
const Blocks = lazy(() => import('./pages/blocks'));
import Blocks from './pages/blocks';
const Block = lazy(() => import('./pages/block'));
const TransactionHash = lazy(() => import('./pages/transaction'));
const Address = lazy(() => import('./pages/address'));
Expand Down
9 changes: 9 additions & 0 deletions packages/insight/src/assets/images/arrow-down-black.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions packages/insight/src/assets/images/arrow-down.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/insight/src/assets/images/arrow-forward-blue.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/insight/src/assets/images/arrow-outward.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions packages/insight/src/assets/images/arrow-thin.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/insight/src/assets/images/cube.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 1 addition & 3 deletions packages/insight/src/components/block-details.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,7 @@ const BlockDetails: FC<BlockDetailsProps> = ({currency, network, block}) => {

<SharedTile
title='Block Reward'
description={`${getConvertedValue(summary.reward, currency).toFixed(
3,
)} ${currency}`}
description={`${getConvertedValue(summary.reward, currency).toFixed(3)} ${currency}`}
/>
<SharedTile title='Confirmations' description={summary.confirmations} />

Expand Down
204 changes: 204 additions & 0 deletions packages/insight/src/components/block-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import React, {FC, useState} from 'react';
import {getApiRoot, getConvertedValue, getDifficultyFromBits, getFormattedDate} from 'src/utilities/helper-methods';
import {BitcoinBlockType, FeeData} from 'src/utilities/models';
import Cube from '../assets/images/cube.svg';
import Arrow from '../assets/images/arrow-thin.svg';
import ArrowOutward from '../assets/images/arrow-outward.svg';
import ForwardArrow from '../assets/images/arrow-forward-blue.svg';
import ArrowDown from '../assets/images/arrow-down.svg';
import styled, { useTheme } from 'styled-components';
import InfoCard from './info-card';
import InfiniteScroll from 'react-infinite-scroll-component';
import { fetcher } from 'src/api/api';
import InfiniteScrollLoadSpinner from './infinite-scroll-load-spinner';
import Info from './info';
import { useNavigate } from 'react-router-dom';

const BlockListTableRow = styled.tr`
text-align: center;
line-height: 45px;

&:nth-child(odd) {
background-color: ${({theme: {dark}}) => (dark ? '#2a2a2a' : '#f6f7f9')};
}

&:nth-child(even) {
background-color: ${({theme: {dark}}) => (dark ? '#0f0f0f' : '#e0e4e7')};
}

font-size: 16px;
`;


const getBlocksUrl = (currency: string, network: string) => {
return `${getApiRoot(currency)}/${currency}/${network}/block?limit=200`;
};

const BlockList: FC<{currency: string, network: string, blocks: Array<BitcoinBlockType & Partial<FeeData>>}> = ({currency, network, blocks}) => {
const theme = useTheme();
const navigate = useNavigate();
const [expandedBlocks, setExpandedBlocks] = useState<number[]>([]);
const [blocksList, setBlocksList] = useState(blocks);
const [error, setError] = useState('');
const [hasMore, setHasMore] = useState(true);
const hasFees = blocks.every(block => block.feeData);
const columnProportion = hasFees ? '20%' : '25%';

const fetchMore = async (_blocksList: BitcoinBlockType[]) => {
if (!_blocksList.length || !currency || !network) return;
const since = _blocksList[_blocksList.length - 1].height;
try {
const newData: [BitcoinBlockType] = await fetcher(
`${getBlocksUrl(currency, network)}&since=${since}&paging=height&direction=-1`,
);
if (newData?.length) {
setBlocksList(_blocksList.concat(newData));
} else {
setHasMore(false);
}
} catch (e: any) {
setError(e.message || 'Something went wrong. Please try again later.');
}
};

const gotoSingleBlockDetailsView = async (hash: string) => {
await navigate(`/${currency}/${network}/block/${hash}`);
};

if (!blocksList?.length) return null;
return (
<>
{error ? <Info type={'error'} message={error} /> : null}
<InfiniteScroll
next={() => fetchMore(blocksList)}
hasMore={hasMore}
loader={<InfiniteScrollLoadSpinner />}
dataLength={blocksList.length}>
<table style={{width: '100%', overflowX: 'hidden', borderCollapse: 'collapse'}}>
<thead>
<BlockListTableRow>
<th style={{textAlign: 'left', paddingLeft: '3rem', width: columnProportion}}>Height</th>
<th style={{width: columnProportion}}>Timestamp</th>
<th style={{width: columnProportion}}>Transactions</th>
<th style={{width: columnProportion}}>Size</th>
{hasFees && <th style={{textAlign: 'right', paddingRight: '3rem', width: '20%'}}>Fee Rate</th>}
</BlockListTableRow>
</thead>
<tbody>
<tr />
{
blocksList.map((block: BitcoinBlockType & Partial<FeeData>, index: number) => {
const feeData = block.feeData;
const expanded = expandedBlocks.includes(block.height);

const dataRowsDB = {
'Previous block': {label: 'Previous block', value: block.height - 1},
'Bits': {label: 'Bits', value: block.bits},
'Version': {label: 'Version', value: block.version},
'Block reward': {label: 'Block reward', value: `${getConvertedValue(block.reward, currency).toFixed(3)} ${currency}`},
'Miner fees': {label: 'Miner fees', value: `${getConvertedValue(feeData?.feeTotal, currency).toFixed(5)} ${currency}`},
'Next block': {label: 'Next block', value:
<>
{block.height + 1}
<img
src={ArrowOutward}
style={{width: '24px', cursor: 'pointer'}}
onClick={() => gotoSingleBlockDetailsView(blocksList[index - 1].hash)}
alt='Next Block'
title={`Go to block ${block.height + 1}`}
/>
</>
},
'Nonce': {label: 'Nonce', value: block.nonce},
'Confirmations': {label: 'Confirmations', value: blocksList[0].height - block.height + 1},
'Difficulty': {label: 'Difficulty', value: getDifficultyFromBits(block.bits).toFixed(0)},
'Fee data': {label: 'Fee data', value:
<div style={{display: 'flex', flexDirection: 'row', justifyContent: 'space-between', width: '100%'}}>
{[{label: 'Mean', value: feeData?.mean}, {label: 'Median', value: feeData?.median}, {label: 'Mode', value: feeData?.mode}]
.map(({label, value}, key) => {
return <React.Fragment key={key}>
<div style={{display: 'flex', flexDirection: 'column', lineHeight: 1.1, marginTop: '-0.4rem'}}>
<span style={{color: theme.dark ? '#888' : '#474d53', alignSelf: 'flex-start', lineHeight: 2, marginBottom: -2, fontSize: '16px'}}>{label}</span>
{value?.toFixed(4)}
</div>
</React.Fragment>
})
}
</div>
}
};

type IDataRowsDB = keyof typeof dataRowsDB;
let columnLeftExpandedDataKeys: IDataRowsDB[];
let columnRightExpandedDataKeys: IDataRowsDB[];

if (currency === 'ETH') {
columnLeftExpandedDataKeys = ['Previous block', 'Block reward'];
columnRightExpandedDataKeys = ['Next block', 'Nonce', 'Confirmations'];
} else {
columnLeftExpandedDataKeys = ['Previous block', 'Bits', 'Version', 'Block reward', 'Miner fees'];
columnRightExpandedDataKeys = ['Next block', 'Nonce', 'Confirmations', 'Difficulty', 'Fee data'];
}
const columnLeftExpandedData : Array<{label: string, value: any}> = columnLeftExpandedDataKeys.map(key => dataRowsDB[key]);
const columnRightExpandedData : Array<{label: string, value: any}> = columnRightExpandedDataKeys.map(key => dataRowsDB[key]);

return (
<React.Fragment key={index}>
<BlockListTableRow key={index}>
<td style={{textAlign: 'left', color: '#2240C4', paddingLeft: '1rem'}}>
<span
style={{display: 'flex', alignItems: 'center', gap: '0.5em', width: 'fit-content', cursor: 'pointer'}}
onClick={() => expanded
? setExpandedBlocks(expandedBlocks.filter(h => h !== block.height))
: setExpandedBlocks([...expandedBlocks, block.height])}>
{expanded
? <img src={ArrowDown} style={{height: '2rem', marginLeft: '-2px', marginRight: '-7px'}} alt='arrow' />
: <img src={Arrow} style={{height: '1.8rem', marginRight: '-6px'}} alt='arrow' />
}
<img src={Cube} style={{height: '1.2rem'}} alt='cube' />
{block.height}
</span>
</td>
<td>{getFormattedDate(block.time)}</td>
<td>{block.transactionCount}</td>
<td>{block.size}</td>
{ feeData && <td style={{textAlign: 'right', paddingRight: '3rem'}}>{feeData.median.toFixed(4)}</td> }
</BlockListTableRow>
{expanded && <>
{/* Alternates the color so the data below this row stays the same*/}
<BlockListTableRow />
<BlockListTableRow>

<td colSpan={5} style={{padding: '1rem 2rem'}}>
<div style={{display: 'flex', flexDirection: 'column', gap: '1rem'}}>
<hr style={{border: 'none', borderTop: '1px solid #eee', margin: '0 -2rem', marginTop: '-0.8rem'}} />
<InfoCard data={[
{label: 'Block Hash', value: block.hash, copyText: true},
{label: 'Merkle Root', value: block.merkleRoot, copyText: true},
]}/>
<span style={{fontSize: '20px', alignSelf: 'flex-start'}}>Summary</span>
<div style={{display: 'flex', gap: '1rem'}}>
<InfoCard data={columnLeftExpandedData}/>
<InfoCard data={columnRightExpandedData}/>
</div>
<span style={{display: 'flex', alignItems: 'center', width: 'fit-content', cursor: 'pointer'}} onClick={() => gotoSingleBlockDetailsView(block.hash)}>
<span style={{color: '#2240C4', marginRight: '0.75rem', fontSize: '18px'}}>View transactions</span>
<img src={ForwardArrow} style={{height: '1.75rem'}} alt='arrow' />
</span>
</div>
</td>
</BlockListTableRow>
</>
}
</React.Fragment>
);
})
}
</tbody>
</table>
</InfiniteScroll>
</>
);
};

export default BlockList;
Loading