-
Notifications
You must be signed in to change notification settings - Fork 339
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: removing the transaction filter for cheqd
- Loading branch information
Showing
2 changed files
with
309 additions
and
0 deletions.
There are no files selected for viewing
166 changes: 166 additions & 0 deletions
166
apps/web-cheqd/src/components/transactions_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,166 @@ | ||
import Loading from '@/components/loading'; | ||
import Result from '@/components/result'; | ||
import Tag from '@/components/tag'; | ||
import Timestamp from '@/components/Timestamp'; | ||
import useStyles from '@/components/transactions_list/components/desktop/styles'; | ||
import { columns } from '@/components/transactions_list/components/desktop/utils'; | ||
import type { TransactionsListState } from '@/components/transactions_list/types'; | ||
import { useGrid } from '@/hooks/use_react_window'; | ||
import { getMiddleEllipsis } from '@/utils/get_middle_ellipsis'; | ||
import { BLOCK_DETAILS, TRANSACTION_DETAILS } from '@/utils/go_to_page'; | ||
import { mergeRefs } from '@/utils/merge_refs'; | ||
import Typography from '@mui/material/Typography'; | ||
import useAppTranslation from '@/hooks/useAppTranslation'; | ||
import Link from 'next/link'; | ||
import numeral from 'numeral'; | ||
import { FC, LegacyRef } from 'react'; | ||
import AutoSizer from 'react-virtualized-auto-sizer'; | ||
import { VariableSizeGrid as Grid } from 'react-window'; | ||
import InfiniteLoader from 'react-window-infinite-loader'; | ||
|
||
const Desktop: FC<TransactionsListState> = ({ | ||
className, | ||
itemCount, | ||
loadMoreItems, | ||
isItemLoaded, | ||
transactions, | ||
}) => { | ||
const { gridRef, columnRef, onResize, getColumnWidth, getRowHeight } = useGrid(columns); | ||
|
||
const { classes, cx } = useStyles(); | ||
const { t } = useAppTranslation('transactions'); | ||
|
||
const items = transactions.map((x) => ({ | ||
block: ( | ||
<Link shallow prefetch={false} href={BLOCK_DETAILS(x.height)}> | ||
{numeral(x.height).format('0,0')} | ||
</Link> | ||
), | ||
hash: ( | ||
<Link shallow prefetch={false} href={TRANSACTION_DETAILS(x.hash)}> | ||
{getMiddleEllipsis(x.hash, { | ||
beginning: 4, | ||
ending: 4, | ||
})} | ||
</Link> | ||
), | ||
type: ( | ||
<div> | ||
<Tag value={x.type?.[0] ?? ''} theme="six" /> | ||
{x.messages.count > 1 && ` + ${x.messages.count - 1}`} | ||
</div> | ||
), | ||
result: <Result success={x.success} />, | ||
time: <Timestamp timestamp={x.timestamp} />, | ||
messages: numeral(x.messages.count).format('0,0'), | ||
})); | ||
return ( | ||
<div className={cx(classes.root, className)}> | ||
<AutoSizer onResize={onResize}> | ||
{({ height, width }) => ( | ||
<> | ||
{/* ======================================= */} | ||
{/* Table Header */} | ||
{/* ======================================= */} | ||
<Grid | ||
ref={columnRef as LegacyRef<Grid>} | ||
columnCount={columns.length} | ||
columnWidth={(index) => getColumnWidth(width ?? 0, index)} | ||
height={50} | ||
rowCount={1} | ||
rowHeight={() => 50} | ||
width={width ?? 0} | ||
> | ||
{({ 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 ?? (() => true)} | ||
itemCount={itemCount} | ||
loadMoreItems={ | ||
loadMoreItems ?? | ||
(() => { | ||
// do nothing | ||
}) | ||
} | ||
> | ||
{({ onItemsRendered, ref }) => ( | ||
<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 ?? 0, index)} | ||
height={(height ?? 0) - 50} | ||
rowCount={itemCount} | ||
rowHeight={getRowHeight} | ||
width={width ?? 0} | ||
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 as keyof (typeof items)[number]]; | ||
return ( | ||
<div | ||
style={style} | ||
className={cx(classes.cell, classes.body, { | ||
odd: !(rowIndex % 2), | ||
})} | ||
> | ||
<Typography variant="body1" align={align} component="div"> | ||
{item} | ||
</Typography> | ||
</div> | ||
); | ||
}} | ||
</Grid> | ||
)} | ||
</InfiniteLoader> | ||
</> | ||
)} | ||
</AutoSizer> | ||
</div> | ||
); | ||
}; | ||
|
||
export default Desktop; |
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,143 @@ | ||
import * as R from 'ramda'; | ||
import { useState } from 'react'; | ||
import { convertMsgsToModels } from '@/components/msg/utils'; | ||
import { | ||
TransactionsListenerSubscription, | ||
useTransactionsListenerSubscription, | ||
useTransactionsQuery, | ||
} from '@/graphql/types/general_types'; | ||
import type { TransactionsState } from '@/screens/transactions/types'; | ||
import { convertMsgType } from '@/utils/convert_msg_type'; | ||
|
||
// This is a bandaid as it can get extremely | ||
// expensive if there is too much data | ||
/** | ||
* Helps remove any possible duplication | ||
* and sorts by height in case it bugs out | ||
*/ | ||
const uniqueAndSort = R.pipe( | ||
R.uniqBy((r: Transactions) => r?.hash), | ||
R.sort(R.descend((r) => r?.height)) | ||
); | ||
|
||
const formatTransactions = (data: TransactionsListenerSubscription): TransactionsState['items'] => { | ||
let formattedData = data.transactions; | ||
if (data.transactions.length === 51) { | ||
formattedData = data.transactions.slice(0, 51); | ||
} | ||
|
||
return formattedData.map((x) => { | ||
const messages = convertMsgsToModels(x); | ||
const msgType = | ||
x.messages?.map((eachMsg: unknown) => { | ||
const eachMsgType = R.pathOr('none type', ['@type'], eachMsg); | ||
return eachMsgType ?? ''; | ||
}) ?? []; | ||
const convertedMsgType = convertMsgType(msgType); | ||
return { | ||
height: x.height, | ||
hash: x.hash, | ||
type: convertedMsgType, | ||
messages: { | ||
count: x.messages.length, | ||
items: messages, | ||
}, | ||
success: x.success, | ||
timestamp: x.block.timestamp, | ||
}; | ||
}); | ||
}; | ||
|
||
export const useTransactions = () => { | ||
const [state, setState] = useState<TransactionsState>({ | ||
loading: true, | ||
exists: true, | ||
hasNextPage: false, | ||
isNextPageLoading: true, | ||
items: [], | ||
}); | ||
|
||
const handleSetState = (stateChange: (prevState: TransactionsState) => TransactionsState) => { | ||
setState((prevState) => { | ||
const newState = stateChange(prevState); | ||
return R.equals(prevState, newState) ? prevState : newState; | ||
}); | ||
}; | ||
|
||
// ================================ | ||
// tx subscription | ||
// ================================ | ||
useTransactionsListenerSubscription({ | ||
variables: { | ||
limit: 1, | ||
offset: 0, | ||
}, | ||
onData: (data) => { | ||
const newItems = uniqueAndSort([ | ||
...(data.data.data ? formatTransactions(data.data.data) : []), | ||
...state.items, | ||
]); | ||
handleSetState((prevState) => ({ | ||
...prevState, | ||
loading: false, | ||
items: newItems, | ||
})); | ||
}, | ||
}); | ||
|
||
// ================================ | ||
// tx query | ||
// ================================ | ||
const LIMIT = 51; | ||
const transactionQuery = useTransactionsQuery({ | ||
variables: { | ||
limit: LIMIT, | ||
offset: 1, | ||
}, | ||
onError: () => { | ||
handleSetState((prevState) => ({ ...prevState, loading: false })); | ||
}, | ||
onCompleted: (data) => { | ||
const itemsLength = data.transactions.length; | ||
const newItems = uniqueAndSort([...state.items, ...formatTransactions(data)]); | ||
handleSetState((prevState) => ({ | ||
...prevState, | ||
loading: false, | ||
items: newItems, | ||
hasNextPage: itemsLength === 51, | ||
isNextPageLoading: false, | ||
})); | ||
}, | ||
}); | ||
|
||
const loadNextPage = async () => { | ||
handleSetState((prevState) => ({ ...prevState, isNextPageLoading: true })); | ||
// refetch query | ||
await transactionQuery | ||
.fetchMore({ | ||
variables: { | ||
offset: state.items.length, | ||
limit: LIMIT, | ||
}, | ||
}) | ||
.then(({ data }) => { | ||
const itemsLength = data.transactions.length; | ||
const newItems = uniqueAndSort([ | ||
...state.items, | ||
...formatTransactions(data), | ||
]) as TransactionsState['items']; | ||
// set new state | ||
handleSetState((prevState) => ({ | ||
...prevState, | ||
items: newItems, | ||
isNextPageLoading: false, | ||
hasNextPage: itemsLength === 51, | ||
})); | ||
}); | ||
}; | ||
|
||
return { | ||
state, | ||
loadNextPage, | ||
}; | ||
}; |