Merge branch 'feature/ui-tweaks' into develop

This commit is contained in:
Willian Mitsuda 2021-07-03 23:03:05 -03:00
commit 2b48163840
6 changed files with 167 additions and 32 deletions

View File

@ -1,15 +1,23 @@
import React, { useEffect, useState, useMemo } from "react"; import React, { useEffect, useState, useMemo } from "react";
import { useParams, NavLink } from "react-router-dom"; import { useParams, NavLink } from "react-router-dom";
import { ethers, BigNumber } from "ethers"; import { ethers, BigNumber } from "ethers";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faChevronLeft,
faChevronRight,
} from "@fortawesome/free-solid-svg-icons";
import { provider } from "./ethersconfig"; import { provider } from "./ethersconfig";
import StandardFrame from "./StandardFrame"; import StandardFrame from "./StandardFrame";
import StandardSubtitle from "./StandardSubtitle"; import StandardSubtitle from "./StandardSubtitle";
import ContentFrame from "./ContentFrame"; import ContentFrame from "./ContentFrame";
import NavButton from "./components/NavButton";
import Timestamp from "./components/Timestamp"; import Timestamp from "./components/Timestamp";
import GasValue from "./components/GasValue"; import GasValue from "./components/GasValue";
import BlockLink from "./components/BlockLink"; import BlockLink from "./components/BlockLink";
import AddressLink from "./components/AddressLink"; import AddressLink from "./components/AddressLink";
import TransactionValue from "./components/TransactionValue"; import TransactionValue from "./components/TransactionValue";
import HexValue from "./components/HexValue";
import { useLatestBlockNumber } from "./useLatestBlock";
type BlockParams = { type BlockParams = {
blockNumberOrHash: string; blockNumberOrHash: string;
@ -89,6 +97,8 @@ const Block: React.FC = () => {
} }
}, [block]); }, [block]);
const latestBlockNumber = useLatestBlockNumber();
return ( return (
<StandardFrame> <StandardFrame>
<StandardSubtitle> <StandardSubtitle>
@ -100,9 +110,36 @@ const Block: React.FC = () => {
{block && ( {block && (
<ContentFrame> <ContentFrame>
<InfoRow title="Block Height"> <InfoRow title="Block Height">
<span className="font-bold"> <div className="flex space-x-1 items-baseline">
<span className="font-bold mr-1">
{ethers.utils.commify(block.number)} {ethers.utils.commify(block.number)}
</span> </span>
<NavButton
blockNum={block.number - 1}
disabled={block.number === 0}
>
<FontAwesomeIcon icon={faChevronLeft} />
</NavButton>
<NavButton
blockNum={block.number + 1}
disabled={
latestBlockNumber === undefined ||
block.number >= latestBlockNumber
}
>
<FontAwesomeIcon icon={faChevronRight} />
</NavButton>
<NavButton
blockNum={latestBlockNumber!}
disabled={
latestBlockNumber === undefined ||
block.number >= latestBlockNumber
}
>
<FontAwesomeIcon icon={faChevronRight} />
<FontAwesomeIcon icon={faChevronRight} />
</NavButton>
</div>
</InfoRow> </InfoRow>
<InfoRow title="Timestamp"> <InfoRow title="Timestamp">
<Timestamp value={block.timestamp} /> <Timestamp value={block.timestamp} />
@ -155,16 +192,16 @@ const Block: React.FC = () => {
</InfoRow> </InfoRow>
<InfoRow title="Ether Price">N/A</InfoRow> <InfoRow title="Ether Price">N/A</InfoRow>
<InfoRow title="Hash"> <InfoRow title="Hash">
<span className="font-hash">{block.hash}</span> <HexValue value={block.hash} />
</InfoRow> </InfoRow>
<InfoRow title="Parent Hash"> <InfoRow title="Parent Hash">
<BlockLink blockTag={block.parentHash} /> <BlockLink blockTag={block.parentHash} />
</InfoRow> </InfoRow>
<InfoRow title="Sha3Uncles"> <InfoRow title="Sha3Uncles">
<span className="font-hash">{block.sha3Uncles}</span> <HexValue value={block.sha3Uncles} />
</InfoRow> </InfoRow>
<InfoRow title="StateRoot"> <InfoRow title="StateRoot">
<span className="font-hash">{block.stateRoot}</span> <HexValue value={block.stateRoot} />
</InfoRow> </InfoRow>
<InfoRow title="Nonce"> <InfoRow title="Nonce">
<span className="font-data">{block.nonce}</span> <span className="font-data">{block.nonce}</span>

View File

@ -1,9 +1,10 @@
import React, { useState, useEffect } from "react"; import React, { useState } from "react";
import { NavLink, useHistory } from "react-router-dom"; import { NavLink, useHistory } from "react-router-dom";
import { ethers } from "ethers"; import { ethers } from "ethers";
import Logo from "./Logo"; import Logo from "./Logo";
import Timestamp from "./components/Timestamp"; import Timestamp from "./components/Timestamp";
import { provider } from "./ethersconfig"; import { useLatestBlock } from "./useLatestBlock";
import { ERIGON_NODE } from "./ethersconfig";
const Home: React.FC = () => { const Home: React.FC = () => {
const [search, setSearch] = useState<string>(); const [search, setSearch] = useState<string>();
@ -24,29 +25,7 @@ const Home: React.FC = () => {
history.push(`/search?q=${search}`); history.push(`/search?q=${search}`);
}; };
const [latestBlock, setLatestBlock] = useState<ethers.providers.Block>(); const latestBlock = useLatestBlock();
useEffect(() => {
const readLatestBlock = async () => {
const blockNum = await provider.getBlockNumber();
const _raw = await provider.send("erigon_getHeaderByNumber", [blockNum]);
const _block = provider.formatter.block(_raw);
setLatestBlock(_block);
};
readLatestBlock();
const listener = async (blockNumber: number) => {
const _raw = await provider.send("erigon_getHeaderByNumber", [
blockNumber,
]);
const _block = provider.formatter.block(_raw);
setLatestBlock(_block);
};
provider.on("block", listener);
return () => {
provider.removeListener("block", listener);
};
}, []);
document.title = "Home | Otterscan"; document.title = "Home | Otterscan";
@ -85,6 +64,9 @@ const Home: React.FC = () => {
<Timestamp value={latestBlock.timestamp} /> <Timestamp value={latestBlock.timestamp} />
</NavLink> </NavLink>
)} )}
<span className="mx-auto mt-5 text-xs text-gray-500">
Using Erigon node at {ERIGON_NODE}
</span>
</form> </form>
</div> </div>
</div> </div>

View File

@ -0,0 +1,28 @@
import React from "react";
type HexValueProps = {
value: string;
};
const HexValue: React.FC<HexValueProps> = ({ value }) => {
const shards: string[] = [value.slice(0, 10)];
for (let i = 10; i < value.length; i += 8) {
shards.push(value.slice(i, i + 8));
}
return (
<>
{shards.map((s, i) => (
<span
className={`font-hash ${
i % 2 === 0 ? "text-black" : "text-gray-400"
}`}
>
{s}
</span>
))}
</>
);
};
export default React.memo(HexValue);

View File

@ -0,0 +1,31 @@
import { NavLink } from "react-router-dom";
type NavButtonProps = {
blockNum: number;
disabled?: boolean;
};
const NavButton: React.FC<NavButtonProps> = ({
blockNum,
disabled,
children,
}) => {
if (disabled) {
return (
<span className="bg-link-blue bg-opacity-10 text-gray-400 rounded px-2 py-1 text-xs">
{children}
</span>
);
}
return (
<NavLink
className="transition-colors bg-link-blue bg-opacity-10 text-link-blue hover:bg-opacity-100 hover:text-white disabled:bg-link-blue disabled:text-gray-400 disabled:cursor-default rounded px-2 py-1 text-xs"
to={`/block/${blockNum}`}
>
{children}
</NavLink>
);
};
export default NavButton;

View File

@ -1,6 +1,8 @@
import { ethers } from "ethers"; import { ethers } from "ethers";
export const ERIGON_NODE = "http://127.0.0.1:8545";
export const provider = new ethers.providers.JsonRpcProvider( export const provider = new ethers.providers.JsonRpcProvider(
"http://127.0.0.1:8545", ERIGON_NODE,
"mainnet" "mainnet"
); );

55
src/useLatestBlock.ts Normal file
View File

@ -0,0 +1,55 @@
import { useState, useEffect } from "react";
import { ethers } from "ethers";
import { provider } from "./ethersconfig";
export const useLatestBlock = () => {
const [latestBlock, setLatestBlock] = useState<ethers.providers.Block>();
useEffect(() => {
const readLatestBlock = async () => {
const blockNum = await provider.getBlockNumber();
const _raw = await provider.send("erigon_getHeaderByNumber", [blockNum]);
const _block = provider.formatter.block(_raw);
setLatestBlock(_block);
};
readLatestBlock();
const listener = async (blockNumber: number) => {
const _raw = await provider.send("erigon_getHeaderByNumber", [
blockNumber,
]);
const _block = provider.formatter.block(_raw);
setLatestBlock(_block);
};
provider.on("block", listener);
return () => {
provider.removeListener("block", listener);
};
}, []);
return latestBlock;
};
export const useLatestBlockNumber = () => {
const [latestBlock, setLatestBlock] = useState<number>();
useEffect(() => {
const readLatestBlock = async () => {
const blockNum = await provider.getBlockNumber();
setLatestBlock(blockNum);
};
readLatestBlock();
const listener = async (blockNumber: number) => {
setLatestBlock(blockNumber);
};
provider.on("block", listener);
return () => {
provider.removeListener("block", listener);
};
}, []);
return latestBlock;
};