diff --git a/components/Animation/RowShowAnimation.tsx b/components/Animation/RowShowAnimation.tsx new file mode 100644 index 00000000..42abffc6 --- /dev/null +++ b/components/Animation/RowShowAnimation.tsx @@ -0,0 +1,43 @@ +import { useEffect, useState } from 'react' +import { CSSTransition } from 'react-transition-group' + +/** + * @param action true: exec animation + * @param minHeight hold element space + */ +type RowShowAnimationProps = { + children: React.ReactNode + action: boolean + minHeight?: string +} +export default function RowShowAnimation({ children, action, minHeight = 'unset' }: RowShowAnimationProps) { + const [show, setShow] = useState(false) + useEffect(() => { + if (action) { + setTimeout(() => { + setShow(true) + }, 100) + } + }, []) + return ( + <> + {action ? ( +
+ setShowButton(false)} + // onExited={() => setShowButton(true)} + > + {children} + +
+ ) : ( + children + )} + + ) +} diff --git a/package.json b/package.json index f90f04a3..0cdf7505 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "react-dom": "18.2.0", "react-markdown": "8.0.0", "react-redux": "^8.0.2", + "react-transition-group": "^4.4.5", "redux": "^4.2.0", "redux-persist": "^6.0.0", "swr": "^1.3.0", diff --git a/pages/_app.tsx b/pages/_app.tsx index a12d16a4..d61f5548 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -7,6 +7,7 @@ import '@astraprotocol/astra-ui/lib/shared/style.css' import { cosmosFetcher, evmFetcher } from 'api' import { SWRConfig } from 'swr' import store, { persistor } from '../store' +import '../styles.css' const App = ({ Component, pageProps }: AppProps) => { const _detectFetcher = (rest: any[]) => { diff --git a/pages/blocks/index.tsx b/pages/blocks/index.tsx index eab042ee..0e3890fc 100644 --- a/pages/blocks/index.tsx +++ b/pages/blocks/index.tsx @@ -33,6 +33,7 @@ const BlockDetailPage: React.FC = _ => { updatedAt={item.timestamp} size={item.size} value={0} + newBlock={item.newBlock} /> ))} diff --git a/project.d.ts b/project.d.ts index 16b43cb6..05f0e0e5 100644 --- a/project.d.ts +++ b/project.d.ts @@ -31,6 +31,7 @@ interface BlockItem { timestamp: string total_difficulty: string updated_at: string + newBlock?: boolean } interface BlockResponse { @@ -61,6 +62,7 @@ interface TransactionItem { value: string } revert_reason: null + newTransaction?: boolean } interface TransactionResponse { diff --git a/styles.css b/styles.css new file mode 100644 index 00000000..7d1e06b8 --- /dev/null +++ b/styles.css @@ -0,0 +1,17 @@ +.alert-enter { + opacity: 0; + transform: scale(0.9); +} +.alert-enter-active { + opacity: 1; + transform: translateX(0); + transition: opacity 300ms, transform 300ms; +} +.alert-exit { + opacity: 1; +} +.alert-exit-active { + opacity: 0; + transform: scale(0.9); + transition: opacity 300ms, transform 300ms; +} diff --git a/view/Block/BlockBriefRow.tsx b/view/Block/BlockBriefRow.tsx index 9cc16fbb..952d6422 100644 --- a/view/Block/BlockBriefRow.tsx +++ b/view/Block/BlockBriefRow.tsx @@ -1,4 +1,5 @@ import clsx from 'clsx' +import RowShowAnimation from 'components/Animation/RowShowAnimation' import DotSpace from 'components/DotSpace' import Timer from 'components/Timer' import Typography from 'components/Typography' @@ -11,32 +12,41 @@ type BlockBriefRowProps = { updatedAt: number | string transactions: number proposerAddress: string + newBlock?: boolean } -export default function BlockBriefRow({ blockNumber, updatedAt, transactions, proposerAddress }: BlockBriefRowProps) { +export default function BlockBriefRow({ + blockNumber, + updatedAt, + transactions, + proposerAddress, + newBlock +}: BlockBriefRowProps) { return ( -
-
- -
-
-
- + +
+
+
-
-
- Block Proposer - {ellipseBetweenText(proposerAddress, 6, 6)} - - {transactions} Transactions +
+
+ +
+
+
+ Block Proposer + {ellipseBetweenText(proposerAddress, 6, 6)} + + {transactions} Transactions +
+
-
-
+ ) } diff --git a/view/Block/BlockRow.tsx b/view/Block/BlockRow.tsx index 186ac4b1..09c2a7ce 100644 --- a/view/Block/BlockRow.tsx +++ b/view/Block/BlockRow.tsx @@ -1,4 +1,5 @@ import clsx from 'clsx' +import RowShowAnimation from 'components/Animation/RowShowAnimation' import DotSpace from 'components/DotSpace' import Timer from 'components/Timer' import Typography from 'components/Typography' @@ -14,6 +15,7 @@ type BlockRowProps = { proposerAddress: string mine?: boolean value: number + newBlock?: boolean } export default function BlockRow({ @@ -23,62 +25,65 @@ export default function BlockRow({ proposerAddress, mine, size, - value + value, + newBlock }: BlockRowProps) { return ( -
-
- -
- {mine ? ( - <> -
-
Block mined, awaiting import...
- - ) : ( - <> -
- -
-
-
+ +
+
+ +
+ {mine ? ( + <> +
+
Block mined, awaiting import...
+ + ) : ( + <> +
-
-
- - {transactions} Transactions - - - {size} bytes +
+
+ +
+
+
+ + {transactions} Transactions + + + {size} bytes +
-
-
- -
+
+ +
-
{value}
- - )} -
+
{value}
+ + )} +
+ ) } diff --git a/view/Block/HomeBlock.tsx b/view/Block/HomeBlock.tsx index a494ca01..3eb1f9c3 100644 --- a/view/Block/HomeBlock.tsx +++ b/view/Block/HomeBlock.tsx @@ -30,6 +30,7 @@ export function HomeBlock() { proposerAddress={item.miner_hash} transactions={0} updatedAt={item.timestamp} + newBlock={item.newBlock} /> ))} diff --git a/view/Block/HomeTransactions.tsx b/view/Block/HomeTransactions.tsx deleted file mode 100644 index c97630aa..00000000 --- a/view/Block/HomeTransactions.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import API_LIST from 'api/api_list' -import clsx from 'clsx' -import BackgroundCard from 'components/Card/Background/BackgroundCard' -import Container from 'components/Container' -import DotSpace from 'components/DotSpace' -import RowLoader from 'components/Loader/RowLoader' -import useSWR from 'swr' -import { convertBalanceToView } from 'utils/helper' -import RowBrief from './TransactionBriefRow' - -export function HomeTransactions() { - const _fetchCondition = () => { - return [API_LIST.ALL_TRANSACTIONS] - } - const { data } = useSWR(_fetchCondition()) - const top10 = data?.items?.slice(0, 10) - return ( - -
- Lastest Transactions - - - View all transactions - -
- - {!top10 || top10.length === 0 ? ( - - ) : ( - - {top10?.map(item => ( - - ))} - - )} -
- ) -} diff --git a/view/Block/TransactionBriefRow.tsx b/view/Block/TransactionBriefRow.tsx deleted file mode 100644 index b88ccdac..00000000 --- a/view/Block/TransactionBriefRow.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { CryptoIcon, Typography as TypographyUI } from '@astraprotocol/astra-ui' -import clsx from 'clsx' -import Timer from 'components/Timer' -import Typography from 'components/Typography' -import Image from 'next/image' -import { ellipseBetweenText, ellipseRightText } from 'utils/helper' -import styles from './style.module.scss' - -type TransactionBriefRowProps = { - hash: string - from: string - to: string - balance: { - value?: string - token?: string - } - updatedAt: number | string -} - -export default function TransactionBriefRow({ hash, from, to, balance, updatedAt }: TransactionBriefRowProps) { - return ( -
-
- -
-
-
-
- Hash - -
- } - currency={balance.token} - size="sm" - value={balance?.value} - /> -
-
-
- From - {ellipseBetweenText(from, 6, 6)} - To - {ellipseBetweenText(to, 6, 6)} -
- -
-
-
- ) -} diff --git a/view/Block/hook/useBlock.ts b/view/Block/hook/useBlock.ts index 826ba776..397d5a7e 100644 --- a/view/Block/hook/useBlock.ts +++ b/view/Block/hook/useBlock.ts @@ -1,16 +1,32 @@ import API_LIST from 'api/api_list' +import { differenceWith, isEmpty } from 'lodash' +import { useEffect, useState } from 'react' import useSWR from 'swr' export default function useBlock() { + const [_items, setState] = useState() + const _fetchCondition = () => { return [API_LIST.ALL_BLOCKS] } const { data } = useSWR(_fetchCondition(), { refreshInterval: parseInt(process.env.NEXT_PUBLIC_BLOCK_INTERVAL) }) - const blockTop10 = data?.items?.slice(0, 10) + useEffect(() => { + if (data?.items) { + if (isEmpty(_items)) { + setState(data?.items) + } else { + const items = differenceWith(data.items, _items, (a, b) => { + return a.number === b.number + }) + items.map(item => (item.newBlock = true)) + setState(data?.items) + } + } + }, [data]) return { - top10: blockTop10, - fullPageData: data?.items + top10: _items?.slice(0, 10), + fullPageData: _items } } diff --git a/view/Transactions/HomeTransactions.tsx b/view/Transactions/HomeTransactions.tsx index cdd80555..de72e664 100644 --- a/view/Transactions/HomeTransactions.tsx +++ b/view/Transactions/HomeTransactions.tsx @@ -1,19 +1,14 @@ -import API_LIST from 'api/api_list' import clsx from 'clsx' import BackgroundCard from 'components/Card/Background/BackgroundCard' import Container from 'components/Container' import DotSpace from 'components/DotSpace' import RowLoader from 'components/Loader/RowLoader' -import useSWR from 'swr' import { convertBalanceToView, LinkMaker } from 'utils/helper' +import useTransaction from './hook/useTransaction' import RowBrief from './TransactionBriefRow' export function HomeTransactions() { - const _fetchCondition = () => { - return [API_LIST.ALL_TRANSACTIONS] - } - const { data } = useSWR(_fetchCondition()) - const top10 = data?.items?.slice(0, 10) + const { top10 } = useTransaction() return (
@@ -36,6 +31,7 @@ export function HomeTransactions() { from="0x123123123123123123123123123123" to="0x2139847192384719234" updatedAt={new Date().getTime()} + newTransaction={item.newTransaction} /> ))} diff --git a/view/Transactions/TransactionBriefRow.tsx b/view/Transactions/TransactionBriefRow.tsx index f3162a75..1cfcb37c 100644 --- a/view/Transactions/TransactionBriefRow.tsx +++ b/view/Transactions/TransactionBriefRow.tsx @@ -1,5 +1,6 @@ import { CryptoIcon, Typography as TypographyUI } from '@astraprotocol/astra-ui' import clsx from 'clsx' +import RowShowAnimation from 'components/Animation/RowShowAnimation' import Timer from 'components/Timer' import Typography from 'components/Typography' import Image from 'next/image' @@ -15,41 +16,51 @@ type TransactionBriefRowProps = { token?: string } updatedAt: number | string + newTransaction?: boolean } -export default function TransactionBriefRow({ hash, from, to, balance, updatedAt }: TransactionBriefRowProps) { +export default function TransactionBriefRow({ + hash, + from, + to, + balance, + updatedAt, + newTransaction +}: TransactionBriefRowProps) { return ( -
-
- -
-
-
-
- Hash - +
+
+ +
+
+
+
+ Hash + +
+ } + currency={balance.token} + size="sm" + value={balance?.value} />
- } - currency={balance.token} - size="sm" - value={balance?.value} - /> -
-
-
- From - {ellipseBetweenText(from, 6, 6)} - To - {ellipseBetweenText(to, 6, 6)} +
+
+ From + {ellipseBetweenText(from, 6, 6)} + To + {ellipseBetweenText(to, 6, 6)} +
+
-
-
+ ) } diff --git a/view/Transactions/hook/useTransaction.ts b/view/Transactions/hook/useTransaction.ts new file mode 100644 index 00000000..548098ea --- /dev/null +++ b/view/Transactions/hook/useTransaction.ts @@ -0,0 +1,33 @@ +import API_LIST from 'api/api_list' +import { differenceWith, isEmpty } from 'lodash' +import { useEffect, useState } from 'react' +import useSWR from 'swr' + +export default function useTransaction() { + const [_items, setState] = useState() + + const _fetchCondition = () => { + return [API_LIST.ALL_TRANSACTIONS] + } + const { data } = useSWR(_fetchCondition(), { + refreshInterval: parseInt(process.env.NEXT_PUBLIC_TRANSACTION_INTERVAL) + }) + useEffect(() => { + if (data?.items) { + if (isEmpty(_items)) { + setState(data?.items) + } else { + const items = differenceWith(data.items, _items, (a, b) => { + return a.hash === b.hash + }) + console.log(items.map(item => item.hash)) + items.map(item => (item.newTransaction = true)) + setState(data?.items) + } + } + }, [data]) + return { + top10: _items?.slice(0, 10), + fullPageData: _items + } +}