Skip to content

Commit

Permalink
delegation card logic isolated
Browse files Browse the repository at this point in the history
  • Loading branch information
Tbaut committed Oct 10, 2024
1 parent 0170c6e commit f6800a4
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 96 deletions.
103 changes: 103 additions & 0 deletions src/components/DelegationCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import { useDelegates } from '@/contexts/DelegatesContext'
import { CurrentDelegation, useLocks } from '@/contexts/LocksContext'
import { Card } from '@polkadot-ui/react'
import { useCallback, useMemo, useState } from 'react'
import { DelegationByAmountConviction } from './DelegationByAmountConviction'
import { AddressDisplay } from './ui/address-display'
import { Button } from './ui/button'
import { useGetSigningCallback } from '@/hooks/useGetSigningCallback'
import { useNetwork } from '@/contexts/NetworkContext'
import { useAccounts } from '@/contexts/AccountsContext'
import { Transaction } from 'polkadot-api'

interface Props {
delegateAddress: string
amountConvictionMap: Record<string, CurrentDelegation[]>
}

export const DelegationCard = ({
delegateAddress,
amountConvictionMap,
}: Props) => {
const { getDelegateByAddress } = useDelegates()
const knownDelegate = getDelegateByAddress(delegateAddress)
const [isUndelegating, setIsUndelegating] = useState(false)
const { api } = useNetwork()
const { delegations, refreshLocks } = useLocks()
const { selectedAccount } = useAccounts()
const tx = useMemo(() => {
if (!api || !delegations) {
return
}

const tracks = delegations[delegateAddress].map((d) => d.trackId)

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let tx: Transaction<any, any, any, any>

if (tracks.length === 1) {
tx = api.tx.ConvictionVoting.undelegate({ class: tracks[0] })
} else {
const batchTx = tracks.map(
(t) => api.tx.ConvictionVoting.undelegate({ class: t }).decodedCall,
)
tx = api.tx.Utility.batch({ calls: batchTx })
}

return tx
}, [api, delegateAddress, delegations])

const getSubscriptionCallback = useGetSigningCallback()
const subscriptionCallback = useMemo(
() =>
getSubscriptionCallback({
onError: () => {
setIsUndelegating(false)
},
onInBlock: () => {
setIsUndelegating(false)
refreshLocks()
},
}),
[getSubscriptionCallback, refreshLocks],
)

const onUndelegate = useCallback(() => {
if (!tx || !selectedAccount) return

setIsUndelegating(true)

tx.signSubmitAndWatch(selectedAccount.polkadotSigner, {
at: 'best',
}).subscribe(subscriptionCallback)
}, [selectedAccount, subscriptionCallback, tx])

return (
<Card className="flex h-max flex-col justify-between border bg-card p-2 px-4">
<div className="flex flex-col justify-between">
{knownDelegate?.name ? (
<div className="flex items-center gap-2">
<img src={knownDelegate.image} className="mr-2 w-12 rounded-full" />
<div className="py-2 text-xl font-semibold">
{knownDelegate.name}
</div>
</div>
) : (
<AddressDisplay address={delegateAddress} size={'3rem'} />
)}
<DelegationByAmountConviction
amountConvictionMap={amountConvictionMap}
/>
</div>
<Button
className="w-a bottom-0 mb-2 mt-4"
variant={'outline'}
onClick={onUndelegate}
disabled={isUndelegating}
loading={isUndelegating}
>
{isUndelegating ? 'Undelegating...' : 'Undelegate'}
</Button>
</Card>
)
}
106 changes: 10 additions & 96 deletions src/components/MyDelegations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,16 @@ import { Card } from '@polkadot-ui/react'
import { Title } from './ui/title'
import { TreePalm } from 'lucide-react'
import { CurrentDelegation, useLocks } from '@/contexts/LocksContext'
import { useCallback, useMemo, useState } from 'react'
import { useMemo } from 'react'
import { Skeleton } from './ui/skeleton'
import { useDelegates } from '@/contexts/DelegatesContext'
import { useNetwork } from '@/contexts/NetworkContext'
import { AddressDisplay } from './ui/address-display'
import { Button } from './ui/button'
import { useAccounts } from '@/contexts/AccountsContext'
import { Transaction } from 'polkadot-api'
import { DelegationByAmountConviction } from './DelegationByAmountConviction'
import { useGetSigningCallback } from '@/hooks/useGetSigningCallback'
import { DelegationCard } from './DelegationCard'

export const MyDelegations = () => {
const { api } = useNetwork()
const { delegations, refreshLocks } = useLocks()
const [delegateLoading, setDelegatesLoading] = useState<string[]>([])
const { delegations } = useLocks()
const noDelegations = useMemo(
() => !!delegations && Object.entries(delegations).length === 0,
[delegations],
)
const { getDelegateByAddress } = useDelegates()
const { selectedAccount } = useAccounts()

const delegationsByDelegateConvictionAmount = useMemo(() => {
if (!delegations) return
Expand All @@ -42,44 +31,6 @@ export const MyDelegations = () => {
return result
}, [delegations])

const getSubscriptionCallback = useGetSigningCallback()
const onUndelegate = useCallback(
(delegate: string) => {
if (!api || !selectedAccount || !delegations) return

setDelegatesLoading((prev) => [...prev, delegate])

const tracks = delegations[delegate].map((d) => d.trackId)

// @ts-expect-error we can't strongly type this
let tx: Transaction<undefined, unknown, unknown, undefined>

if (tracks.length === 1) {
tx = api.tx.ConvictionVoting.undelegate({ class: tracks[0] })
} else {
const batchTx = tracks.map(
(t) => api.tx.ConvictionVoting.undelegate({ class: t }).decodedCall,
)
tx = api.tx.Utility.batch({ calls: batchTx })
}

const subscriptionCallback = getSubscriptionCallback({
onError: () => {
setDelegatesLoading((prev) => prev.filter((id) => id !== delegate))
},
onInBlock: () => {
setDelegatesLoading((prev) => prev.filter((id) => id !== delegate))
refreshLocks()
},
})

tx.signSubmitAndWatch(selectedAccount.polkadotSigner, {
at: 'best',
}).subscribe(subscriptionCallback)
},
[api, delegations, getSubscriptionCallback, refreshLocks, selectedAccount],
)

return (
<>
<Title>My Delegations</Title>
Expand All @@ -99,50 +50,13 @@ export const MyDelegations = () => {
</Card>
) : (
Object.entries(delegationsByDelegateConvictionAmount).map(
([delegateAddress, amountConvictionMap]) => {
const knownDelegate = getDelegateByAddress(delegateAddress)
const isUndelegating = delegateLoading.includes(delegateAddress)

return (
<Card
className="flex h-max flex-col justify-between border bg-card p-2 px-4"
key={delegateAddress}
>
<>
<div className="flex flex-col justify-between">
{knownDelegate?.name ? (
<div className="flex items-center gap-2">
<img
src={knownDelegate.image}
className="mr-2 w-12 rounded-full"
/>
<div className="py-2 text-xl font-semibold">
{knownDelegate.name}
</div>
</div>
) : (
<AddressDisplay
address={delegateAddress}
size={'3rem'}
/>
)}
<DelegationByAmountConviction
amountConvictionMap={amountConvictionMap}
/>
</div>
<Button
className="w-a bottom-0 mb-2 mt-4"
variant={'outline'}
onClick={() => onUndelegate(delegateAddress)}
disabled={isUndelegating}
loading={isUndelegating}
>
{isUndelegating ? 'Undelegating...' : 'Undelegate'}
</Button>
</>
</Card>
)
},
([delegateAddress, amountConvictionMap]) => (
<DelegationCard
delegateAddress={delegateAddress}
amountConvictionMap={amountConvictionMap}
key={delegateAddress}
/>
),
)
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions src/pages/Delegate/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ export const Delegate = () => {
setIsTxInitiated(false)
return
}

if (isExhaustsResourcesError) {
setIsMultiTxDialogOpen(true)
return
Expand Down

0 comments on commit f6800a4

Please sign in to comment.