Skip to content
7 changes: 7 additions & 0 deletions src/assets/scss/components/_datatable.scss
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ table {
.table-data {
flex: 1;
flex-grow: 1;

// This style is for parent container injected by react-skeleton.
span[aria-live=polite] {
flex: 1;
align-items: center;
justify-content: center;
}
}

.table-data-container {
Expand Down
4 changes: 3 additions & 1 deletion src/components/Dashboard/DashboardHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface DashboardHeaderProps {
export const DashboardHeader: FC<DashboardHeaderProps> = ({
showInfo = false
}) => {
const { totalBorrow: totalMarketBorrow, totalSupply: totalMarketSupply } =
const { totalBorrow: totalMarketBorrow, totalSupply: totalMarketSupply, isMarketLoading } =
useMarketData()

return (
Expand All @@ -25,6 +25,7 @@ export const DashboardHeader: FC<DashboardHeaderProps> = ({
value={convertBigIntValueToNormal(totalMarketSupply)}
size={18}
countUp={true}
isLoading={isMarketLoading}
/>
{/* <ChipRate direction="up" value={10} /> */}
</div>
Expand All @@ -35,6 +36,7 @@ export const DashboardHeader: FC<DashboardHeaderProps> = ({
value={convertBigIntValueToNormal(totalMarketBorrow)}
size={18}
countUp={true}
isLoading={isMarketLoading}
/>
{/* <ChipRate direction="down" value={20} /> */}
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/components/Dashboard/DashboardTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { LiquidityTooltip } from '../LiquidityTooltip'
import { type IDashboardData } from '@/@types/store.types'

export const DashboardTable: FC = () => {
const { data: dashboardData } = useDashboardData()
const { data: dashboardData, isDashboardLoading } = useDashboardData()

const [supplyChainFilter, setSupplyChainFilter] = useState<
tSupportedChains[]
Expand Down Expand Up @@ -64,6 +64,7 @@ export const DashboardTable: FC = () => {
onChangeFilterChange={onChangeSupplyChains}
type="supply"
key="dashboard-supply"
isLoading={isDashboardLoading}
/>
</div>
<div className="section-card">
Expand All @@ -78,6 +79,7 @@ export const DashboardTable: FC = () => {
type="borrow"
key="dashboard-borrow"
onChangeFilterChange={onChangeBorrowChains}
isLoading={isDashboardLoading}
/>
</div>
<LiquidityTooltip id="liquidity-tooltip-supply" />
Expand Down
24 changes: 15 additions & 9 deletions src/components/Datatable/AccordionTable.component.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { type FC, useState, useEffect } from 'react'
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import { type FC, useState, useEffect, useMemo } from 'react'
import {
flexRender,
getCoreRowModel,
Expand All @@ -15,6 +18,7 @@ import { type tSupportedChains } from '@cedro-finance/sdk'
import type { IDashboardData } from '@/@types/store.types'
import { cedroClient } from '@/configs/chainConfig'
import { type AccordionTableProps, type DatatableRowDetailsProps, type TableCellProps } from '@/@types'
import Skeleton from 'react-loading-skeleton'

/* eslint-disable no-unused-vars */
/* eslint-disable @typescript-eslint/no-invalid-void-type */
Expand All @@ -38,9 +42,17 @@ export function AccordionTable <T> (props: AccordionTableProps<T>): JSX.Element

const { title, data, columns, onRowClick, showChainFilter = false, noData, isAccordionRow, isLoading } = props

const tableData = useMemo(
() => (isLoading ? Array(10).fill({}) : data),
[isLoading, data]
)

// columns with skeleton in cell. The cell will replace skeleton with data once loading state is false.
const tableColums = useMemo(() => isLoading ? columns.map(column => ({ ...column, cell: () => <Skeleton borderRadius={10} width={'90%'} height={40} /> })) : columns, [isLoading, columns])

const { getHeaderGroups, getRowModel } = useReactTable({
data: data ?? [],
columns: columns ?? [],
data: tableData ?? [],
columns: tableColums ?? [],
state: {
sorting
},
Expand Down Expand Up @@ -112,12 +124,6 @@ export function AccordionTable <T> (props: AccordionTableProps<T>): JSX.Element

<div className="table-data-container">

{(isLoading) && (
<div className="datatable-loader">
<Icon name="spinner" height={50} width={50} />
</div>
)}

{(!isLoading && data.length <= 0) && (
<div className='no-data-ui'>
{noData ?? ''}
Expand Down
22 changes: 12 additions & 10 deletions src/components/Navbar/AvailableTokens.component.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { TokenIconMapping } from '@/constants'
import { truncateString, toFixedCutZero, toFixedNumber } from '@/utils'
import { truncateString } from '@/utils'
import { getIconName } from '@/utils/misc'
import { Dropdown } from '../Dropdown'
import { Icon } from '../icon'
Expand All @@ -8,11 +8,12 @@ import { useAvailableBalance } from '@/hooks/useAvailableBalance'
import { type FC } from 'react'
import { toast } from 'react-toastify'
import { cedroClient } from '@/configs/chainConfig'
import { ValueWithPrice } from '../Price'

export const AvailableTokens: FC = () => {
const { disconnect } = useDisconnect()
const { address, connector } = useAccount()
const { tokenBalances } = useAvailableBalance()
const { tokenBalances, isLoading } = useAvailableBalance()

const copyAddress = (): void => {
navigator.clipboard.writeText(address ?? '')
Expand All @@ -36,21 +37,22 @@ export const AvailableTokens: FC = () => {
const chain = cedroClient.Config.getChainConfig(token.chain)
return (
<Dropdown.Item key={token.chain}>
<div className='token'>
<div className="token">
<div className="token-name">
<div>
<Icon name={TokenIconMapping[token.poolId]} height={30} width={30} />
<Icon
name={TokenIconMapping[token.poolId]}
height={30}
width={30}
/>
</div>
<div>
<div className='token-symbol'>{tokenSymbol}</div>
<div className='chain-name'>{chain.name}</div>
<div className="token-symbol">{tokenSymbol}</div>
<div className="chain-name">{chain.name}</div>
</div>
</div>
<div className="token-balance">
<div className="token-amt" style={{ fontWeight: 600, fontSize: '18px' }}>
{toFixedNumber(token.balance.formatted, 4, true)}
</div>
<div className="dollar-amt" style={{ fontSize: '14px' }}>$ {toFixedCutZero((+(token.balance?.usd ?? 0)).toString(), 2, true)}</div>
<ValueWithPrice pool={token.poolId} value={(token.balance.formatted)} isLoading={isLoading} />
</div>
</div>
</Dropdown.Item>
Expand Down
5 changes: 3 additions & 2 deletions src/components/Navbar/NavbarSharedCompoent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { ChainFormatters } from 'viem'
import type { ChainConstants, ChainConfig } from 'viem/_types/types/chain'
import type { tSupportedChains } from '@cedro-finance/sdk'
import { NETWORK_TYPE } from '@/configs/env'
import Skeleton from 'react-loading-skeleton'

type ConnectedChain = (ChainConstants & ChainConfig<ChainFormatters | undefined> & {
unsupported?: boolean | undefined
Expand Down Expand Up @@ -76,7 +77,7 @@ export const SwitchNetworkDropdown: FC = () => {
export const WalletActions: FC = () => {
const [isGetTokenModalActive, setGetTokenModalState] = useState(false)
const { isConnected: isWalletConnected } = useAccount()
const { aggregateDollarValue } = useAvailableBalance()
const { aggregateDollarValue, isLoading } = useAvailableBalance()

return (
<>
Expand Down Expand Up @@ -106,7 +107,7 @@ export const WalletActions: FC = () => {

<div className="wallet-info">
<span className="wallet-balance">
$ {toFixedCutZero(aggregateDollarValue.toString() ?? '', 2, true)}
$ {isLoading ? <Skeleton width={50} style={{ marginRight: 5, opacity: 0.7 }} /> : toFixedCutZero(aggregateDollarValue.toString() ?? '', 2, true)}
</span>
<AvailableTokens />
</div>
Expand Down
59 changes: 43 additions & 16 deletions src/components/Price/Price.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,35 @@ import { parseUnits } from 'viem'
import CountUp from 'react-countup'
import { useAppSelector } from '@/hooks'
import { getTokenSymbol } from '@/constants'
import Skeleton from 'react-loading-skeleton'

interface PriceProps {
value: string
size?: number
countUp?: boolean
isLoading?: boolean
}

export const Price: FC<PriceProps> = ({ value, size, countUp = false }) => {
export const Price: FC<PriceProps> = ({ value, size, countUp = false, isLoading = false }) => {
const price = parseFloat(toFixedCutZero(value, 2, true).replace(/,/g, ''))

return (
<div className="price-only" style={{ fontSize: size }}>
<span>$</span>
{
countUp
? (<span>
<CountUp end={price} duration={1} decimals={2} />
</span>)
: (<span>{toFixedCutZero(price.toString(), 2, true)}</span>
)
}
</div>
<div className="price-only" style={{ fontSize: size }}>
<span>$</span>
{isLoading
? (
<Skeleton width={100} style={{ marginLeft: 5 }} />
)
: countUp
? (
<span>
<CountUp end={price} duration={1} decimals={2} />
</span>
)
: (
<span>{toFixedCutZero(price.toString(), 2, true)}</span>
)}
</div>
)
}

Expand All @@ -36,9 +43,10 @@ export interface IValueWithPriceProps {
displayUnit?: boolean
variant?: 'primary' | 'secondary'
unit?: string
isLoading?: boolean
}

export const ValueWithPrice: FC<IValueWithPriceProps> = ({ pool, value, displayUnit = false, unit, variant = 'primary' }) => {
export const ValueWithPrice: FC<IValueWithPriceProps> = ({ pool, value, displayUnit = false, unit, variant = 'primary', isLoading = false }) => {
const { oraclePrices } = useAppSelector(state => state.pool)

const poolPrice = useMemo(() => {
Expand All @@ -58,10 +66,29 @@ export const ValueWithPrice: FC<IValueWithPriceProps> = ({ pool, value, displayU
<div>
{/* TODO should the precision be 4 for tokens? */}
<div className="price-label" style={{ fontWeight: 600 }}>
<span className="number">{toFixedNumber(value, 4, true)}</span>{' '}
<span className="unit">{displayUnit ? unit ?? getTokenSymbol(pool) : ''}</span>
<span className="number">
{isLoading
? (
<Skeleton width={100} />
)
: (
toFixedNumber(value, 4, true)
)}
</span>
<span className="unit">
{displayUnit ? unit ?? getTokenSymbol(pool) : ''}
</span>
</div>
<div className="price-value">
$
{isLoading
? (
<Skeleton width={75} style={{ marginLeft: 5 }} />
)
: (
toFixedCutZero(dollarEquivalent, 2, true)
)}
</div>
<div className="price-value">${toFixedCutZero(dollarEquivalent, 2, true)}</div>
</div>
</div>
)
Expand Down
18 changes: 12 additions & 6 deletions src/containers/dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,18 @@ import { useTokenBalances } from '@/store/chain'
import { cedroClient } from '@/configs/chainConfig'
import { Link } from 'react-router-dom'
import { parseUnits } from 'viem'
import Skeleton from 'react-loading-skeleton'

export function Dashboard (): JSX.Element {
const [trigger, { data, isLoading }] = useLazyGetDashboardTrendQuery()

const { address } = useAccount()
const [borrowLimit] = useBorrowLimit()
const { healthFactor, userPoolBalances } = useAppSelector(
const { healthFactor, userPoolBalances, dashboardDataFetchStatus } = useAppSelector(
(state) => state.dashboard
)
const { totalInterest } = useDashboardData()
const { aggregateDollarValue } = useAvailableBalance()
const { totalInterest, isDashboardLoading } = useDashboardData()
const { aggregateDollarValue, isLoading: isAvailableBalanceLoading } = useAvailableBalance()
const userBalances = useTokenBalances()

const getPoolDetails = useGetPoolDetails()
Expand Down Expand Up @@ -164,15 +165,18 @@ export function Dashboard (): JSX.Element {
)}
size={46}
countUp={true}
isLoading={dashboardDataFetchStatus === 'loading'}
/>
</div>
<div className="available-balance">
Available:{' '}
{`$${toFixedCutZero(
$ { isAvailableBalanceLoading
? <Skeleton width={50} />
: toFixedCutZero(
aggregateDollarValue.toString(),
2,
true
)}`}
) }
</div>
</div>

Expand Down Expand Up @@ -210,6 +214,7 @@ export function Dashboard (): JSX.Element {
value={convertBigIntValueToNormal(totalInterest)}
size={18}
countUp
isLoading={isDashboardLoading}
/>
</div>
</div>
Expand All @@ -233,11 +238,12 @@ export function Dashboard (): JSX.Element {
value={convertBigIntValueToNormal(healthFactor.debtValue)}
size={46}
countUp={true}
isLoading={dashboardDataFetchStatus === 'loading'}
/>
</div>
<div className="available-balance">
Available:{' '}
{`$${convertBigIntValueToNormal(borrowLimit, 18, 2, true)}`}
$ {dashboardDataFetchStatus === 'loading' ? <Skeleton width={50} /> : convertBigIntValueToNormal(borrowLimit, 18, 2, true)}
</div>
</div>

Expand Down
6 changes: 5 additions & 1 deletion src/containers/market.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,8 @@ export const Market: FC = () => {
const {
tableData: dashboardData,
totalBorrow,
totalSupply
totalSupply,
isMarketLoading
} = useMarketData()
const { data, isLoading } = useGetMarketTrendQuery({})

Expand Down Expand Up @@ -324,6 +325,7 @@ export const Market: FC = () => {
value={convertBigIntValueToNormal(totalSupply)}
size={46}
countUp
isLoading={isMarketLoading}
/>
</div>
<ChipRate
Expand All @@ -350,6 +352,7 @@ export const Market: FC = () => {
value={convertBigIntValueToNormal(totalBorrow)}
size={46}
countUp
isLoading={isMarketLoading}
/>
</div>

Expand All @@ -376,6 +379,7 @@ export const Market: FC = () => {
showChainFilter={true}
onChangeFilterChange={(chains) => { setSelectedChains(chains) }}
onRowClick={handleRowClick}
isLoading={isMarketLoading}
/>
</div>
<LiquidityTooltip id = "liquidity-tooltip"/>
Expand Down
Loading