Commit 818e9832 authored by Jack Short's avatar Jack Short Committed by GitHub

style: adding loading state for asset activity (#5503)

* style: adding loading state for asset activity

* translations

* previous translations did not work
parent aa3225c2
import { Trans } from '@lingui/macro'
import { OpacityHoverState, ScrollBarStyles } from 'components/Common' import { OpacityHoverState, ScrollBarStyles } from 'components/Common'
import { LoadingBubble } from 'components/Tokens/loading'
import { EventCell, MarketplaceIcon } from 'nft/components/collection/ActivityCells'
import { ActivityEventResponse } from 'nft/types' import { ActivityEventResponse } from 'nft/types'
import { shortenAddress } from 'nft/utils/address' import { shortenAddress } from 'nft/utils/address'
import { formatEthPrice } from 'nft/utils/currency' import { formatEthPrice } from 'nft/utils/currency'
import { getTimeDifference } from 'nft/utils/date' import { getTimeDifference } from 'nft/utils/date'
import { putCommas } from 'nft/utils/putCommas' import { putCommas } from 'nft/utils/putCommas'
import { ReactNode } from 'react'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import { EventCell } from '../collection/ActivityCells'
import { MarketplaceIcon } from '../collection/ActivityCells'
const TR = styled.tr` const TR = styled.tr`
border-bottom: ${({ theme }) => `1px solid ${theme.backgroundOutline}`}; border-bottom: ${({ theme }) => `1px solid ${theme.backgroundOutline}`};
width: 100%; width: 100%;
...@@ -84,75 +85,116 @@ const ActivityContainer = styled.div` ...@@ -84,75 +85,116 @@ const ActivityContainer = styled.div`
${ScrollBarStyles} ${ScrollBarStyles}
` `
const AssetActivity = ({ eventsData }: { eventsData: ActivityEventResponse | undefined }) => { const LoadingCell = styled(LoadingBubble)`
height: 20px;
width: 80px;
`
const ActivityTable = ({ children }: { children: ReactNode }) => {
return ( return (
<ActivityContainer id="activityContainer"> <ActivityContainer id="activityContainer">
<Table> <Table>
<thead> <thead>
<TR> <TR>
<TH>Event</TH> <TH>
<TH>Price</TH> <Trans>Event</Trans>
<TH>By</TH> </TH>
<TH>To</TH> <TH>
<TH>Time</TH> <Trans>Price</Trans>
</TH>
<TH>
<Trans>By</Trans>
</TH>
<TH>
<Trans>To</Trans>
</TH>
<TH>
<Trans>Time</Trans>
</TH>
</TR> </TR>
</thead> </thead>
<tbody> <tbody>{children}</tbody>
{eventsData?.events &&
eventsData.events.map((event, index) => {
const { eventTimestamp, eventType, fromAddress, marketplace, price, toAddress, transactionHash } = event
const formattedPrice = price ? putCommas(formatEthPrice(price)).toString() : null
return (
<TR key={index}>
<TD>
<EventCell
eventType={eventType}
eventTimestamp={eventTimestamp}
eventTransactionHash={transactionHash}
eventOnly
/>
</TD>
<TD>
{formattedPrice && (
<PriceContainer>
{marketplace && <MarketplaceIcon marketplace={marketplace} />}
{formattedPrice} ETH
</PriceContainer>
)}
</TD>
<TD>
{fromAddress && (
<Link
href={`https://etherscan.io/address/${fromAddress}`}
target="_blank"
rel="noopener noreferrer"
>
{shortenAddress(fromAddress, 2, 4)}
</Link>
)}
</TD>
<TD>
{toAddress && (
<Link
href={`https://etherscan.io/address/${toAddress}`}
target="_blank"
rel="noopener noreferrer"
>
{shortenAddress(toAddress, 2, 4)}
</Link>
)}
</TD>
<TD>{eventTimestamp && getTimeDifference(eventTimestamp.toString())}</TD>
</TR>
)
})}
</tbody>
</Table> </Table>
</ActivityContainer> </ActivityContainer>
) )
} }
const LoadingAssetActivityRow = ({ cellCount }: { cellCount: number }) => {
return (
<TR>
{Array(cellCount)
.fill(null)
.map((_, index) => {
return (
<TD key={index}>
<LoadingCell />
</TD>
)
})}
</TR>
)
}
export const LoadingAssetActivity = ({ rowCount }: { rowCount: number }) => {
return (
<ActivityTable>
{Array(rowCount)
.fill(null)
.map((_, index) => {
return <LoadingAssetActivityRow key={index} cellCount={5} />
})}
</ActivityTable>
)
}
const AssetActivity = ({ eventsData }: { eventsData: ActivityEventResponse | undefined }) => {
return (
<ActivityTable>
{eventsData?.events &&
eventsData.events.map((event, index) => {
const { eventTimestamp, eventType, fromAddress, marketplace, price, toAddress, transactionHash } = event
const formattedPrice = price ? putCommas(formatEthPrice(price)).toString() : null
return (
<TR key={index}>
<TD>
<EventCell
eventType={eventType}
eventTimestamp={eventTimestamp}
eventTransactionHash={transactionHash}
eventOnly
/>
</TD>
<TD>
{formattedPrice && (
<PriceContainer>
{marketplace && <MarketplaceIcon marketplace={marketplace} />}
{formattedPrice} ETH
</PriceContainer>
)}
</TD>
<TD>
{fromAddress && (
<Link href={`https://etherscan.io/address/${fromAddress}`} target="_blank" rel="noopener noreferrer">
{shortenAddress(fromAddress, 2, 4)}
</Link>
)}
</TD>
<TD>
{toAddress && (
<Link href={`https://etherscan.io/address/${toAddress}`} target="_blank" rel="noopener noreferrer">
{shortenAddress(toAddress, 2, 4)}
</Link>
)}
</TD>
<TD>{eventTimestamp && getTimeDifference(eventTimestamp.toString())}</TD>
</TR>
)
})}
</ActivityTable>
)
}
export default AssetActivity export default AssetActivity
...@@ -22,7 +22,7 @@ import { Link as RouterLink } from 'react-router-dom' ...@@ -22,7 +22,7 @@ import { Link as RouterLink } from 'react-router-dom'
import { useIsDarkMode } from 'state/user/hooks' import { useIsDarkMode } from 'state/user/hooks'
import styled from 'styled-components/macro' import styled from 'styled-components/macro'
import AssetActivity from './AssetActivity' import AssetActivity, { LoadingAssetActivity } from './AssetActivity'
import * as styles from './AssetDetails.css' import * as styles from './AssetDetails.css'
import DetailsContainer from './DetailsContainer' import DetailsContainer from './DetailsContainer'
import InfoContainer from './InfoContainer' import InfoContainer from './InfoContainer'
...@@ -312,6 +312,7 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -312,6 +312,7 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
hasNextPage, hasNextPage,
isFetchingNextPage, isFetchingNextPage,
isSuccess, isSuccess,
isLoading: isActivityLoading,
} = useInfiniteQuery<ActivityEventResponse>( } = useInfiniteQuery<ActivityEventResponse>(
[ [
'collectionActivity', 'collectionActivity',
...@@ -410,16 +411,17 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -410,16 +411,17 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
<Filter eventType={ActivityEventType.Transfer} /> <Filter eventType={ActivityEventType.Transfer} />
<Filter eventType={ActivityEventType.CancelListing} /> <Filter eventType={ActivityEventType.CancelListing} />
</ActivitySelectContainer> </ActivitySelectContainer>
{isActivityLoading && <LoadingAssetActivity rowCount={10} />}
{events && events.length > 0 ? ( {events && events.length > 0 ? (
<InfiniteScroll <InfiniteScroll
next={fetchNextPage} next={fetchNextPage}
hasMore={!!hasNextPage} hasMore={!!hasNextPage}
loader={ loader={
isFetchingNextPage ? ( isFetchingNextPage && (
<Center> <Center>
<LoadingSparkle /> <LoadingSparkle />
</Center> </Center>
) : null )
} }
dataLength={events?.length ?? 0} dataLength={events?.length ?? 0}
scrollableTarget="activityContainer" scrollableTarget="activityContainer"
...@@ -427,10 +429,14 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => { ...@@ -427,10 +429,14 @@ export const AssetDetails = ({ asset, collection }: AssetDetailsProps) => {
<AssetActivity eventsData={{ events }} /> <AssetActivity eventsData={{ events }} />
</InfiniteScroll> </InfiniteScroll>
) : ( ) : (
<EmptyActivitiesContainer> <>
<div>No activities yet</div> {!isActivityLoading && (
<Link to={`/nfts/collection/${asset.address}`}>View collection items</Link>{' '} <EmptyActivitiesContainer>
</EmptyActivitiesContainer> <div>No activities yet</div>
<Link to={`/nfts/collection/${asset.address}`}>View collection items</Link>{' '}
</EmptyActivitiesContainer>
)}
</>
)} )}
</> </>
</InfoContainer> </InfoContainer>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment