Skip to content

Commit

Permalink
Improve skeletons (#124)
Browse files Browse the repository at this point in the history
* Add gap to transaction list

* Implement async list layout

* Implement AsyncListLayout on all lists

* Refactor to extract logic

* Implement fees table isLoading

* Memoize components

* Implement async table

* Implement envelope loading

* Add txCount to tab

* Implement PaginatedAsyncList on account elections

* Use txCount
  • Loading branch information
selankon authored Sep 5, 2024
1 parent 8946aa3 commit 00fe05b
Show file tree
Hide file tree
Showing 15 changed files with 456 additions and 383 deletions.
29 changes: 10 additions & 19 deletions src/components/Accounts/Details/Elections.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { Flex } from '@chakra-ui/react'
import { useTranslation } from 'react-i18next'
import { LoadingCards } from '~components/Layout/Loading'
import { RoutedPagination } from '~components/Pagination/Pagination'
import { RoutedPaginationProvider, useRoutedPagination } from '~components/Pagination/PaginationProvider'
import { ElectionCard } from '~components/Process/Card'
import { RoutePath } from '~constants'
import { useOrganizationElections } from '~queries/accounts'
import { ContentError, NoResultsError } from '~components/Layout/ContentError'
import { NoResultsError } from '~components/Layout/ContentError'
import { useOrganization } from '@vocdoni/react-providers'
import { PaginatedAsyncList } from '~components/Layout/AsyncList'

const AccountElections = () => {
const { t } = useTranslation()
Expand Down Expand Up @@ -40,24 +39,16 @@ const AccountElectionsList = () => {
},
})

if (isLoading) {
return <LoadingCards />
}

if (data?.pagination.totalItems === 0) {
return <NoResultsError />
}

if (isError || !data) {
return <ContentError error={error} />
}

return (
<Flex direction={'column'} gap={4}>
{data.elections?.map((election) => {
return <ElectionCard key={election.id} election={election} />
})}
<RoutedPagination pagination={data.pagination} />
<PaginatedAsyncList
isLoading={isLoading}
elements={data?.elections}
isError={isError}
error={error}
pagination={data?.pagination}
component={({ element }) => <ElectionCard key={element.id} election={element} />}
/>
</Flex>
)
}
Expand Down
155 changes: 79 additions & 76 deletions src/components/Accounts/Details/Fees.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { Box, Flex, Link, Table, TableContainer, Tbody, Td, Text, Th, Thead, Tr } from '@chakra-ui/react'
import { Flex, Link, Skeleton, Td, Text, Th, Thead, Tr } from '@chakra-ui/react'
import { useOrganization } from '@vocdoni/react-providers'
import { Fee, TransactionType } from '@vocdoni/sdk'
import { Trans } from 'react-i18next'
import { LoadingCards } from '~components/Layout/Loading'
import { useDateFns } from '~i18n/use-date-fns'
import { TransactionType } from '@vocdoni/sdk'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { PaginatedAsyncTable } from '~components/Layout/AsyncList'
import { PaginationProvider, usePagination } from '~components/Pagination/PaginationProvider'
import { Pagination } from '~components/Pagination/Pagination'
import { useAccountFees } from '~queries/accounts'
import { TransactionTypeBadge } from '~components/Transactions/TransactionCard'
import { generatePath, Link as RouterLink } from 'react-router-dom'
import { RoutePath } from '~constants'
import { ContentError, NoResultsError } from '~components/Layout/ContentError'
import { useOrganization } from '@vocdoni/react-providers'
import { useDateFns } from '~i18n/use-date-fns'
import { useAccountFees } from '~queries/accounts'
import { generateListStub, PaginationStub } from '~utils/stubs'

const AccountFees = () => {
return (
Expand All @@ -22,91 +21,95 @@ const AccountFees = () => {

const AccountFeesTable = () => {
const { page } = usePagination()
const { formatDistance } = useDateFns()
const { organization } = useOrganization()

if (!organization) return null

const feesCount = organization.feesCount ?? 0

const { data, isLoading, isError, error } = useAccountFees({
const { data, isError, error, isPlaceholderData } = useAccountFees({
params: {
accountId: organization.address,
page,
},
options: {
enabled: feesCount > 0,
placeholderData: {
fees: generateListStub<Fee>({
cost: 12,
from: 'string',
height: 12,
reference: 'string',
timestamp: '2024-08-28T15:20:06Z',
txType: 'string',
}),
pagination: PaginationStub,
},
},
})

if (isLoading) {
return <LoadingCards />
}

if (data?.pagination.totalItems === 0 || feesCount === 0) {
return <NoResultsError />
}

if (isError || !data) {
return <ContentError error={error} />
}
return (
<PaginatedAsyncTable
isLoading={isPlaceholderData}
elements={data?.fees}
isError={isError}
error={error}
pagination={data?.pagination}
component={({ element }) => <AccountFeesRow fee={element} isLoading={isPlaceholderData} />}
skeletonProps={{ skeletonCircle: true }}
routedPagination={false}
th={
<Thead>
<Tr>
<Th>
<Trans i18nKey={'account.fees.tx_type'}>Tx Type</Trans>
</Th>
<Th>
<Trans i18nKey={'account.transfers.block'}>Block</Trans>
</Th>
<Th>
<Trans i18nKey={'account.fees.cost'}>Cost</Trans>
</Th>
</Tr>
</Thead>
}
/>
)
}

if (!data.fees.length) {
return (
<Text>
<Trans i18nKey={'account.fees.no_fees'}>No fees yet!</Trans>
</Text>
)
}
const AccountFeesRow = ({ fee, isLoading }: { fee: Fee; isLoading: boolean }) => {
const { formatDistance } = useDateFns()

return (
<>
<Box overflow='auto' w='auto'>
<TableContainer>
<Table>
<Thead>
<Tr>
<Th>
<Trans i18nKey={'account.fees.tx_type'}>Tx Type</Trans>
</Th>
<Th>
<Trans i18nKey={'account.transfers.block'}>Block</Trans>
</Th>
<Th>
<Trans i18nKey={'account.fees.cost'}>Cost</Trans>
</Th>
</Tr>
</Thead>
<Tbody>
{data.fees.map((fee, i) => (
<Tr key={i}>
<Td>
<Flex direction={'column'} align={'start'} gap={3}>
<TransactionTypeBadge transactionType={fee.txType as TransactionType} />
<Text fontWeight={100} color={'lighterText'} fontSize={'sm'}>
{formatDistance(new Date(fee.timestamp), new Date())}
</Text>
</Flex>
</Td>
<Td>
<Link
as={RouterLink}
to={generatePath(RoutePath.Block, { height: fee.height.toString(), tab: null, page: null })}
>
{fee.height}
</Link>
</Td>
<Td>{fee.cost}</Td>
</Tr>
))}
</Tbody>
</Table>
</TableContainer>
</Box>
<Box pt={4}>
<Pagination pagination={data.pagination} />
</Box>
</>
<Tr>
<Td>
<Flex direction={'column'} align={'start'} gap={3}>
<Skeleton isLoaded={!isLoading} fitContent>
<TransactionTypeBadge transactionType={fee.txType as TransactionType} />
</Skeleton>
<Skeleton isLoaded={!isLoading} fitContent>
<Text fontWeight={100} color={'lighterText'} fontSize={'sm'}>
{formatDistance(new Date(fee.timestamp), new Date())}
</Text>
</Skeleton>
</Flex>
</Td>
<Td>
<Skeleton isLoaded={!isLoading} fitContent>
<Link
as={RouterLink}
to={generatePath(RoutePath.Block, { height: fee.height.toString(), tab: null, page: null })}
>
{fee.height}
</Link>
</Skeleton>
</Td>
<Td>
<Skeleton isLoaded={!isLoading} fitContent>
{fee.cost}
</Skeleton>
</Td>
</Tr>
)
}

Expand Down
Loading

2 comments on commit 00fe05b

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.