From 375f53087a98c1bc723dc7adeb1d3f419c503dca Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Wed, 11 Sep 2024 15:48:52 +0200 Subject: [PATCH] Show skeleton on Spacewalk transactions page (#551) * Show skeleton for transactions table * Fix conditions for showing skeleton * Fix table loading endlessly when no wallet connected * Use react-query * Change subscription of active block number to single fetch This is to prevent rerenders of the table for each new active block This prevents the timestamps of the entries in the table to change on each rerender --- .gitignore | 4 +- src/components/Table/index.tsx | 40 ++++-- src/pages/spacewalk/transactions/index.tsx | 153 +++++++++++---------- 3 files changed, 110 insertions(+), 87 deletions(-) diff --git a/.gitignore b/.gitignore index 682ea7b6..7254d232 100644 --- a/.gitignore +++ b/.gitignore @@ -35,4 +35,6 @@ dist-ssr !.yarn/versions vite.config.ts.timestamp-* -coverage/ \ No newline at end of file +coverage/ +# Local Netlify folder +.netlify diff --git a/src/components/Table/index.tsx b/src/components/Table/index.tsx index 8ee7f8e7..28b2678e 100644 --- a/src/components/Table/index.tsx +++ b/src/components/Table/index.tsx @@ -59,7 +59,6 @@ export type TableProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any const defaultData: any[] = []; -const loading = <>{repeat(, 6)}; const Table = ({ data = defaultData, @@ -77,6 +76,20 @@ const Table = ({ }: TableProps): JSX.Element | null => { const totalCount = data.length; + const showSkeleton = useMemo(() => { + return isLoading; + }, [isLoading]); + + const tableData = useMemo(() => { + return showSkeleton ? Array(8).fill({}) : data; + }, [showSkeleton, data]); + + const tableColumns = useMemo(() => { + return showSkeleton + ? columns.map((column) => ({ ...column, cell: () => })) + : columns; + }, [showSkeleton, columns]); + const initialSort = useMemo(() => { return sortBy ? Object.keys(sortBy).map((columnName) => ({ id: columnName, desc: sortBy[columnName] === SortingOrder.DESC })) @@ -85,8 +98,8 @@ const Table = ({ const { getHeaderGroups, getRowModel, getPageCount, nextPage, previousPage, setGlobalFilter, getState } = useReactTable({ - columns, - data, + columns: tableColumns, + data: tableData, initialState: { pagination: { pageSize: ps, @@ -105,18 +118,17 @@ const Table = ({ globalFilter, } = getState(); - if (isLoading) return loading; return ( <> {search ? ( -
+
) : null}
@@ -124,28 +136,28 @@ const Table = ({ {getHeaderGroups().map((headerGroup) => ( - + {headerGroup.headers.map((header) => { const isSortable = header.column.getCanSort(); return ( rowCallback(row, index) : undefined} - className={rowCallback && 'cursor-pointer highlighted-row'} + className={rowCallback && 'highlighted-row cursor-pointer'} > {row.getVisibleCells().map((cell) => { return ( @@ -180,7 +192,7 @@ const Table = ({
{flexRender(header.column.columnDef.header, header.getContext())} {isSortable ? ( -
+
{header.column.getIsSorted() === 'desc' ? ( - + ) : ( - + )}
) : null} @@ -161,7 +173,7 @@ const Table = ({
Promise, + getRedeemRequests: () => Promise, +) => { + const issueEntries = await getIssueRequests(); + const redeemEntries = await getRedeemRequests(); + const entries: TTransfer[] = []; + + issueEntries.forEach((e) => { + if (!walletAccount || !e.request.requester.eq(walletAccount?.address)) { + return; + } + + const deadline = calculateDeadline( + activeBlockNumber as number, + e.request.opentime.toNumber(), + e.request.period.toNumber(), + ); + + const timedOut = deadline < DateTime.now(); + const pending = e.request.status.type === 'Pending'; + entries.push({ + updated: estimateRequestCreationTime(activeBlockNumber as number, e.request.opentime.toNumber()), + amount: nativeToDecimal(e.request.amount.toString()).toString(), + asset: convertCurrencyToStellarAsset(e.request.asset)?.code, + transactionId: e.id.toString(), + type: TransferType.issue, + status: timedOut && pending ? 'Cancelled' : e.request.status.type, + original: e.request, + }); + }); + + redeemEntries.forEach((e) => { + if (!walletAccount || !e.request.redeemer.eq(walletAccount?.address)) { + return; + } + + const deadline = calculateDeadline( + activeBlockNumber as number, + e.request.opentime.toNumber(), + e.request.period.toNumber(), + ); + + const timedOut = deadline < DateTime.now(); + const pending = e.request.status.type === 'Pending'; + + entries.push({ + updated: estimateRequestCreationTime(activeBlockNumber as number, e.request.opentime.toNumber()), + amount: nativeToDecimal(e.request.amount.toString()).toString(), + asset: convertCurrencyToStellarAsset(e.request.asset)?.code, + transactionId: e.id.toString(), + type: TransferType.redeem, + status: timedOut && pending ? 'Failed' : e.request.status.type, + original: e.request, + }); + }); + + return entries; +}; function Transactions(): JSX.Element { const { getIssueRequests } = useIssuePallet(); const { getRedeemRequests } = useRedeemPallet(); - const { subscribeActiveBlockNumber } = useSecurityPallet(); + const { getActiveBlockNumber } = useSecurityPallet(); const { tenantName, walletAccount } = useGlobalState(); const [currentTransfer, setCurrentTransfer] = useState(); const [activeBlockNumber, setActiveBlockNumber] = useState(0); - const [data, setData] = useState(undefined); useEffect(() => { - let unsub: VoidFn = () => undefined; - subscribeActiveBlockNumber((blockNumber) => { + getActiveBlockNumber().then((blockNumber) => { setActiveBlockNumber(blockNumber); - }).then((u) => (unsub = u)); - - return unsub; - }, [subscribeActiveBlockNumber]); - - useEffect(() => { - const fetchAllEntries = async () => { - const issueEntries = await getIssueRequests(); - const redeemEntries = await getRedeemRequests(); - const entries: TTransfer[] = []; - - issueEntries.forEach((e) => { - if (!walletAccount || !e.request.requester.eq(walletAccount?.address)) { - return; - } - - const deadline = calculateDeadline( - activeBlockNumber as number, - e.request.opentime.toNumber(), - e.request.period.toNumber(), - ); - - const timedOut = deadline < DateTime.now(); - const pending = e.request.status.type === 'Pending'; - entries.push({ - updated: estimateRequestCreationTime(activeBlockNumber as number, e.request.opentime.toNumber()), - amount: nativeToDecimal(e.request.amount.toString()).toString(), - asset: convertCurrencyToStellarAsset(e.request.asset)?.code, - transactionId: e.id.toString(), - type: TransferType.issue, - status: timedOut && pending ? 'Cancelled' : e.request.status.type, - original: e.request, - }); - }); - - redeemEntries.forEach((e) => { - if (!walletAccount || !e.request.redeemer.eq(walletAccount?.address)) { - return; - } - - const deadline = calculateDeadline( - activeBlockNumber as number, - e.request.opentime.toNumber(), - e.request.period.toNumber(), - ); - - const timedOut = deadline < DateTime.now(); - const pending = e.request.status.type === 'Pending'; - - entries.push({ - updated: estimateRequestCreationTime(activeBlockNumber as number, e.request.opentime.toNumber()), - amount: nativeToDecimal(e.request.amount.toString()).toString(), - asset: convertCurrencyToStellarAsset(e.request.asset)?.code, - transactionId: e.id.toString(), - type: TransferType.redeem, - status: timedOut && pending ? 'Failed' : e.request.status.type, - original: e.request, - }); - }); - - return entries; - }; - fetchAllEntries().then((res) => setData(res)); - }, [activeBlockNumber, walletAccount, getIssueRequests, getRedeemRequests]); + }); + }, [getActiveBlockNumber]); + + const { data, isInitialLoading } = useQuery( + ['fetchAllEntries', walletAccount, activeBlockNumber], + () => fetchAllEntries(walletAccount, activeBlockNumber, getIssueRequests, getRedeemRequests), + { + onError: console.error, + }, + ); const columns = useMemo(() => { const statusColumn = statusColumnCreator(); @@ -119,7 +127,7 @@ function Transactions(): JSX.Element { const getDialog = (DialogComponent: ComponentType<{ transfer: TTransfer; visible: boolean; onClose: () => void }>) => currentTransfer ? ( - setCurrentTransfer(undefined)} /> + setCurrentTransfer(undefined)} /> ) : ( <> ); @@ -138,7 +146,7 @@ function Transactions(): JSX.Element { setCurrentTransfer(row.original)} @@ -150,4 +158,5 @@ function Transactions(): JSX.Element { ); } + export default Transactions;