diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 675d21d..fcc7d71 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -11,6 +11,8 @@ module.exports = { parser: '@typescript-eslint/parser', plugins: ['react-refresh'], rules: { + 'no-unused-expressions': 'off', + '@typescript-eslint/no-unused-expressions': 'off', 'react-hooks/exhaustive-deps': [ 'warn', { diff --git a/src/components/DelegateCard.tsx b/src/components/DelegateCard.tsx index 824e17d..abe63d7 100644 --- a/src/components/DelegateCard.tsx +++ b/src/components/DelegateCard.tsx @@ -1,18 +1,9 @@ import { Button } from '@/components/ui/button' import { Card } from '@/components/ui/card' -import { Check, Copy, Ellipsis } from 'lucide-react' -import { - Dialog, - DialogContent, - DialogDescription, - DialogHeader, - DialogTrigger, -} from '@/components/ui/dialog' -import { ellipsisFn } from '@polkadot-ui/utils' import { useNavigate } from 'react-router-dom' -import copy from 'copy-to-clipboard' import { useEffect, useState } from 'react' import { Delegate } from '@/contexts/DelegatesContext' +import { ContentReveal } from './ui/content-reveal' interface Props { delegate: Delegate @@ -30,6 +21,7 @@ export const DelegateCard = ({ delegate: d }: Props) => { const onDelegate = () => { navigate(`/delegate/${d.address}`) } + return ( @@ -37,43 +29,19 @@ export const DelegateCard = ({ delegate: d }: Props) => { - {d.name} - {d.shortDescription} - - Delegate - + {d.name} + {d.shortDescription} + + {d.longDescription} + - - - - - - - - - {d.name} - - - {ellipsisFn(d.address)} - - {copied ? ( - - ) : ( - { - setCopied(true) - copy(d.address) - }} - /> - )} - - - - {d.longDescription} - - - + + Delegate + diff --git a/src/components/LocksCard.tsx b/src/components/LocksCard.tsx index e8c4033..71091b6 100644 --- a/src/components/LocksCard.tsx +++ b/src/components/LocksCard.tsx @@ -17,6 +17,7 @@ import { useAccounts } from '@/contexts/AccountsContext' import { TypedApi } from 'polkadot-api' import { getUnlockUnvoteTx } from '@/lib/utils' import { useLocks, VoteLock } from '@/contexts/LocksContext' +import { Skeleton } from './ui/skeleton' export const LocksCard = () => { const [currentBlock, setCurrentBlock] = useState(0) @@ -26,6 +27,7 @@ export const LocksCard = () => { const { assetInfo } = useNetwork() const [ongoingVoteLocks, setOngoingVoteLocks] = useState([]) const [freeLocks, setFreeLocks] = useState([]) + const [locksLoaded, setLocksLoaded] = useState(false) const [currentLocks, setCurrentLocks] = useState([]) const { selectedAccount } = useAccounts() const [isUnlockingLoading, setIsUnlockingLoading] = useState(false) @@ -50,6 +52,7 @@ export const LocksCard = () => { setOngoingVoteLocks(tempOngoingLocks) setFreeLocks(tempFree) setCurrentLocks(tempCurrent) + setLocksLoaded(true) }, [currentBlock, locks]) useEffect(() => { @@ -100,9 +103,6 @@ export const LocksCard = () => { }) }, [api, freeLocks, selectedAccount]) - if (!ongoingVoteLocks?.length && !freeLocks?.length && !currentLocks.length) - return null - return ( {freeLocks.length > 0 && ( @@ -145,62 +145,71 @@ export const LocksCard = () => { )} - {currentLocks.length > 0 && ( - - Locked - - {currentLocks.length} - - - - {currentLocks.map(({ amount, endBlock, refId }) => { - const remainingTimeMs = - (Number(endBlock) - currentBlock) * expectedBlockTime - const remainingDisplay = convertMiliseconds(remainingTimeMs) - return ( - - - - #{refId}{' '} - {planckToUnit(amount, assetInfo.precision).toLocaleString( - 'en', - )}{' '} - {assetInfo.symbol} - - Remaining: {displayRemainingTime(remainingDisplay)} - - - - ) - })} - - - )} - {ongoingVoteLocks.length > 0 && ( - - Votes - - {ongoingVoteLocks.length} - - - - {ongoingVoteLocks.map(({ amount, refId }) => { - return ( - - - - #{refId}{' '} - {planckToUnit(amount, assetInfo.precision).toLocaleString( - 'en', - )}{' '} - {assetInfo.symbol} - - - - ) - })} - - + {!locksLoaded ? ( + <> + + + > + ) : ( + <> + + Locked + + {currentLocks.length} + + + + {currentLocks.map(({ amount, endBlock, refId }) => { + const remainingTimeMs = + (Number(endBlock) - currentBlock) * expectedBlockTime + const remainingDisplay = convertMiliseconds(remainingTimeMs) + return ( + + + + #{refId}{' '} + {planckToUnit( + amount, + assetInfo.precision, + ).toLocaleString('en')}{' '} + {assetInfo.symbol} + + Remaining: {displayRemainingTime(remainingDisplay)} + + + + ) + })} + + + + Votes + + {ongoingVoteLocks.length} + + + { + + {ongoingVoteLocks.map(({ amount, refId }) => { + return ( + + + + #{refId}{' '} + {planckToUnit( + amount, + assetInfo.precision, + ).toLocaleString('en')}{' '} + {assetInfo.symbol} + + + + ) + })} + + } + + > )} ) diff --git a/src/components/ui/content-reveal.tsx b/src/components/ui/content-reveal.tsx index 25d1b3c..704a27c 100644 --- a/src/components/ui/content-reveal.tsx +++ b/src/components/ui/content-reveal.tsx @@ -1,19 +1,33 @@ +import { cn } from '@/lib/utils' import { ChevronDown } from 'lucide-react' -import { useState } from 'react' +import { useEffect, useState } from 'react' type Props = { children: React.ReactNode className?: string + hidden?: boolean } -export const ContentReveal = ({ children, className }: Props) => { +export const ContentReveal = ({ children, className, hidden }: Props) => { const [isOpen, setIsOpen] = useState(false) + useEffect(() => { + if (hidden) { + setIsOpen(false) + } + }, [hidden]) + return ( setIsOpen(!isOpen)} - className="flex w-full items-center justify-center" + onClick={() => { + !hidden && setIsOpen(!isOpen) + }} + className={cn( + `flex w-full items-center justify-center`, + hidden && 'opacity-0', + )} + disabled={hidden} > ) { + return ( + + ) +} + +export { Skeleton }