Skip to content

Commit

Permalink
Redesign delegate cards and make ContentReveal available only when no… (
Browse files Browse the repository at this point in the history
#74)

Co-authored-by: Thibaut Sardan <[email protected]>
  • Loading branch information
wirednkod and Tbaut authored Sep 1, 2024
1 parent 2c53d8b commit 32bc4f6
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 109 deletions.
2 changes: 2 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -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',
{
Expand Down
60 changes: 14 additions & 46 deletions src/components/DelegateCard.tsx
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -30,50 +21,27 @@ export const DelegateCard = ({ delegate: d }: Props) => {
const onDelegate = () => {
navigate(`/delegate/${d.address}`)
}

return (
<Card className="mb-5 flex flex-col border-2 p-2">
<div className="flex columns-3">
<div className="w-[10%] p-2">
<img className="rounded-3xl" width="100" src={d.image} />
</div>
<div className="w-[85%] p-2">
<div className="font-bold">{d.name}</div>
<div className="">{d.shortDescription}</div>
<Button variant="default" className="mt-2" onClick={onDelegate}>
Delegate
</Button>
<div className="py-2 text-xl font-bold text-primary">{d.name}</div>
<div>{d.shortDescription}</div>
<ContentReveal
hidden={
d.shortDescription === d.longDescription || !d.longDescription
}
>
{d.longDescription}
</ContentReveal>
</div>
<Dialog>
<DialogTrigger asChild>
<Button variant={'outline'} className="text-xs">
<Ellipsis className="text-xs" />
</Button>
</DialogTrigger>
<DialogContent className="">
<DialogHeader>
<div className="font-bold">{d.name}</div>
</DialogHeader>
<DialogDescription className="flex">
<div>{ellipsisFn(d.address)}</div>
<div className="cursor-pointer pl-4">
{copied ? (
<Check className="text-[green]" />
) : (
<Copy
className="cursor-pointer"
onClick={() => {
setCopied(true)
copy(d.address)
}}
/>
)}
</div>
</DialogDescription>
<div className="grid py-4">
<div className="items-center">{d.longDescription}</div>
</div>
</DialogContent>
</Dialog>
<Button variant="default" onClick={onDelegate} className="">
Delegate
</Button>
</div>
<div className="w-full"></div>
</Card>
Expand Down
127 changes: 68 additions & 59 deletions src/components/LocksCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -26,6 +27,7 @@ export const LocksCard = () => {
const { assetInfo } = useNetwork()
const [ongoingVoteLocks, setOngoingVoteLocks] = useState<VoteLock[]>([])
const [freeLocks, setFreeLocks] = useState<VoteLock[]>([])
const [locksLoaded, setLocksLoaded] = useState<boolean>(false)
const [currentLocks, setCurrentLocks] = useState<VoteLock[]>([])
const { selectedAccount } = useAccounts()
const [isUnlockingLoading, setIsUnlockingLoading] = useState(false)
Expand All @@ -50,6 +52,7 @@ export const LocksCard = () => {
setOngoingVoteLocks(tempOngoingLocks)
setFreeLocks(tempFree)
setCurrentLocks(tempCurrent)
setLocksLoaded(true)
}, [currentBlock, locks])

useEffect(() => {
Expand Down Expand Up @@ -100,9 +103,6 @@ export const LocksCard = () => {
})
}, [api, freeLocks, selectedAccount])

if (!ongoingVoteLocks?.length && !freeLocks?.length && !currentLocks.length)
return null

return (
<div className="flex w-full gap-x-2">
{freeLocks.length > 0 && (
Expand Down Expand Up @@ -145,62 +145,71 @@ export const LocksCard = () => {
</div>
</Card>
)}
{currentLocks.length > 0 && (
<Card className="h-full w-4/12 border-2 p-2 px-4">
<Title variant="h4">Locked</Title>
<div className="text-5xl font-bold">
{currentLocks.length}
<Clock2 className="inline-block h-8 w-8 rotate-[10deg] text-gray-200" />
</div>
<ContentReveal>
{currentLocks.map(({ amount, endBlock, refId }) => {
const remainingTimeMs =
(Number(endBlock) - currentBlock) * expectedBlockTime
const remainingDisplay = convertMiliseconds(remainingTimeMs)
return (
<div key={refId}>
<ul>
<li>
<Badge>#{refId}</Badge>{' '}
{planckToUnit(amount, assetInfo.precision).toLocaleString(
'en',
)}{' '}
{assetInfo.symbol}
<br />
Remaining: {displayRemainingTime(remainingDisplay)}
</li>
</ul>
</div>
)
})}
</ContentReveal>
</Card>
)}
{ongoingVoteLocks.length > 0 && (
<Card className="h-full w-4/12 border-2 p-2 px-4">
<Title variant="h4">Votes</Title>
<div className="text-5xl font-bold">
{ongoingVoteLocks.length}
<Vote className="inline-block h-8 w-8 text-gray-200" />
</div>
<ContentReveal>
{ongoingVoteLocks.map(({ amount, refId }) => {
return (
<div key={refId}>
<ul>
<li>
<Badge>#{refId}</Badge>{' '}
{planckToUnit(amount, assetInfo.precision).toLocaleString(
'en',
)}{' '}
{assetInfo.symbol}
</li>
</ul>
</div>
)
})}
</ContentReveal>
</Card>
{!locksLoaded ? (
<>
<Skeleton className="h-[116px] w-4/12 rounded-xl" />
<Skeleton className="h-[116px] w-4/12 rounded-xl" />
</>
) : (
<>
<Card className="h-full w-4/12 border-2 p-2 px-4">
<Title variant="h4">Locked</Title>
<div className="text-5xl font-bold">
{currentLocks.length}
<Clock2 className="inline-block h-8 w-8 rotate-[10deg] text-gray-200" />
</div>
<ContentReveal hidden={!currentLocks.length}>
{currentLocks.map(({ amount, endBlock, refId }) => {
const remainingTimeMs =
(Number(endBlock) - currentBlock) * expectedBlockTime
const remainingDisplay = convertMiliseconds(remainingTimeMs)
return (
<div key={refId}>
<ul>
<li>
<Badge>#{refId}</Badge>{' '}
{planckToUnit(
amount,
assetInfo.precision,
).toLocaleString('en')}{' '}
{assetInfo.symbol}
<br />
Remaining: {displayRemainingTime(remainingDisplay)}
</li>
</ul>
</div>
)
})}
</ContentReveal>
</Card>
<Card className="h-full w-4/12 border-2 p-2 px-4">
<Title variant="h4">Votes</Title>
<div className="text-5xl font-bold">
{ongoingVoteLocks.length}
<Vote className="inline-block h-8 w-8 text-gray-200" />
</div>
{
<ContentReveal hidden={!ongoingVoteLocks.length}>
{ongoingVoteLocks.map(({ amount, refId }) => {
return (
<div key={refId}>
<ul>
<li>
<Badge>#{refId}</Badge>{' '}
{planckToUnit(
amount,
assetInfo.precision,
).toLocaleString('en')}{' '}
{assetInfo.symbol}
</li>
</ul>
</div>
)
})}
</ContentReveal>
}
</Card>
</>
)}
</div>
)
Expand Down
22 changes: 18 additions & 4 deletions src/components/ui/content-reveal.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className={className}>
<button
onClick={() => 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}
>
<ChevronDown
className={`transition-transform duration-300 ${
Expand Down
15 changes: 15 additions & 0 deletions src/components/ui/skeleton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { cn } from '@/lib/utils'

function Skeleton({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) {
return (
<div
className={cn('animate-pulse rounded-md bg-muted', className)}
{...props}
/>
)
}

export { Skeleton }

0 comments on commit 32bc4f6

Please sign in to comment.