Skip to content

Commit 368a2a7

Browse files
authored
feat: support key reg transaction
1 parent ef37b7c commit 368a2a7

17 files changed

+627
-68
lines changed

src/features/common/components/badge.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const badgeVariants = cva(
1111
default: 'border-transparent bg-primary text-primary-foreground hover:bg-primary/80',
1212
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
1313
destructive: 'border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80',
14-
outline: 'text-foreground',
14+
outline: '',
1515
},
1616
},
1717
defaultVariants: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<div>
2+
<div
3+
class="relative grid"
4+
style="grid-template-columns: minmax(128px, 128px) repeat(2, 128px); grid-template-rows: repeat(2, 40px);"
5+
>
6+
<div />
7+
<div
8+
class="p-2 flex justify-center"
9+
>
10+
<h1
11+
class="text-l font-semibold"
12+
>
13+
65NE...YLNI
14+
</h1>
15+
</div>
16+
<div
17+
class="p-2 flex justify-center"
18+
>
19+
<h1
20+
class="text-l font-semibold"
21+
/>
22+
</div>
23+
<div
24+
class="absolute left-0"
25+
style="top: 40px;"
26+
>
27+
<div>
28+
<div
29+
class="p-0"
30+
/>
31+
<div
32+
class="p-0"
33+
style="height: 40px; width: 256px;"
34+
>
35+
<div
36+
class="grid h-full"
37+
style="grid-template-columns: minmax(128px, 128px) repeat(2, 128px); height: 40px;"
38+
>
39+
<div />
40+
<div
41+
class="flex justify-center"
42+
>
43+
<div
44+
class="border-muted h-full border-dashed"
45+
style="border-left-width: 2px;"
46+
/>
47+
</div>
48+
</div>
49+
</div>
50+
</div>
51+
</div>
52+
<div
53+
class="p-0 relative pr-8"
54+
>
55+
<div
56+
class="relative h-full p-0 flex items-center px-0"
57+
style="margin-left: 0px;"
58+
>
59+
<div
60+
class="inline"
61+
style="margin-left: 16px;"
62+
>
63+
VE767RE...
64+
</div>
65+
</div>
66+
</div>
67+
<div
68+
class="flex items-center justify-center relative z-10"
69+
data-state="closed"
70+
style="grid-column-start: 2; grid-column-end: 3; color: rgb(126 200 191);"
71+
>
72+
<svg
73+
height="20"
74+
viewBox="0 0 21 21"
75+
width="20"
76+
xmlns="http://www.w3.org/2000/svg"
77+
xmlns:xlink="http://www.w3.org/1999/xlink"
78+
>
79+
<g
80+
transform="matrix(1 0 0 1 -153 -143 )"
81+
>
82+
<path
83+
d="M 163.5 143 C 169.38 143 174 147.62 174 153.5 C 174 159.38 169.38 164 163.5 164 C 157.62 164 153 159.38 153 153.5 C 153 147.62 157.62 143 163.5 143 Z "
84+
fill="currentColor"
85+
fill-rule="nonzero"
86+
stroke="none"
87+
/>
88+
</g>
89+
</svg>
90+
</div>
91+
<div />
92+
</div>
93+
</div>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { Card, CardContent } from '@/features/common/components/card'
2+
import { cn } from '@/features/common/utils'
3+
import { TransactionInfo } from './transaction-info'
4+
import { TransactionNote } from './transaction-note'
5+
import { TransactionJson } from './transaction-json'
6+
import { KeyRegTransaction, InnerKeyRegTransaction, SignatureType } from '../models'
7+
import { MultisigDetails } from './multisig-details'
8+
import { LogicsigDetails } from './logicsig-details'
9+
import { KeyRegTransactionInfo } from './key-reg-transaction-info'
10+
import { TransactionViewTabs } from './transaction-view-tabs'
11+
12+
type KeyRegTransactionProps = {
13+
transaction: KeyRegTransaction | InnerKeyRegTransaction
14+
}
15+
16+
export function KeyRegTransactionDetails({ transaction }: KeyRegTransactionProps) {
17+
return (
18+
<div className={cn('space-y-6 pt-7')}>
19+
<TransactionInfo transaction={transaction} />
20+
<Card className={cn('p-4')}>
21+
<CardContent className={cn('text-sm space-y-4')}>
22+
<KeyRegTransactionInfo transaction={transaction} />
23+
<TransactionViewTabs transaction={transaction} />
24+
{transaction.note && <TransactionNote note={transaction.note} />}
25+
<TransactionJson json={transaction.json} />
26+
{transaction.signature?.type === SignatureType.Multi && <MultisigDetails signature={transaction.signature} />}
27+
{transaction.signature?.type === SignatureType.Logic && <LogicsigDetails signature={transaction.signature} />}
28+
</CardContent>
29+
</Card>
30+
</div>
31+
)
32+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { cn } from '@/features/common/utils'
2+
import { useMemo } from 'react'
3+
import { KeyRegTransaction, InnerKeyRegTransaction } from '../models'
4+
import { DescriptionList } from '@/features/common/components/description-list'
5+
import { transactionSenderLabel } from './transaction-view-table'
6+
import { AccountLink } from '@/features/accounts/components/account-link'
7+
import { isDefined } from '@/utils/is-defined'
8+
9+
type Props = {
10+
transaction: KeyRegTransaction | InnerKeyRegTransaction
11+
}
12+
13+
export const voteParticipationKeyLabel = 'Vote Participation Key'
14+
export const selectionParticipationKeyLabel = 'Selection Participation Key'
15+
export const voteFirstValidLabel = 'Vote First Valid'
16+
export const voteLastValidLabel = 'Vote Last Valid'
17+
export const voteKeyDilutionLabel = 'Vote Key Dilution'
18+
19+
export function KeyRegTransactionInfo({ transaction }: Props) {
20+
const items = useMemo(
21+
() =>
22+
[
23+
{
24+
dt: transactionSenderLabel,
25+
dd: <AccountLink address={transaction.sender}></AccountLink>,
26+
},
27+
transaction.voteParticipationKey
28+
? {
29+
dt: voteParticipationKeyLabel,
30+
dd: transaction.voteParticipationKey,
31+
}
32+
: undefined,
33+
transaction.selectionParticipationKey
34+
? {
35+
dt: selectionParticipationKeyLabel,
36+
dd: transaction.selectionParticipationKey,
37+
}
38+
: undefined,
39+
transaction.voteFirstValid
40+
? {
41+
dt: voteFirstValidLabel,
42+
dd: transaction.voteFirstValid,
43+
}
44+
: undefined,
45+
transaction.voteLastValid
46+
? {
47+
dt: voteLastValidLabel,
48+
dd: transaction.voteLastValid,
49+
}
50+
: undefined,
51+
transaction.voteKeyDilution
52+
? {
53+
dt: voteKeyDilutionLabel,
54+
dd: transaction.voteKeyDilution,
55+
}
56+
: undefined,
57+
].filter(isDefined),
58+
[
59+
transaction.selectionParticipationKey,
60+
transaction.sender,
61+
transaction.voteFirstValid,
62+
transaction.voteKeyDilution,
63+
transaction.voteLastValid,
64+
transaction.voteParticipationKey,
65+
]
66+
)
67+
68+
return (
69+
<div className={cn('space-y-2')}>
70+
<div className={cn('flex items-center justify-between')}>
71+
<h1 className={cn('text-2xl text-primary font-bold')}>Key Registration</h1>
72+
</div>
73+
<DescriptionList items={items} />
74+
</div>
75+
)
76+
}

src/features/transactions/components/transaction-details.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { AppCallTransactionDetails } from './app-call-transaction-details'
55
import { AssetConfigTransactionDetails } from './asset-config-transaction-details'
66
import { AssetFreezeTransactionDetails } from './asset-freeze-transaction-details'
77
import { StateProofTransactionDetails } from './state-proof-transaction-details'
8+
import { KeyRegTransactionDetails } from './key-reg-transaction-details'
89

910
type Props = {
1011
transaction: Transaction | InnerTransaction
@@ -24,6 +25,8 @@ export function TransactionDetails({ transaction }: Props) {
2425
return <AssetFreezeTransactionDetails transaction={transaction} />
2526
case TransactionType.StateProof:
2627
return <StateProofTransactionDetails transaction={transaction} />
28+
case TransactionType.KeyReg:
29+
return <KeyRegTransactionDetails transaction={transaction} />
2730
default:
2831
return <></>
2932
}

src/features/transactions/components/transaction-info.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { cn } from '@/features/common/utils'
33
import { dateFormatter } from '@/utils/format'
44
import { DisplayAlgo } from '@/features/common/components/display-algo'
55
import { useMemo } from 'react'
6-
import { Transaction, SignatureType, TransactionType, InnerTransaction } from '../models'
6+
import { Transaction, SignatureType, InnerTransaction } from '../models'
77
import { DescriptionList } from '@/features/common/components/description-list'
88
import { Badge } from '@/features/common/components/badge'
99
import { BlockLink } from '@/features/blocks/components/block-link'
@@ -31,12 +31,7 @@ export function TransactionInfo({ transaction }: Props) {
3131
dd: (
3232
<>
3333
{transaction.type}
34-
{transaction.type === TransactionType.AssetTransfer && transaction.subType && (
35-
<Badge variant="outline">{transaction.subType}</Badge>
36-
)}
37-
{transaction.type === TransactionType.AssetConfig && transaction.subType && (
38-
<Badge variant="outline">{transaction.subType}</Badge>
39-
)}
34+
{transaction.subType && <Badge variant="outline">{transaction.subType}</Badge>}
4035
{transaction.signature?.type === SignatureType.Multi && <Badge variant="outline">Multisig</Badge>}
4136
{transaction.signature?.type === SignatureType.Logic && <Badge variant="outline">LogicSig</Badge>}
4237
</>

src/features/transactions/components/transaction-view-visual.test.tsx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { AssetResult, TransactionResult } from '@algorandfoundation/algokit-util
88
import { assetResultMother } from '@/tests/object-mother/asset-result'
99
import { useParams } from 'react-router-dom'
1010
import { asAsset } from '@/features/assets/mappers'
11+
import { asKeyRegTransaction } from '../mappers/key-reg-transaction-mappers'
1112

1213
// This file maintain the snapshot test for the TransactionViewVisual component
1314
// To add new test case:
@@ -104,3 +105,26 @@ describe('application-call-view-visual', () => {
104105
}
105106
)
106107
})
108+
109+
describe('key-reg-view-visual', () => {
110+
describe.each([
111+
{
112+
transactionResult: transactionResultMother['mainnet-VE767RE4HGQM7GFC7MUVY3J67KOR5TV34OBTDDEQTDET2UFM7KTQ']().build(),
113+
},
114+
])('when rendering transaction $transactionResult.id', ({ transactionResult }: { transactionResult: TransactionResult }) => {
115+
it('should match snapshot', () => {
116+
vi.mocked(useParams).mockImplementation(() => ({ transactionId: transactionResult.id }))
117+
118+
const model = asKeyRegTransaction(transactionResult)
119+
120+
return executeComponentTest(
121+
() => render(<TransactionViewVisual transaction={model} />),
122+
async (component) => {
123+
expect(prettyDOM(component.container, prettyDomMaxLength, { highlight: false })).toMatchFileSnapshot(
124+
`__snapshots__/key-reg-view-visual.${transactionResult.id}.html`
125+
)
126+
}
127+
)
128+
})
129+
})
130+
})

0 commit comments

Comments
 (0)