fix: search bar fix if number input, add badge (#2) (#4)

* fix: search bar fix if number input, add badge (#2)

* fix: search bar fix if number input, add badge
for type in search bar, horfix for direct link in inventory page

* fix: theme mode blink page

* fix: write boolean in tx page

* fix: styles for contract tab in address page

* fix: remove btn

* fix: env, results per page go to first page
in grid. fix path for REACT_APP_EXPLORER_V1_API_URL

* Update .env.example

Co-authored-by: potvik <57394565+potvik@users.noreply.github.com>
pull/6/head
vpcodebase 3 years ago committed by GitHub
parent d384cb23c7
commit f8e044f9c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      .env.example
  2. 4
      src/api/explorerV1.ts
  3. 5
      src/components/tables/TransactionsTable.tsx
  4. 2
      src/components/transaction/TransactionLogs.tsx
  5. 4
      src/components/ui/Pagination/index.tsx
  6. 61
      src/components/ui/Search.tsx
  7. 23
      src/hooks/themeSwitcherHook.ts
  8. 5
      src/pages/AddressPage/ContractDetails/AbiMethodView.tsx
  9. 17
      src/pages/AddressPage/ContractDetails/index.tsx
  10. 2
      src/pages/AllTransactionsPage/index.tsx
  11. 2
      src/pages/ERC20List/ERC20Table.tsx
  12. 4
      src/pages/ERC721List/ERC721Table.tsx
  13. 2
      src/pages/InventoryDetailsPage/InventoryDetailsPage.tsx
  14. 7
      src/web3/parseByteCode.tsx

@ -1,9 +1,9 @@
REACT_APP_RPC_URL_SHARD0=https://a.api.s0.t.hmny.io REACT_APP_RPC_URL_SHARD0=https://a.api.s0.t.hmny.io/
REACT_APP_RPC_URL_SHARD1=https://api.s1.t.hmny.io REACT_APP_RPC_URL_SHARD1=https://api.s1.t.hmny.io/
REACT_APP_RPC_URL_SHARD2=https://api.s2.t.hmny.io REACT_APP_RPC_URL_SHARD2=https://api.s2.t.hmny.io/
REACT_APP_RPC_URL_SHARD3=https://api.s3.t.hmny.io REACT_APP_RPC_URL_SHARD3=https://api.s3.t.hmny.io/
REACT_APP_AVAILABLE_SHARDS=0 REACT_APP_AVAILABLE_SHARDS=0,1,2,3
REACT_APP_EXPLORER_V1_API_URL=https://explorer.harmony.one:8888 REACT_APP_EXPLORER_V1_API_URL=https://explorer.pops.one:8888
REACT_APP_INDEXER_IPFS_GATEWAY=https://ipfs.io/ipfs/ REACT_APP_INDEXER_IPFS_GATEWAY=https://ipfs.io/ipfs/
REACT_APP_PROD_ADDRESS=https://explorer-v2-api.hmny.io REACT_APP_PROD_ADDRESS=https://explorer-v2-api.hmny.io/
REACT_APP_DEV_ADDRESS=https://ws.explorer-v2.hmny.io REACT_APP_DEV_ADDRESS=https://ws.explorer-v2.hmny.io/

@ -28,7 +28,7 @@ export interface IVerifyContractDataSendData {
export const verifyContractCode = async (data: IVerifyContractDataSendData) => { export const verifyContractCode = async (data: IVerifyContractDataSendData) => {
const response = await fetch( const response = await fetch(
`${process.env.REACT_APP_EXPLORER_V1_API_URL}/codeVerification`, `${process.env.REACT_APP_EXPLORER_V1_API_URL}codeVerification`,
{ {
method: "POST", method: "POST",
mode: "cors", mode: "cors",
@ -48,7 +48,7 @@ export const verifyContractCode = async (data: IVerifyContractDataSendData) => {
export const loadSourceCode = async (address: string): Promise<ISourceCode> => { export const loadSourceCode = async (address: string): Promise<ISourceCode> => {
const response = await fetch( const response = await fetch(
`${process.env.REACT_APP_EXPLORER_V1_API_URL}/fetchContractCode?contractAddress=${address}`, `${process.env.REACT_APP_EXPLORER_V1_API_URL}fetchContractCode?contractAddress=${address}`,
{ {
mode: "cors", mode: "cors",
cache: "no-cache", cache: "no-cache",

@ -186,6 +186,11 @@ export function TransactionsTable(props: TransactionTableProps) {
const _IsLoading = isLoading; const _IsLoading = isLoading;
useEffect(() => {
filter.offset = 0;
setFilter(filter);
}, [filter.limit]);
return ( return (
<> <>
<Box <Box

@ -76,7 +76,7 @@ const LogItem = (props: LogItemProps) => {
<Text color="minorText" size="small"> <Text color="minorText" size="small">
Suggested Event Suggested Event
</Text> </Text>
<Text size="small" color="black"> <Text size="small">
{displaySignature || signatures[0].signature || ''} {displaySignature || signatures[0].signature || ''}
</Text> </Text>
</Box> </Box>

@ -34,7 +34,7 @@ export function PaginationNavigator(props: PaginationNavigator) {
const onPrevClick = () => { const onPrevClick = () => {
const newFilter = JSON.parse(JSON.stringify(filter)) as Filter; const newFilter = JSON.parse(JSON.stringify(filter)) as Filter;
newFilter.offset = newFilter.offset - 10; newFilter.offset = newFilter.offset - (filter.limit || 10);
if (!isLoading) { if (!isLoading) {
onChange(newFilter, "prevPage"); onChange(newFilter, "prevPage");
@ -43,7 +43,7 @@ export function PaginationNavigator(props: PaginationNavigator) {
const onNextClick = () => { const onNextClick = () => {
const newFilter = JSON.parse(JSON.stringify(filter)) as Filter; const newFilter = JSON.parse(JSON.stringify(filter)) as Filter;
newFilter.offset += 10; newFilter.offset += filter.limit || 10;
if (!isLoading) { if (!isLoading) {
onChange(newFilter, "nextPage"); onChange(newFilter, "nextPage");
} }

@ -19,34 +19,41 @@ import { Address } from "./Address";
let timeoutID: any | null = null; let timeoutID: any | null = null;
export interface ISearchItem {
symbol: string;
name: string;
type: "erc1155" | "erc20" | "erc721";
item: any;
}
export const SearchInput = () => { export const SearchInput = () => {
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const [readySubmit, setReadySubmit] = useState(false); const [readySubmit, setReadySubmit] = useState(false);
const [focus, setFocus] = useState(false); const [focus, setFocus] = useState(false);
const [results, setResults] = useState<any[]>([]); const [results, setResults] = useState<ISearchItem[]>([]);
const themeMode = useThemeMode(); const themeMode = useThemeMode();
const erc20Map = useERC20Pool(); const erc20Map = useERC20Pool();
const erc721Map = useERC721Pool(); const erc721Map = useERC721Pool();
const erc1155Map = useERC1155Pool(); const erc1155Map = useERC1155Pool();
const dataTest = [ const dataTest: ISearchItem[] = [
...Object.keys(erc1155Map).map((address) => ({ ...Object.keys(erc1155Map).map((address) => ({
symbol: erc1155Map[address].symbol, symbol: erc1155Map[address].symbol,
name: erc1155Map[address].name, name: erc1155Map[address].name,
type: "erc1155", type: "erc1155" as "erc1155",
item: erc1155Map[address], item: erc1155Map[address],
})), })),
...Object.keys(erc20Map).map((address) => ({ ...Object.keys(erc20Map).map((address) => ({
symbol: erc20Map[address].symbol, symbol: erc20Map[address].symbol,
name: erc20Map[address].name, name: erc20Map[address].name,
type: "erc20", type: "erc20" as "erc20",
item: erc20Map[address], item: erc20Map[address],
})), })),
...Object.keys(erc721Map).map((address) => ({ ...Object.keys(erc721Map).map((address) => ({
symbol: erc721Map[address].symbol, symbol: erc721Map[address].symbol,
name: erc721Map[address].name, name: erc721Map[address].name,
type: "erc721", type: "erc721" as "erc721",
item: erc721Map[address], item: erc721Map[address],
})), })),
]; ];
@ -60,9 +67,6 @@ export const SearchInput = () => {
const { value: newValue } = event.target; const { value: newValue } = event.target;
setValue(newValue); setValue(newValue);
clearTimeout(timeoutID);
timeoutID = setTimeout(() => setReadySubmit(true), 200);
}, []); }, []);
useEffect(() => { useEffect(() => {
@ -87,7 +91,7 @@ export const SearchInput = () => {
if ("" + +v === v && +v > 0) { if ("" + +v === v && +v > 0) {
// is block number // is block number
history.push(`/block/${v}`); history.push(`/block/${v}`);
setValue('') setValue("");
return; return;
} }
@ -97,7 +101,7 @@ export const SearchInput = () => {
if (v.length === 42 && /^0x[a-f0-9]+$/.test(v)) { if (v.length === 42 && /^0x[a-f0-9]+$/.test(v)) {
// address // address
history.push(`/address/${v}`); history.push(`/address/${v}`);
setValue('') setValue("");
return; return;
} }
@ -106,7 +110,7 @@ export const SearchInput = () => {
const ethAddress = getAddress(v).basicHex; const ethAddress = getAddress(v).basicHex;
history.push(`/address/${ethAddress}`); history.push(`/address/${ethAddress}`);
setValue('') setValue("");
return; return;
} }
@ -130,7 +134,7 @@ export const SearchInput = () => {
return; return;
} }
history.push(`/tx/${v}`); history.push(`/tx/${v}`);
setValue('') setValue("");
}) })
.catch(), .catch(),
getStakingTransactionByField([0, "hash", v]).then((res) => { getStakingTransactionByField([0, "hash", v]).then((res) => {
@ -139,7 +143,7 @@ export const SearchInput = () => {
} }
history.push(`/staking-tx/${v}`); history.push(`/staking-tx/${v}`);
setValue('') setValue("");
}), }),
]); ]);
} catch { } catch {
@ -153,14 +157,14 @@ export const SearchInput = () => {
return; return;
} }
history.push(`/block/${v}`); history.push(`/block/${v}`);
setValue('') setValue("");
}), }),
getTransactionByField([shard, "hash", v]).then((res) => { getTransactionByField([shard, "hash", v]).then((res) => {
if (!res) { if (!res) {
return; return;
} }
history.push(`/tx/${v}`); history.push(`/tx/${v}`);
setValue('') setValue("");
}), }),
getStakingTransactionByField([shard, "hash", v]).then( getStakingTransactionByField([shard, "hash", v]).then(
(res) => { (res) => {
@ -169,7 +173,7 @@ export const SearchInput = () => {
} }
history.push(`/staking-tx/${v}`); history.push(`/staking-tx/${v}`);
setValue('') setValue("");
} }
), ),
]); ]);
@ -213,11 +217,25 @@ export const SearchInput = () => {
setValue(""); setValue("");
}} }}
> >
<Box
pad={"xxsmall"}
background={"backgroundSuccess"}
style={{
borderRadius: "6px",
marginRight: "10px",
paddingLeft: "6px",
paddingRight: "6px",
}}
>
<Text size={"xsmall"}>{`H${results[index].type
.slice(1)
.toUpperCase()}`}</Text>
</Box>
<Text size={"small"} style={{ paddingRight: "5px" }}> <Text size={"small"} style={{ paddingRight: "5px" }}>
Name {results[index].name} | {results[index].name} |
</Text> </Text>
<Text size={"small"} style={{ paddingRight: "5px" }}> <Text size={"small"} style={{ paddingRight: "5px" }}>
Symbol {results[index].symbol} | {results[index].symbol} |
</Text> </Text>
<Address <Address
address={results[index].item.address} address={results[index].item.address}
@ -244,9 +262,14 @@ export const SearchInput = () => {
setFocus(false); setFocus(false);
}, 100); }, 100);
}} }}
onPaste={(evt) => {
clearTimeout(timeoutID);
timeoutID = setTimeout(() => setReadySubmit(true), 200);
}}
onKeyDown={(e) => { onKeyDown={(e) => {
if (e.keyCode === 13) { if (e.keyCode === 13) {
onChange(e); clearTimeout(timeoutID);
timeoutID = setTimeout(() => setReadySubmit(true), 200);
} }
}} }}
color="red" color="red"

@ -7,20 +7,23 @@ let globalSetMode = () => {
throw new Error("you must useDarkMode before setting its state"); throw new Error("you must useDarkMode before setting its state");
}; };
export const useThemeMode = singletonHook(initTheme, () => { export const useThemeMode = singletonHook(
const currentTheme = window.localStorage.getItem('themeMode') as themeType || initTheme; (window.localStorage.getItem("themeMode") || initTheme) as themeType,
() => {
const [mode, setMode] = useState<themeType>(currentTheme); const currentTheme =
//@ts-ignore (window.localStorage.getItem("themeMode") as themeType) || initTheme;
globalSetMode = setMode;
return mode;
});
const [mode, setMode] = useState<themeType>(currentTheme);
//@ts-ignore
globalSetMode = setMode;
return mode;
}
);
export const setThemeMode = (mode: themeType) => { export const setThemeMode = (mode: themeType) => {
//@ts-ignore //@ts-ignore
globalSetMode(mode); globalSetMode(mode);
window.localStorage.setItem('themeMode', mode); window.localStorage.setItem("themeMode", mode);
}; };
export type themeType = "light" | "dark"; export type themeType = "light" | "dark";

@ -16,7 +16,8 @@ const ViewWrapper = styled(Box)`
const NameWrapper = styled(Box)` const NameWrapper = styled(Box)`
border-bottom: 1px solid #e7ecf7; border-bottom: 1px solid #e7ecf7;
padding: 10px; padding: 10px;
background: #f8f9fa; opacity: 0.7;
border-radius: 5px;
`; `;
const SmallTextInput = styled(TextInput)` const SmallTextInput = styled(TextInput)`
@ -127,7 +128,7 @@ export const AbiMethodsView = (props: {
return ( return (
<ViewWrapper direction="column" margin={{ bottom: "medium" }}> <ViewWrapper direction="column" margin={{ bottom: "medium" }}>
<NameWrapper> <NameWrapper background={"backgroundBack"}>
<Text size="small"> <Text size="small">
{index + 1}. {abiMethod.name} {index + 1}. {abiMethod.name}
</Text> </Text>

@ -1,5 +1,5 @@
import React, { useState } from "react"; import React, { useState } from "react";
import { Box, Text } from "grommet"; import { Box, Text, TextArea } from "grommet";
import { AddressDetails } from "src/types"; import { AddressDetails } from "src/types";
import { Item } from "../AddressDetails"; import { Item } from "../AddressDetails";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
@ -9,11 +9,10 @@ import { AbiMethodsView } from "./AbiMethodView";
import { AbiItem } from "web3-utils"; import { AbiItem } from "web3-utils";
import { Wallet } from "./ConnectWallets"; import { Wallet } from "./ConnectWallets";
const StyledTextArea = styled("textarea")` const StyledTextArea = styled(TextArea)`
padding: 0.75rem; padding: 0.75rem;
border: 1px solid #e7eaf3;
background-color: #f8f9fa;
border-radius: 0.35rem; border-radius: 0.35rem;
font-weight: normal;
`; `;
export const ContractDetails = (props: { export const ContractDetails = (props: {
@ -110,8 +109,10 @@ enum V_TABS {
WRITE = "Write Contract", WRITE = "Write Contract",
} }
const TabBox = styled(Box)` const TabBox = styled(Box)<{ selected: boolean }>`
border: 1px solid #dedede; border: 1px solid ${(props) => props.theme.global.colors.border};
background: ${(props) =>
props.selected ? props.theme.global.colors.backgroundBack : "transparent"};
padding: 7px 12px 6px 12px; padding: 7px 12px 6px 12px;
border-radius: 4px; border-radius: 4px;
margin: 5px 10px; margin: 5px 10px;
@ -125,9 +126,9 @@ const TabButton = (props: {
return ( return (
<TabBox <TabBox
onClick={props.onClick} onClick={props.onClick}
style={{ background: props.selected ? "#77838f" : "transparent" }} selected={props.selected}
> >
<Text size="small" color={props.selected ? "white" : "black"}> <Text size="small" color={'minorText'}>
{props.text} {props.text}
</Text> </Text>
</TabBox> </TabBox>

@ -87,7 +87,7 @@ export function AllTransactionsPage() {
limit={+limit} limit={+limit}
filter={filter} filter={filter}
setFilter={setFilter} setFilter={setFilter}
primaryKey={'blockHash'} primaryKey={'hash'}
/> />
</BasePage> </BasePage>
</BaseContainer> </BaseContainer>

@ -83,6 +83,7 @@ export function ERC20Table(props: TransactionTableProps) {
className={"g-table-header"} className={"g-table-header"}
style={{ width: "100%", minWidth }} style={{ width: "100%", minWidth }}
columns={getColumns({ history })} columns={getColumns({ history })}
primaryKey={'address'}
data={data} data={data}
border={{ border={{
header: { header: {
@ -160,7 +161,6 @@ function getColumns(props: any) {
</Text> </Text>
), ),
render: (data: Erc20) => { render: (data: Erc20) => {
console.log(data);
return ( return (
<Box direction={"row"}> <Box direction={"row"}>
<TokenValue <TokenValue

@ -84,6 +84,7 @@ export function ERC721Table(props: TransactionTableProps) {
style={{ width: "100%", minWidth }} style={{ width: "100%", minWidth }}
columns={getColumns({ history })} columns={getColumns({ history })}
data={data} data={data}
primaryKey={'address'}
border={{ border={{
header: { header: {
color: "brand", color: "brand",
@ -149,8 +150,7 @@ function getColumns(props: any) {
</Text> </Text>
), ),
render: (data: Erc20) => { render: (data: Erc20) => {
console.log(data) return <Address address={data.address} displayHash />;
return <Address address={data.address} displayHash />
}, },
}, },
// { // {

@ -15,7 +15,7 @@ export function InventoryDetailsPage() {
// @ts-ignore // @ts-ignore
const { address, tokenID, type } = useParams(); const { address, tokenID, type } = useParams();
const item = erc721Map[address] || erc1155Map[address]; const item = erc721Map[address] || erc1155Map[address] || {};
const name = item.name || ""; const name = item.name || "";
useEffect(() => { useEffect(() => {

@ -131,8 +131,9 @@ export const DisplaySignature = (props: any = {}) => {
return <></>; return <></>;
} }
return ( return (
<> <Text size={"small"}>
{event.name}( {event.name}(
<> <>
{abi.inputs.map((input: any, i: number) => { {abi.inputs.map((input: any, i: number) => {
@ -158,7 +159,7 @@ export const DisplaySignature = (props: any = {}) => {
) : Array.isArray(parsed[input.name]) ? ( ) : Array.isArray(parsed[input.name]) ? (
parsed[input.name].join(", ") parsed[input.name].join(", ")
) : ( ) : (
parsed[input.name] parsed[input.name].toString()
)} )}
{i < abi.inputs.length - 1 ? ", " : null} {i < abi.inputs.length - 1 ? ", " : null}
</div> </div>
@ -166,7 +167,7 @@ export const DisplaySignature = (props: any = {}) => {
})} })}
</> </>
) )
</> </Text>
); );
}; };

Loading…
Cancel
Save