Skip to content

Commit

Permalink
feat: removing the transaction filter for cheqd
Browse files Browse the repository at this point in the history
  • Loading branch information
icfor committed Apr 24, 2024
1 parent c3361b9 commit 38d7d7e
Show file tree
Hide file tree
Showing 2 changed files with 309 additions and 0 deletions.
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;
143 changes: 143 additions & 0 deletions apps/web-cheqd/src/screens/transactions/hooks.ts
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,
};
};

0 comments on commit 38d7d7e

Please sign in to comment.