Skip to content

Commit 69396f3

Browse files
committed
feat: enhance vault management with new hooks for token approval, withdrawal, and staking; update UI components and integrate new icons for improved user experience
1 parent 1bf5990 commit 69396f3

27 files changed

+2430
-653
lines changed

apps/hub/package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
"clean": "rimraf .next .vercel/output node_modules"
1515
},
1616
"dependencies": {
17+
"@hookform/devtools": "^4.3.1",
18+
"@hookform/resolvers": "^3.1.1",
1719
"@status-im/colors": "workspace:*",
1820
"@status-im/components": "workspace:*",
1921
"@status-im/icons": "workspace:*",
@@ -26,10 +28,12 @@
2628
"next-mdx-remote": "^5.0.0",
2729
"react": "^19.0.0",
2830
"react-dom": "^19.0.0",
31+
"react-hook-form": "^7.45.1",
2932
"rehype-slug": "^6.0.0",
3033
"siwe": "^2.3.2",
3134
"ts-pattern": "^5.6.2",
32-
"viem": "^2.21.1"
35+
"viem": "^2.21.1",
36+
"zod": "^3.21.4"
3337
},
3438
"devDependencies": {
3539
"@ianvs/prettier-plugin-sort-imports": "^4.3.1",

apps/hub/src/app/_components/icons/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,14 @@ export { default as HomeIcon } from './home-icon'
1111
export { default as KarmaIcon } from './karma-icon'
1212
export { default as LaunchIcon } from './launch-icon'
1313
export { default as MintIcon } from './mint-icon'
14-
export { default as NewActionIcon } from './new-action-icon'
1514
export { default as PercentIcon } from './percent-icon'
1615
export { default as PlusIcon } from './plus-icon'
1716
export { default as ProcessingIcon } from './processing-icon'
17+
export { default as RejectIcon } from './reject-icon'
1818
export { default as SettingsIcon } from './settings-icon'
1919
export { default as SNTIcon } from './snt-icon'
2020
export { default as StakeIcon } from './stake-icon'
2121
export { default as SubmitAppIcon } from './submit-app-icon'
2222
export { default as SwapIcon } from './swap-icon'
2323
export { default as TwitterIcon } from './twitter-icon'
24+
export { default as VaultIcon } from './vault-icon'
Lines changed: 27 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,27 @@
1-
export default function LaunchIcon({
2-
className = '',
3-
...props
4-
}: React.SVGProps<SVGSVGElement>) {
5-
return (
6-
<svg
7-
width="20"
8-
height="20"
9-
viewBox="0 0 20 20"
10-
fill="none"
11-
xmlns="http://www.w3.org/2000/svg"
12-
className={className}
13-
{...props}
14-
>
15-
<g clipPath="url(#clip0_2815_575)">
16-
<path
17-
d="M3.75004 13.7498C2.50004 14.7998 2.08337 17.9164 2.08337 17.9164C2.08337 17.9164 5.20004 17.4998 6.25004 16.2498C6.84171 15.5498 6.83337 14.4748 6.17504 13.8248C5.85113 13.5156 5.42445 13.337 4.9769 13.3231C4.52934 13.3093 4.09244 13.4612 3.75004 13.7498Z"
18-
stroke="currentColor"
19-
strokeWidth="1.5"
20-
strokeLinecap="round"
21-
strokeLinejoin="round"
22-
/>
23-
<path
24-
d="M10 12.4996L7.5 9.99956C7.94345 8.84908 8.50184 7.74627 9.16667 6.70789C10.1377 5.15538 11.4897 3.8771 13.0942 2.99463C14.6986 2.11217 16.5022 1.65486 18.3333 1.66622C18.3333 3.93289 17.6833 7.91622 13.3333 10.8329C12.2807 11.4985 11.164 12.0568 10 12.4996Z"
25-
stroke="currentColor"
26-
strokeWidth="1.5"
27-
strokeLinecap="round"
28-
strokeLinejoin="round"
29-
/>
30-
<path
31-
d="M7.50004 10.0009H3.33337C3.33337 10.0009 3.79171 7.47591 5.00004 6.66758C6.35004 5.76758 9.16671 6.66758 9.16671 6.66758"
32-
stroke="currentColor"
33-
strokeWidth="1.5"
34-
strokeLinecap="round"
35-
strokeLinejoin="round"
36-
/>
37-
<path
38-
d="M10 12.5007V16.6673C10 16.6673 12.525 16.209 13.3333 15.0007C14.2333 13.6507 13.3333 10.834 13.3333 10.834"
39-
stroke="currentColor"
40-
strokeWidth="1.5"
41-
strokeLinecap="round"
42-
strokeLinejoin="round"
43-
/>
44-
</g>
45-
<defs>
46-
<clipPath id="clip0_2815_575">
47-
<rect width="20" height="20" fill="white" />
48-
</clipPath>
49-
</defs>
50-
</svg>
51-
)
52-
}
1+
import type { SVGProps } from 'react'
2+
3+
const LaunchIcon = (props: SVGProps<SVGSVGElement>) => (
4+
<svg
5+
xmlns="http://www.w3.org/2000/svg"
6+
width={32}
7+
height={32}
8+
fill="none"
9+
{...props}
10+
>
11+
<path
12+
stroke="#7140FD"
13+
strokeLinecap="round"
14+
strokeLinejoin="round"
15+
strokeWidth={2}
16+
d="M6 22c-2 1.68-2.666 6.667-2.666 6.667S8.321 28 10.001 26c.946-1.12.933-2.84-.12-3.88A2.907 2.907 0 0 0 6 22ZM16 20.002l-4-4a29.328 29.328 0 0 1 2.667-5.267 17.172 17.172 0 0 1 14.666-8.067c0 3.627-1.04 10-8 14.667A29.798 29.798 0 0 1 16 20.002Z"
17+
/>
18+
<path
19+
stroke="#7140FD"
20+
strokeLinecap="round"
21+
strokeLinejoin="round"
22+
strokeWidth={2}
23+
d="M12 16H5.335s.733-4.04 2.667-5.333c2.16-1.44 6.666 0 6.666 0M16 19.999v6.666s4.04-.733 5.333-2.666c1.44-2.16 0-6.667 0-6.667"
24+
/>
25+
</svg>
26+
)
27+
export default LaunchIcon

apps/hub/src/app/_components/icons/processing-icon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { SVGProps } from 'react'
22

3-
const ProcessingIcon = (props: SVGProps<SVGSVGElement>) => (
3+
const ProcessingIcon = ({ ...props }: SVGProps<SVGSVGElement>) => (
44
<svg
55
xmlns="http://www.w3.org/2000/svg"
66
width={50}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import type { SVGProps } from 'react'
2+
3+
const RejectIcon = (props: SVGProps<SVGSVGElement>) => (
4+
<svg
5+
xmlns="http://www.w3.org/2000/svg"
6+
width={50}
7+
height={50}
8+
fill="none"
9+
{...props}
10+
>
11+
<g
12+
stroke="#E95460"
13+
strokeLinecap="round"
14+
strokeLinejoin="round"
15+
strokeWidth={4}
16+
clipPath="url(#a)"
17+
>
18+
<path d="m10.269 10.27 29.46 29.462M25 45.833c11.506 0 20.834-9.328 20.834-20.834S36.506 4.166 25 4.166 4.167 13.493 4.167 24.999c0 11.506 9.327 20.834 20.833 20.834Z" />
19+
</g>
20+
<defs>
21+
<clipPath id="a">
22+
<path fill="#fff" d="M0 0h50v50H0z" />
23+
</clipPath>
24+
</defs>
25+
</svg>
26+
)
27+
export default RejectIcon

apps/hub/src/app/_components/icons/new-action-icon.tsx renamed to apps/hub/src/app/_components/icons/vault-icon.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { SVGProps } from 'react'
22

3-
export default function NewActionIcon({
3+
export default function VaultIcon({
44
className,
55
...props
66
}: SVGProps<SVGSVGElement>) {

apps/hub/src/app/_components/stake/action-status-dialog.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import * as Dialog from '@radix-ui/react-dialog'
33
import { CloseIcon } from '@status-im/icons/20'
44
import { match } from 'ts-pattern'
55

6-
import { NewActionIcon, ProcessingIcon } from '../icons'
6+
import { ProcessingIcon, RejectIcon, VaultIcon } from '../icons'
77

88
import type { ActionStatusState } from './use-action-status-content'
99

@@ -36,10 +36,10 @@ const ActionStatusDialog = (props: Props) => {
3636

3737
const mapIconToState = (state: ActionStatusState) => {
3838
return match(state)
39-
.with('pending', () => <NewActionIcon />)
39+
.with('pending', () => <VaultIcon />)
4040
.with('processing', () => <ProcessingIcon />)
41-
.with('error', () => <CloseIcon />)
42-
.with('success', () => <NewActionIcon />)
41+
.with('error', () => <RejectIcon />)
42+
.with('success', () => <VaultIcon />)
4343
.otherwise(() => null)
4444
}
4545

@@ -65,7 +65,7 @@ const ActionStatusDialog = (props: Props) => {
6565
<div className="relative z-10 flex min-h-[198px] flex-col items-center justify-center gap-2 p-8">
6666
{mapIconToState(state)}
6767
<Dialog.Title asChild>
68-
<h2 className="text-19 font-semibold text-neutral-100">
68+
<h2 className="text-center text-19 font-semibold text-neutral-100">
6969
{title}
7070
</h2>
7171
</Dialog.Title>

apps/hub/src/app/_components/stake/use-action-status-content.tsx

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { match } from 'ts-pattern'
22

3+
import { formatSNT } from '../../../utils/currency'
4+
35
import type { VaultState } from '../../_hooks/useVaultStateMachine'
46

57
export type ActionStatusState =
@@ -18,6 +20,7 @@ export type ActionStatusContent = {
1820
export function useActionStatusContent(
1921
state: VaultState
2022
): ActionStatusContent | null {
23+
console.log(state)
2124
return (
2225
match<VaultState, ActionStatusContent | null>(state)
2326
// SIWE flow
@@ -65,7 +68,7 @@ export function useActionStatusContent(
6568
title: 'Increase token allowance',
6669
description: 'Please sign the message in your wallet.',
6770
state: 'pending',
68-
showCloseButton: true,
71+
showCloseButton: false,
6972
}))
7073
.with({ type: 'increaseAllowance', step: 'processing' }, () => ({
7174
title: 'Increasing token allowance',
@@ -87,15 +90,15 @@ export function useActionStatusContent(
8790
step: 'initialize',
8891
},
8992
state => ({
90-
title: `Ready to stake ${state.amount || '0'} SNT`,
93+
title: `Ready to stake ${formatSNT(state.amount ?? 0, { includeSymbol: true })}`,
9194
description: 'Please sign the message in your wallet.',
9295
state: 'pending',
9396
showCloseButton: true,
9497
})
9598
)
9699

97100
.with({ type: 'staking', step: 'processing' }, state => ({
98-
title: `Staking ${state.amount || '0'} SNT`,
101+
title: `Staking ${formatSNT(state.amount ?? 0, { includeSymbol: true })}`,
99102
description: 'Wait a moment...',
100103
state: 'processing',
101104
showCloseButton: false,
@@ -107,6 +110,52 @@ export function useActionStatusContent(
107110
showCloseButton: true,
108111
}))
109112

113+
// Withdraw flow
114+
.with(
115+
{
116+
type: 'withdraw',
117+
step: 'initialize',
118+
},
119+
state => ({
120+
title: `Ready to withdraw ${formatSNT(state.amount ?? 0, { includeSymbol: true })}`,
121+
description: 'Please sign the message in your wallet.',
122+
state: 'pending',
123+
showCloseButton: true,
124+
})
125+
)
126+
.with({ type: 'withdraw', step: 'processing' }, state => ({
127+
title: `Withdrawing ${formatSNT(state.amount ?? 0, { includeSymbol: true })}`,
128+
description: 'Wait a moment...',
129+
state: 'processing',
130+
showCloseButton: false,
131+
}))
132+
.with({ type: 'withdraw', step: 'rejected' }, () => ({
133+
title: 'Request was rejected',
134+
description: 'Request was rejected by user',
135+
state: 'error',
136+
showCloseButton: true,
137+
}))
138+
139+
// Lock flow
140+
.with({ type: 'lock', step: 'initialize' }, () => ({
141+
title: 'Ready to lock vault',
142+
description: 'Please sign the message in your wallet.',
143+
state: 'pending',
144+
showCloseButton: true,
145+
}))
146+
.with({ type: 'lock', step: 'processing' }, () => ({
147+
title: 'Locking vault',
148+
description: 'Wait a moment...',
149+
state: 'processing',
150+
showCloseButton: false,
151+
}))
152+
.with({ type: 'lock', step: 'rejected' }, () => ({
153+
title: 'Request was rejected',
154+
description: 'Request was rejected by user',
155+
state: 'error',
156+
showCloseButton: true,
157+
}))
158+
110159
// Success
111160
.with({ type: 'success' }, () => ({
112161
title: 'Success!',

0 commit comments

Comments
 (0)