diff --git a/src/components/LiteTransactionList/LiteTransactionList.module.scss b/src/components/LiteTransactionList/LiteTransactionList.module.scss new file mode 100644 index 000000000..05b6e6ad4 --- /dev/null +++ b/src/components/LiteTransactionList/LiteTransactionList.module.scss @@ -0,0 +1,148 @@ +.container { + padding: 0 2rem; + background: #fff; + + table { + width: 100%; + + th, + td { + height: 4rem; + padding: 0 8px; + white-space: nowrap; + font-size: 1rem; + font-weight: 500; + text-align: left; + + &:first-child { + padding-left: 0; + } + + &:last-child { + padding-right: 0; + text-align: right; + } + + &.noRecords:last-child { + text-align: center; + } + } + + thead { + th { + font-weight: 600; + } + } + + tbody { + tr { + border-top: 1px solid #e5e5e5; + } + } + } + + a { + color: var(--primary-color); + } + + .hash { + font-size: 0.875rem; + max-width: 25vw; + } + + .height { + font-family: Roboto, inherit, sans-serif; + } + + .cells { + white-space: pre; + } + + .income > span { + display: inline-flex; + + * { + color: inherit; + font-size: 1rem; + + // REFACTOR: it's hard to maintain, the component of decimal should be refactored + :global { + div.addition, + div.subtraction { + font-size: 0.875rem; + } + } + } + + &[data-is-positive='true'][data-is-zero='false'] { + color: var(--primary-color); + + &::before { + content: '+'; + } + } + + &[data-is-zero='true'] { + color: #999; + } + + &[data-is-positive='false'] { + color: var(--accent-color); + } + } + + // TODO: use https://github.com/Magickbase/ckb-explorer-frontend/pull/178/files#diff-0f21b8f9c1d917feff4b138db3e62f202f2e3c1b691a2cd309397400edfca591R3 + @media screen and (width <= 1200px) { + padding: 0; + + table { + thead { + display: none; + } + + tbody { + tr { + display: flex; + flex-direction: column; + align-items: stretch; + border-top: 4px solid #ededed; + } + + td { + position: relative; + display: flex; + flex-direction: column; + height: auto; + padding: 0.625rem 1rem; + + &:first-child { + padding-left: 1rem; + max-width: calc(100vw - 2.25rem); + } + + &:last-child { + text-align: left; + } + + &:not(:last-child)::after { + position: absolute; + bottom: 0; + left: 1rem; + right: 1rem; + content: ''; + display: block; + height: 1px; + background: #f5f5f5; + } + + &::before { + content: attr(title); + font-size: 1rem; + color: #666; + margin-bottom: 0.5rem; + } + } + } + } + } +} diff --git a/src/components/LiteTransactionList/index.tsx b/src/components/LiteTransactionList/index.tsx new file mode 100644 index 000000000..2c25feaea --- /dev/null +++ b/src/components/LiteTransactionList/index.tsx @@ -0,0 +1,125 @@ +import { useEffect, useState } from 'react' +import { Link } from 'react-router-dom' +import { useTranslation } from 'react-i18next' +import BigNumber from 'bignumber.js' +import type { Transaction } from '../../models/Transaction' +import { useSearchParams } from '../../hooks' +import styles from './LiteTransactionList.module.scss' +import AddressText from '../AddressText' +import { localeNumberString } from '../../utils/number' +import { useParseDate } from '../../utils/date' +import DecimalCapacity from '../DecimalCapacity' +import { shannonToCkb } from '../../utils/util' + +const LiteTransactionList: React.FC<{ + address?: string + list: Transaction[] +}> = ({ address, list }) => { + const [t] = useTranslation() + const [timeBase, setTimeBase] = useState(Date.now()) + const dateParser = useParseDate() + + useEffect(() => { + const timer = setInterval(() => { + setTimeBase(Date.now()) + }, 1000) + return () => { + clearInterval(timer) + } + }, [setTimeBase]) + + const { tx_status: txStatus } = useSearchParams('tx_status') + + const isPendingListActive = txStatus === 'pending' + + const headers = [ + t('transaction.transaction_hash'), + isPendingListActive ? null : t('transaction.height'), + t('transaction.time'), + `${t('transaction.input')} & ${t('transaction.output')}`, + address ? t('transaction.capacity_change') : null, + ].filter(v => v) + + return ( +
+ + + + {headers.map(header => ( + + ))} + + + + {list.length ? ( + list.map(item => { + let timestamp = 0 + if (item.blockTimestamp) { + timestamp = +item.blockTimestamp + } else if (item.createTimestamp) { + // FIXME: round the timestamp because sometimes a decimal is returned from the API, could be removed when the API is fixed + timestamp = Math.floor(Number(item.createTimestamp)) + } + + const dateTime = new Date(timestamp).toISOString() + const localTime = dateParser(timestamp, timeBase) + + let bigIncome = new BigNumber(item.income) + if (bigIncome.isNaN()) { + bigIncome = new BigNumber(0) + } + const isIncome = bigIncome.isGreaterThanOrEqualTo(0) + return ( + + + {isPendingListActive ? null : ( + + )} + + + {address ? ( + + ) : null} + + ) + }) + ) : ( + + + + )} + +
{header}
+ + {item.transactionHash} + + + + {localeNumberString(item.blockNumber)} + + + + + {`${t('transaction.input')}: ${item.displayInputs.length} ${t('transaction.output')}: ${ + item.displayOutputs.length + }`} + + + + +
+ {t('transaction.no_records')} +
+
+ ) +} + +export default LiteTransactionList diff --git a/src/components/TransactionItem/TransactionLiteIncome/index.module.scss b/src/components/TransactionItem/TransactionLiteIncome/index.module.scss deleted file mode 100644 index 3b4fabb5a..000000000 --- a/src/components/TransactionItem/TransactionLiteIncome/index.module.scss +++ /dev/null @@ -1,26 +0,0 @@ -.transactionLitePanel { - > div { - font-weight: 500; - font-size: 16px; - line-height: 19px; - - > div:not(:last-child) { - font-size: 14px; - line-height: 16px; - } - - @media (width >= 751px) and (width <= 960px) { - > div:not(:last-child) { - display: none; - } - } - } -} - -.increased { - color: var(--primary-color); -} - -.decreased { - color: var(--accent-color); -} diff --git a/src/components/TransactionItem/TransactionLiteIncome/index.tsx b/src/components/TransactionItem/TransactionLiteIncome/index.tsx deleted file mode 100644 index 8f389f742..000000000 --- a/src/components/TransactionItem/TransactionLiteIncome/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import BigNumber from 'bignumber.js' -import classNames from 'classnames' -import { shannonToCkb } from '../../../utils/util' -import { localeNumberString } from '../../../utils/number' -import DecimalCapacity from '../../DecimalCapacity' -import styles from './index.module.scss' - -export default ({ income }: { income: string }) => { - let bigIncome = new BigNumber(income) - if (bigIncome.isNaN()) { - bigIncome = new BigNumber(0) - } - const isIncome = bigIncome.isGreaterThanOrEqualTo(0) - return ( -
- -
- ) -} diff --git a/src/components/TransactionItem/TransactionLiteItem/index.module.scss b/src/components/TransactionItem/TransactionLiteItem/index.module.scss deleted file mode 100644 index dd1a1051c..000000000 --- a/src/components/TransactionItem/TransactionLiteItem/index.module.scss +++ /dev/null @@ -1,119 +0,0 @@ -.transactionLitePanel { - width: 100%; - background-color: #fff; - padding: 0 40px; - display: flex; - - .transactionLiteRow { - width: 100%; - border-top: 1px solid #e5e5e5; - padding: 23px 0; - display: flex; - flex-direction: row; - font-weight: 500; - font-size: 16px; - line-height: 19px; - - .transactionLink { - font-weight: 500; - font-size: 14px; - line-height: 18px; - color: var(--primary-color); - } - - .blockLink { - font-weight: 400; - font-size: 16px; - line-height: 19px; - color: var(--primary-color); - } - - > div { - padding: 0 6px 0 0; - font-weight: 400; - font-size: 16px; - line-height: 19px; - color: #333; - - &:first-child { - width: 28%; - padding-right: 20px; - - @media (width >= 1200px) { - padding-right: 50px; - } - } - - &:nth-child(2) { - width: 13%; - } - - &:nth-child(3) { - width: 20%; - } - - &:nth-child(4) { - width: 27%; - - > span:last-child { - margin-left: 16px; - } - } - - &:last-child { - width: 12%; - text-align: right; - padding: 0; - } - } - } - - @media (width <= 750px) { - padding: 0 16px; - margin-bottom: 4px; - - .transactionLiteRow { - flex-direction: column; - border-top: none; - padding: 0; - - > div { - // This selector is just to increase the specificity. - &:nth-child(n) { - width: 100%; - padding: 16px 0; - } - - > div:first-child { - color: #666; - margin-bottom: 8px; - } - - &:not(:first-child) { - border-top: 1px solid #f0f0f0; - } - } - - > div:first-child { - > a > div { - padding-right: 38px; - } - } - - > div:nth-child(4) { - > span:last-child { - margin-left: 24px; - } - } - - > div:last-child { - text-align: left; - width: 100%; - - > div:last-child > div { - justify-content: flex-start; - } - } - } - } -} diff --git a/src/components/TransactionItem/TransactionLiteItem/index.tsx b/src/components/TransactionItem/TransactionLiteItem/index.tsx deleted file mode 100644 index 2169bce25..000000000 --- a/src/components/TransactionItem/TransactionLiteItem/index.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Link } from 'react-router-dom' -import { useTranslation } from 'react-i18next' -import { localeNumberString } from '../../../utils/number' -import AddressText from '../../AddressText' -import styles from './index.module.scss' -import TransactionLiteIncome from '../TransactionLiteIncome' -import { useIsMobile, useParsedDate } from '../../../hooks' -import { Transaction } from '../../../models/Transaction' - -const TransactionLiteItem = ({ transaction, address }: { transaction: Transaction; address?: string }) => { - const isMobile = useIsMobile() - const { t } = useTranslation() - const parsedBlockCreateAt = useParsedDate(transaction.blockTimestamp) - return ( -
-
-
- {isMobile &&
{t('transaction.transaction_hash')}
} - - {transaction.transactionHash} - -
-
- {isMobile &&
{t('transaction.height')}
} - - {localeNumberString(transaction.blockNumber)} - -
-
- {isMobile &&
{t('transaction.time')}
} - {parsedBlockCreateAt} -
-
- {isMobile &&
{`${t('transaction.input')} & ${t('transaction.output')}`}
} - {transaction.displayInputs && `${t('transaction.input')}: ${transaction.displayInputs.length}`} - - {transaction.displayOutputs && `${t('transaction.output')}: ${transaction.displayOutputs.length}`} - -
-
- {isMobile &&
{t('transaction.capacity_change')}
} - {address && } -
-
-
- ) -} - -export default TransactionLiteItem diff --git a/src/components/TransactionItem/index.tsx b/src/components/TransactionItem/index.tsx index 2112f0201..dedd18f08 100644 --- a/src/components/TransactionItem/index.tsx +++ b/src/components/TransactionItem/index.tsx @@ -17,6 +17,43 @@ export interface CircleCorner { bottom?: boolean } +const Time: React.FC<{ tx?: Transaction }> = ({ tx }) => { + const { t } = useTranslation() + let timestamp = 0 + if (tx) { + if (tx.blockTimestamp) { + timestamp = +tx.blockTimestamp + } else if (tx.createTimestamp) { + // FIXME: round the timestamp because sometimes a decimal is returned from the API, could be removed when the API is fixed + timestamp = Math.floor(Number(tx.createTimestamp)) + } + } + + const dateTime = new Date(timestamp).toISOString() + const localTime = useParsedDate(timestamp) + + if (!tx) { + return null + } + + if (tx.blockTimestamp) { + return ( + + ) + } + + if (tx.createTimestamp) { + return ( + + ) + } + return null +} + const TransactionItem = ({ transaction, address, @@ -51,8 +88,6 @@ const TransactionItem = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []) - const parsedBlockCreateAt = useParsedDate(transaction.blockTimestamp) - return ( {titleCard} @@ -67,11 +102,7 @@ const TransactionItem = ({ > {transaction.transactionHash} - {!isBlock && ( -
- {`(${t('block.block')} ${localeNumberString(transaction.blockNumber)}) ${parsedBlockCreateAt}`} -
- )} +