Skip to content

Commit bc6bc54

Browse files
committed
feat: integrate emergency mode functionality and enhance slider configuration for vault lockup periods; update UI components for improved user experience
1 parent 69396f3 commit bc6bc54

File tree

6 files changed

+291
-145
lines changed

6 files changed

+291
-145
lines changed

apps/hub/src/app/_components/vaults/table-columns.tsx

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ interface TableColumnsProps {
1515
vaults: VaultWithAddress[] | undefined
1616
openModalVaultId: string | null
1717
setOpenModalVaultId: (vaultId: string | null) => void
18+
emergencyModeEnabled: unknown
1819
}
1920

2021
export const createVaultTableColumns = ({
2122
vaults = [],
2223
openModalVaultId,
2324
setOpenModalVaultId,
25+
emergencyModeEnabled,
2426
}: TableColumnsProps) => {
2527
const totalStaked = vaults.reduce(
2628
(acc, vault) => acc + (vault.data?.stakedBalance || 0n),
@@ -219,36 +221,40 @@ export const createVaultTableColumns = ({
219221
<div className="flex items-center justify-end gap-2 lg:gap-4">
220222
{isLocked ? (
221223
<div className="flex items-center gap-2">
222-
<VaultWithdrawModal
223-
open={isWithdrawModalOpen}
224-
onOpenChange={open =>
225-
setOpenModalVaultId(open ? withdrawModalId : null)
226-
}
227-
onClose={() => setOpenModalVaultId(null)}
228-
vaultAdress={row.original.address}
229-
>
230-
{/* @ts-expect-error - Button component is not typed */}
231-
<Button
232-
variant="destructive"
233-
size="32"
234-
className="min-w-fit bg-danger-50 text-[13px] text-white-100 hover:bg-danger-60"
224+
{Boolean(emergencyModeEnabled) && (
225+
<VaultWithdrawModal
226+
open={isWithdrawModalOpen}
227+
onOpenChange={open =>
228+
setOpenModalVaultId(open ? withdrawModalId : null)
229+
}
230+
onClose={() => setOpenModalVaultId(null)}
231+
vaultAdress={row.original.address}
235232
>
236-
<AlertIcon className="shrink-0" />
237-
<span className="hidden whitespace-nowrap xl:inline">
238-
Withdraw funds
239-
</span>
240-
<span className="whitespace-nowrap xl:hidden">
241-
Withdraw
242-
</span>
243-
</Button>
244-
</VaultWithdrawModal>
233+
{/* @ts-expect-error - Button component is not typed */}
234+
<Button
235+
variant="destructive"
236+
size="32"
237+
className="min-w-fit bg-danger-50 text-[13px] text-white-100 hover:bg-danger-60"
238+
>
239+
<AlertIcon className="shrink-0" />
240+
<span className="hidden whitespace-nowrap xl:inline">
241+
Withdraw funds
242+
</span>
243+
<span className="whitespace-nowrap xl:hidden">
244+
Withdraw
245+
</span>
246+
</Button>
247+
</VaultWithdrawModal>
248+
)}
245249
<VaultLockConfigModal
246250
open={isLockModalOpen}
247251
onOpenChange={open =>
248252
setOpenModalVaultId(open ? lockModalId : null)
249253
}
250254
vaultAddress={row.original.address}
251255
title="Extend lock time"
256+
initialYears="2"
257+
initialDays="732"
252258
description="Extending lock time increasing Karma boost"
253259
actions={[
254260
{
@@ -290,13 +296,6 @@ export const createVaultTableColumns = ({
290296
vaultAddress={row.original.address}
291297
title="Do you want to lock the vault?"
292298
description="Lock this vault to receive more Karma"
293-
sliderConfig={{
294-
minLabel: '90 days',
295-
maxLabel: '4 years',
296-
minDays: 90,
297-
maxDays: 1460,
298-
initialPosition: 50,
299-
}}
300299
initialYears="2"
301300
initialDays="732"
302301
actions={[

apps/hub/src/app/_components/vaults/table.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ import {
1010
getCoreRowModel,
1111
useReactTable,
1212
} from '@tanstack/react-table'
13-
import { useAccount } from 'wagmi'
13+
import { useAccount, useReadContract } from 'wagmi'
1414

15+
import { STAKING_MANAGER } from '../../../config'
1516
import { useAccountVaults } from '../../_hooks/useAccountVaults'
1617
import { useVaultMutation } from '../../_hooks/useVault'
18+
import { stakingManagerAbi } from '../../contracts'
1719
import { createVaultTableColumns } from './table-columns'
1820

1921
import type { VaultWithAddress } from '../../_hooks/useAccountVaults'
@@ -129,14 +131,21 @@ export function VaultsTable() {
129131
const { isConnected } = useAccount()
130132
const { mutate: deployVault } = useVaultMutation()
131133

134+
const { data: emergencyModeEnabled } = useReadContract({
135+
address: STAKING_MANAGER.address,
136+
abi: stakingManagerAbi,
137+
functionName: 'emergencyModeEnabled',
138+
})
139+
132140
const columns = useMemo(
133141
() =>
134142
createVaultTableColumns({
135143
vaults: vaultDataList,
136144
openModalVaultId,
137145
setOpenModalVaultId,
146+
emergencyModeEnabled,
138147
}),
139-
[openModalVaultId, vaultDataList]
148+
[openModalVaultId, emergencyModeEnabled, vaultDataList]
140149
)
141150

142151
const table = useReactTable({

apps/hub/src/app/_components/vaults/vault-lock-modal.tsx

Lines changed: 65 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/* eslint-disable import/no-unresolved */
22
'use client'
33

4-
import { useEffect, useState } from 'react'
4+
import { useEffect, useMemo, useState } from 'react'
55

66
import { zodResolver } from '@hookform/resolvers/zod'
77
import * as Dialog from '@radix-ui/react-dialog'
@@ -12,6 +12,7 @@ import { Button } from '@status-im/status-network/components'
1212
import { useForm } from 'react-hook-form'
1313
import { z } from 'zod'
1414

15+
import { useSliderConfig } from '../../_hooks/useSliderConfig'
1516
import { useVaultLock } from '../../_hooks/useVaultLock'
1617

1718
import type { HTMLAttributes } from 'react'
@@ -39,14 +40,6 @@ type Props = {
3940
title: string
4041
description: string
4142
children?: React.ReactNode
42-
// Slider configuration
43-
sliderConfig?: {
44-
minLabel: string
45-
maxLabel: string
46-
minDays: number
47-
maxDays: number
48-
initialPosition?: number // 0-100 percentage
49-
}
5043
// Initial values
5144
initialYears?: string
5245
initialDays?: string
@@ -70,13 +63,6 @@ const VaultLockConfigModal = (props: Props) => {
7063
title,
7164
vaultAddress,
7265
description,
73-
sliderConfig = {
74-
minLabel: '90 days',
75-
maxLabel: '4 years',
76-
minDays: 90,
77-
maxDays: 1460,
78-
initialPosition: 0,
79-
},
8066
initialYears = '0',
8167
initialDays = '90',
8268
boost = 'x2.5',
@@ -86,6 +72,8 @@ const VaultLockConfigModal = (props: Props) => {
8672
actions,
8773
} = props
8874

75+
const [closeAction, submitAction] = actions
76+
8977
const { mutate: lockVault } = useVaultLock()
9078
const { watch, setValue, handleSubmit } = useForm<FormValues>({
9179
resolver: zodResolver(createFormSchema()),
@@ -95,6 +83,37 @@ const VaultLockConfigModal = (props: Props) => {
9583
},
9684
})
9785

86+
const { data: sliderConfigQuery } = useSliderConfig()
87+
88+
const sliderConfig = useMemo(() => {
89+
// Convert seconds to days
90+
const SECONDS_PER_DAY = 24 * 60 * 60
91+
const DAYS_PER_YEAR = 365
92+
93+
const minSeconds = sliderConfigQuery?.min || 7776000 // fallback: 90 days in seconds
94+
const maxSeconds = sliderConfigQuery?.max || 126144000 // fallback: 4 years in seconds
95+
96+
const minDays = Math.round(minSeconds / SECONDS_PER_DAY)
97+
const maxDays = Math.round(maxSeconds / SECONDS_PER_DAY)
98+
99+
// Format labels
100+
const minYears = minDays / DAYS_PER_YEAR
101+
const maxYears = maxDays / DAYS_PER_YEAR
102+
103+
const minLabel =
104+
minYears < 1 ? `${minDays} days` : `${minYears.toFixed(1)} years`
105+
const maxLabel =
106+
maxYears < 1 ? `${maxDays} days` : `${Math.round(maxYears)} years`
107+
108+
return {
109+
minLabel,
110+
maxLabel,
111+
minDays,
112+
maxDays,
113+
initialPosition: 50,
114+
}
115+
}, [sliderConfigQuery])
116+
98117
const years = watch('years')
99118
const days = watch('days')
100119

@@ -136,7 +155,7 @@ const VaultLockConfigModal = (props: Props) => {
136155
}
137156
}
138157

139-
const handleVaultLockAndExtend = async (data: FormValues) => {
158+
const handleVaultLockOrExtend = async (data: FormValues) => {
140159
const totalDays = parseInt(data.days || '0')
141160
const lockPeriodInSeconds = BigInt(totalDays * 24 * 60 * 60)
142161

@@ -236,7 +255,7 @@ const VaultLockConfigModal = (props: Props) => {
236255
<Dialog.Overlay className="fixed inset-0 z-40 bg-neutral-80/60 backdrop-blur-sm" />
237256
<Dialog.Content className="fixed left-1/2 top-1/2 z-50 w-full max-w-[440px] -translate-x-1/2 -translate-y-1/2 px-4 focus:outline-none">
238257
<form
239-
onSubmit={handleSubmit(handleVaultLockAndExtend)}
258+
onSubmit={handleSubmit(handleVaultLockOrExtend)}
240259
className="relative mx-auto w-full max-w-[440px] overflow-hidden rounded-20 bg-white-100 shadow-3"
241260
>
242261
<Dialog.Close asChild>
@@ -305,21 +324,23 @@ const VaultLockConfigModal = (props: Props) => {
305324
</div>
306325
</div>
307326

308-
<div
309-
className="box-border flex flex-col gap-2 px-8 py-0"
310-
style={{ opacity: hasError ? 1 : 0 }}
311-
>
312-
<div className="flex items-center gap-1">
313-
<div className="box-border flex items-center justify-center gap-[10px] self-stretch px-0 py-px">
314-
<div className="relative overflow-hidden">
315-
<IncorrectIcon />
327+
{hasError && (
328+
<div
329+
className="box-border flex flex-col gap-2 px-8 py-0"
330+
style={{ opacity: hasError ? 1 : 0 }}
331+
>
332+
<div className="flex items-center gap-1">
333+
<div className="box-border flex items-center justify-center gap-[10px] self-stretch px-0 py-px">
334+
<div className="relative overflow-hidden">
335+
<IncorrectIcon />
336+
</div>
337+
</div>
338+
<div className="flex min-h-px min-w-px shrink-0 grow basis-0 flex-col justify-center text-[13px] font-medium leading-[0] tracking-[-0.039px] text-[#e95460]">
339+
<span className="leading-[1.4]">{displayError}</span>
316340
</div>
317-
</div>
318-
<div className="flex min-h-px min-w-px shrink-0 grow basis-0 flex-col justify-center text-[13px] font-medium leading-[0] tracking-[-0.039px] text-[#e95460]">
319-
<span className="leading-[1.4]">{displayError}</span>
320341
</div>
321342
</div>
322-
</div>
343+
)}
323344

324345
<div className="box-border flex items-center gap-6 px-8 py-4">
325346
<div className="flex items-center gap-2">
@@ -355,24 +376,27 @@ const VaultLockConfigModal = (props: Props) => {
355376

356377
<div className="flex w-full flex-col items-start bg-[rgba(255,255,255,0.7)] backdrop-blur-[20px]">
357378
<div className="box-border flex w-full items-center justify-center gap-3 px-4 pb-4 pt-6">
358-
{/* @ts-expect-error - Button component is not typed */}
359-
<Button
360-
size="40"
361-
variant="outline"
362-
type="button"
363-
className="flex-1 justify-center"
364-
>
365-
{actions[0].label}
366-
</Button>
379+
<Dialog.Close asChild>
380+
{/* @ts-expect-error - Button component is not typed */}
381+
<Button
382+
size="40"
383+
variant="outline"
384+
type="button"
385+
aria-label="Close"
386+
className="flex-1 justify-center"
387+
>
388+
{closeAction.label}
389+
</Button>
390+
</Dialog.Close>
367391
{/* @ts-expect-error - Button component is not typed */}
368392
<Button
369393
size="40"
370394
variant="primary"
371395
type="submit"
372396
className="flex-1 justify-center"
373-
disabled={actions[1].disabled || hasError}
397+
disabled={submitAction.disabled || hasError}
374398
>
375-
{actions[1].label}
399+
{submitAction.label}
376400
</Button>
377401
</div>
378402
</div>

0 commit comments

Comments
 (0)