forked from forbole/big-dipper-2.0-cosmos
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Display info for smart contract address
- Loading branch information
avalkov
committed
Apr 13, 2022
1 parent
83dd72c
commit 907592e
Showing
38 changed files
with
1,309 additions
and
62 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { useState } from 'react'; | ||
import * as R from 'ramda'; | ||
import axios from 'axios'; | ||
import { | ||
CosmWasmExecutesDocument, | ||
} from '@graphql/cosmwasm'; | ||
import { ContractMessagesState } from './types'; | ||
|
||
const LIMIT = 50; | ||
|
||
export const useMessages = (addr: string) => { | ||
const fetchMessages = async (address: string, offset: number, limit: number) => { | ||
return axios.post(process.env.NEXT_PUBLIC_GRAPHQL_URL, { | ||
variables: { | ||
address, | ||
offset, | ||
limit, | ||
}, | ||
query: CosmWasmExecutesDocument, | ||
}); | ||
}; | ||
|
||
const fetchMessagesCompletionHandler = (data: any) => { | ||
const extractedData = R.pathOr([], ['data', 'cosmwasm_execute'], data); | ||
const itemsLength = extractedData.length; | ||
if (itemsLength === 0) { | ||
return; | ||
} | ||
const newItems = R.uniq([...state.data, ...formatMessages(extractedData)]); | ||
const stateChange = { | ||
data: newItems, | ||
hasNextPage: itemsLength === LIMIT, | ||
isNextPageLoading: false, | ||
offsetCount: state.offsetCount + itemsLength, | ||
}; | ||
|
||
handleSetState(stateChange); | ||
}; | ||
|
||
const [state, setState] = useState<ContractMessagesState>({ | ||
data: [], | ||
hasNextPage: false, | ||
isNextPageLoading: false, | ||
offsetCount: 0, | ||
}); | ||
|
||
const handleSetState = (stateChange: any) => { | ||
setState((prevState) => R.mergeDeepLeft(stateChange, prevState)); | ||
}; | ||
|
||
fetchMessages(addr, state.offsetCount, LIMIT).then(({ data }) => { | ||
fetchMessagesCompletionHandler(data); | ||
}); | ||
|
||
const loadNextPage = async () => { | ||
handleSetState({ | ||
isNextPageLoading: true, | ||
}); | ||
// refetch query | ||
fetchMessages(addr, state.offsetCount, LIMIT).then(({ data }) => { | ||
fetchMessagesCompletionHandler(data); | ||
}); | ||
}; | ||
|
||
const formatMessages = (data: any) => { | ||
return data.map((x) => { | ||
return ({ | ||
height: x.transaction.block.height, | ||
transaction_hash: x.transaction_hash, | ||
method: x.method, | ||
success: x.success, | ||
timestamp: x.transaction.block.timestamp, | ||
}); | ||
}); | ||
}; | ||
|
||
return ({ | ||
state, | ||
loadNextPage, | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import React from 'react'; | ||
import classnames from 'classnames'; | ||
import { Typography } from '@material-ui/core'; | ||
import useTranslation from 'next-translate/useTranslation'; | ||
import { | ||
ContractMessagesList, | ||
Box, | ||
} from '@components'; | ||
import { useStyles } from './styles'; | ||
import { useMessages } from './hooks'; | ||
|
||
type ContractMessagesComponent = { | ||
className?: string; | ||
address: string; | ||
} | ||
|
||
const ContractMessages: React.FC<ContractMessagesComponent> = (props) => { | ||
const classes = useStyles(); | ||
const { t } = useTranslation('transactions'); | ||
|
||
const { | ||
state, | ||
loadNextPage, | ||
} = useMessages(props.address); | ||
|
||
const loadMoreItems = state.isNextPageLoading ? () => null : loadNextPage; | ||
const isItemLoaded = (index) => !state.hasNextPage || index < state.data.length; | ||
const itemCount = state.hasNextPage ? state.data.length + 1 : state.data.length; | ||
|
||
return ( | ||
<Box className={classnames(props.className, classes.root)}> | ||
<Typography variant="h2"> | ||
{t('messages')} | ||
</Typography> | ||
<div className={classes.list}> | ||
<ContractMessagesList | ||
messages={state.data} | ||
itemCount={itemCount} | ||
hasNextPage={state.hasNextPage} | ||
isNextPageLoading={state.isNextPageLoading} | ||
loadNextPage={loadNextPage} | ||
loadMoreItems={loadMoreItems} | ||
isItemLoaded={isItemLoaded} | ||
/> | ||
</div> | ||
</Box> | ||
); | ||
}; | ||
|
||
export default ContractMessages; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { makeStyles } from '@material-ui/core/styles'; | ||
|
||
export const useStyles = () => { | ||
const styles = makeStyles( | ||
(theme) => { | ||
return ({ | ||
root: { | ||
'& .MuiTypography-h2': { | ||
marginBottom: theme.spacing(2), | ||
}, | ||
}, | ||
list: { | ||
minHeight: '500px', | ||
height: '50vh', | ||
[theme.breakpoints.up('lg')]: { | ||
minHeight: '65vh', | ||
}, | ||
}, | ||
}); | ||
}, | ||
)(); | ||
|
||
return styles; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export type ContractMessagesState = { | ||
hasNextPage: boolean; | ||
isNextPageLoading: boolean; | ||
offsetCount: number; | ||
data: ContractMessage[]; | ||
} |
196 changes: 196 additions & 0 deletions
196
src/components/cosmwasm/contract_messages_list/components/desktop/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
import React from 'react'; | ||
import classnames from 'classnames'; | ||
import AutoSizer from 'react-virtualized-auto-sizer'; | ||
import numeral from 'numeral'; | ||
import dayjs from '@utils/dayjs'; | ||
import Link from 'next/link'; | ||
import { | ||
TRANSACTION_DETAILS, | ||
BLOCK_DETAILS, | ||
} from '@utils/go_to_page'; | ||
import InfiniteLoader from 'react-window-infinite-loader'; | ||
import { VariableSizeGrid as Grid } from 'react-window'; | ||
import { Typography } from '@material-ui/core'; | ||
import useTranslation from 'next-translate/useTranslation'; | ||
import { mergeRefs } from '@utils/merge_refs'; | ||
import { | ||
Loading, Result, | ||
} from '@components'; | ||
import { useGrid } from '@hooks'; | ||
import { getMiddleEllipsis } from '@utils/get_middle_ellipsis'; | ||
import { ContractMessagesListState } from '../../types'; | ||
import { columns } from './utils'; | ||
import { useStyles } from './styles'; | ||
|
||
const Desktop: React.FC<ContractMessagesListState> = ({ | ||
className, | ||
itemCount, | ||
loadMoreItems, | ||
isItemLoaded, | ||
messages, | ||
}) => { | ||
const { | ||
gridRef, | ||
columnRef, | ||
onResize, | ||
getColumnWidth, | ||
getRowHeight, | ||
} = useGrid(columns); | ||
|
||
const classes = useStyles(); | ||
const { t } = useTranslation('transactions'); | ||
|
||
const items = messages.map((x) => ({ | ||
block: ( | ||
<Link href={BLOCK_DETAILS(x.height)} passHref> | ||
<Typography variant="body1" component="a"> | ||
{numeral(x.height).format('0,0')} | ||
</Typography> | ||
</Link> | ||
), | ||
hash: ( | ||
<Link href={TRANSACTION_DETAILS(x.transaction_hash)} passHref> | ||
<Typography variant="body1" component="a"> | ||
{getMiddleEllipsis(x.transaction_hash, { | ||
beginning: 20, ending: 15, | ||
})} | ||
</Typography> | ||
</Link> | ||
), | ||
result: ( | ||
<Result success={x.success} /> | ||
), | ||
time: dayjs.utc(x.timestamp).fromNow(), | ||
method: x.method, | ||
})); | ||
return ( | ||
<div className={classnames(className, classes.root)}> | ||
<AutoSizer onResize={onResize}> | ||
{({ | ||
height, width, | ||
}) => { | ||
return ( | ||
<> | ||
{/* ======================================= */} | ||
{/* Table Header */} | ||
{/* ======================================= */} | ||
<Grid | ||
ref={columnRef} | ||
columnCount={columns.length} | ||
columnWidth={(index) => getColumnWidth(width, index)} | ||
height={50} | ||
rowCount={1} | ||
rowHeight={() => 50} | ||
width={width} | ||
> | ||
{({ | ||
columnIndex, style, | ||
}) => { | ||
const { | ||
key, align, | ||
} = columns[columnIndex]; | ||
|
||
return ( | ||
<div | ||
style={style} | ||
className={classes.cell} | ||
> | ||
<Typography | ||
variant="h4" | ||
align={align} | ||
> | ||
{t(key)} | ||
</Typography> | ||
</div> | ||
); | ||
}} | ||
</Grid> | ||
{/* ======================================= */} | ||
{/* Table Body */} | ||
{/* ======================================= */} | ||
<InfiniteLoader | ||
isItemLoaded={isItemLoaded} | ||
itemCount={itemCount} | ||
loadMoreItems={loadMoreItems} | ||
> | ||
{({ | ||
onItemsRendered, ref, | ||
}) => { | ||
return ( | ||
<Grid | ||
onItemsRendered={({ | ||
visibleRowStartIndex, | ||
visibleRowStopIndex, | ||
overscanRowStopIndex, | ||
overscanRowStartIndex, | ||
}) => { | ||
onItemsRendered({ | ||
overscanStartIndex: overscanRowStartIndex, | ||
overscanStopIndex: overscanRowStopIndex, | ||
visibleStartIndex: visibleRowStartIndex, | ||
visibleStopIndex: visibleRowStopIndex, | ||
}); | ||
}} | ||
ref={mergeRefs(gridRef, ref)} | ||
columnCount={columns.length} | ||
columnWidth={(index) => getColumnWidth(width, index)} | ||
height={height - 50} | ||
rowCount={itemCount} | ||
rowHeight={getRowHeight} | ||
width={width} | ||
className="scrollbar" | ||
> | ||
{({ | ||
columnIndex, rowIndex, style, | ||
}) => { | ||
if (!isItemLoaded(rowIndex) && columnIndex === 0) { | ||
return ( | ||
<div | ||
style={{ | ||
...style, | ||
width, | ||
}} | ||
> | ||
<Loading /> | ||
</div> | ||
); | ||
} | ||
|
||
if (!isItemLoaded(rowIndex)) { | ||
return null; | ||
} | ||
|
||
const { | ||
key, align, | ||
} = columns[columnIndex]; | ||
const item = items[rowIndex][key]; | ||
return ( | ||
<div | ||
style={style} | ||
className={classnames(classes.cell, classes.body, { | ||
odd: !(rowIndex % 2), | ||
})} | ||
> | ||
<Typography | ||
variant="body1" | ||
align={align} | ||
component="div" | ||
> | ||
{item} | ||
</Typography> | ||
</div> | ||
); | ||
}} | ||
</Grid> | ||
); | ||
}} | ||
</InfiniteLoader> | ||
</> | ||
); | ||
}} | ||
</AutoSizer> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Desktop; |
Oops, something went wrong.