1- import { ethToHaqq , haqqToEth , useAddress , useWallet } from '@haqq/shared' ;
1+ import {
2+ ethToHaqq ,
3+ haqqToEth ,
4+ useAddress ,
5+ useClipboard ,
6+ useWallet ,
7+ } from '@haqq/shared' ;
28import { Button , Container } from '@haqq/shell-ui-kit' ;
39import clsx from 'clsx' ;
4- import { useEffect , useState } from 'react' ;
10+ import { useCallback , useEffect , useState } from 'react' ;
511import { isAddress } from 'viem' ;
612// import { useNetwork } from 'wagmi';
713import { useVestingActions } from '../use-vesting-actions/use-vesting-actions' ;
@@ -52,9 +58,7 @@ export function CreateVestingAccountPage() {
5258}
5359
5460function CreateVestingAccountForm ( ) {
55- const [ targetAccount , setTargetAccount ] = useState (
56- '0xa5767e34Fc9B41872b4d0b321EF3531fD87624e5' ,
57- ) ;
61+ const [ targetAccount , setTargetAccount ] = useState ( '' ) ;
5862 const [ isTargetValid , setTargetValid ] = useState ( false ) ;
5963 const [ targetAddresses , setTargetAddresses ] = useState < {
6064 eth : string ;
@@ -68,22 +72,13 @@ function CreateVestingAccountForm() {
6872 const [ unlock , setUnlock ] = useState ( 60 ) ;
6973 const [ startTime , setStartTime ] = useState ( 1695695564 ) ;
7074 const { getParams } = useVestingActions ( ) ;
71- // const toast = useToast();
72- const [ isCodeVisible , setCodeVisible ] = useState ( false ) ;
7375 const [ generatedTx , setGeneratedTx ] = useState ( { } ) ;
7476 const { haqqAddress } = useAddress ( ) ;
77+ const { copyText } = useClipboard ( ) ;
78+ // const toast = useToast();
7579 // const { chain } = useNetwork();
7680 // const invalidateQueries = useQueryInvalidate();
7781
78- console . log ( {
79- targetAccount,
80- isTargetValid,
81- targetAddresses,
82- amount,
83- lockup,
84- unlock,
85- } ) ;
86-
8782 // const handleCreateNewClick = useCallback(async () => {
8883 // const grantPromise = createNew(
8984 // targetAddresses.haqq,
@@ -221,97 +216,96 @@ function CreateVestingAccountForm() {
221216 unlock ,
222217 ] ) ;
223218
224- return (
225- < Container >
226- < div className = "flex flex-col gap-[18px]" >
227- < Input
228- label = "Account address"
229- id = "target"
230- placeholder = "0x... or haqq1..."
231- value = { targetAccount }
232- onChange = { ( value ) => {
233- setTargetAccount ( value ) ;
234- } }
235- />
236- < Input
237- label = "Vesting amount"
238- id = "amount"
239- placeholder = "Deposit amount in ISLM"
240- value = { amount . toString ( ) }
241- onChange = { ( value ) => {
242- const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
243- ? Number . parseInt ( value )
244- : 0 ;
245- setAmount ( nextValue ) ;
246- } }
247- />
248- < Input
249- label = "Lockup period"
250- id = "lockup"
251- placeholder = "in days"
252- value = { lockup . toString ( ) }
253- onChange = { ( value ) => {
254- const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
255- ? Number . parseInt ( value )
256- : 0 ;
257- setLockup ( nextValue ) ;
258- } }
259- />
260- < Input
261- label = "Vesting period"
262- id = "unlock"
263- placeholder = "in days"
264- value = { unlock . toString ( ) }
265- onChange = { ( value ) => {
266- const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
267- ? Number . parseInt ( value )
268- : 0 ;
269- setUnlock ( nextValue ) ;
270- } }
271- />
272- < div >
273- < Input
274- label = "Vesting start date"
275- id = "startTime"
276- placeholder = "UNIX Timestamp"
277- value = { startTime . toString ( ) }
278- onChange = { ( value ) => {
279- const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
280- ? Number . parseInt ( value )
281- : 0 ;
282- setStartTime ( nextValue ) ;
283- } }
284- />
285- < div className = "mt-[4px] text-[12px] leading-[24px] text-white/50" >
286- { formatDate ( new Date ( startTime * 1000 ) ) }
287- </ div >
288- </ div >
219+ const handleSaveFileClick = useCallback ( ( ) => {
220+ const jsonString = JSON . stringify ( generatedTx , null , 2 ) ;
221+ const blob = new Blob ( [ jsonString ] , { type : 'application/json' } ) ;
222+ const blobUrl = URL . createObjectURL ( blob ) ;
223+ const downloadLink = document . createElement ( 'a' ) ;
224+ downloadLink . href = blobUrl ;
225+ downloadLink . download = `${ targetAddresses . haqq } -convert-to-vesting-tx.json` ;
226+ downloadLink . click ( ) ;
227+ URL . revokeObjectURL ( blobUrl ) ;
228+ } , [ generatedTx , targetAddresses . haqq ] ) ;
229+ const [ isCopied , setIsCopied ] = useState ( false ) ;
289230
290- { isCodeVisible ? (
291- < div
292- className = { clsx (
293- 'prose prose-sm w-full min-w-full max-w-fit' ,
294- 'prose-pre:max-h-[200px] prose-pre:overflow-auto prose-pre:p-[12px] prose-pre:rounded-[8px] prose-pre:border' ,
295- 'prose-pre:bg-transparent prose-pre:text-white prose-pre:border-haqq-border' ,
296- ) }
297- >
298- < pre >
299- < code > { JSON . stringify ( generatedTx , null , 2 ) } </ code >
300- </ pre >
301- </ div >
302- ) : (
303- < Button
304- onClick = { ( ) => {
305- setCodeVisible ( true ) ;
306- } }
307- variant = { 2 }
308- disabled = { ! isTargetValid }
309- >
310- Show tx JSON
311- </ Button >
312- ) }
231+ const handleCopyClick = useCallback ( async ( ) => {
232+ const jsonString = JSON . stringify ( generatedTx , null , 2 ) ;
233+ await copyText ( jsonString ) ;
234+ setIsCopied ( true ) ;
235+ setTimeout ( ( ) => {
236+ setIsCopied ( false ) ;
237+ } , 2000 ) ;
238+ } , [ copyText , generatedTx ] ) ;
239+
240+ return (
241+ < div className = "border-t border-t-[#ffffff26]" >
242+ < Container >
243+ < div className = "flex flex-1 flex-col gap-[32px] py-[32px] sm:py-[22px] lg:flex-row lg:pb-[40px] lg:pt-[32px]" >
244+ < div className = "flex flex-none flex-col gap-[18px] lg:w-1/3" >
245+ < Input
246+ label = "Account address"
247+ id = "target"
248+ placeholder = "0x... or haqq1..."
249+ value = { targetAccount }
250+ onChange = { ( value ) => {
251+ setTargetAccount ( value ) ;
252+ } }
253+ />
254+ < Input
255+ label = "Vesting amount"
256+ id = "amount"
257+ placeholder = "Deposit amount in ISLM"
258+ value = { amount . toString ( ) }
259+ onChange = { ( value ) => {
260+ const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
261+ ? Number . parseInt ( value )
262+ : 0 ;
263+ setAmount ( nextValue ) ;
264+ } }
265+ />
266+ < Input
267+ label = "Lockup period"
268+ id = "lockup"
269+ placeholder = "in days"
270+ value = { lockup . toString ( ) }
271+ onChange = { ( value ) => {
272+ const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
273+ ? Number . parseInt ( value )
274+ : 0 ;
275+ setLockup ( nextValue ) ;
276+ } }
277+ />
278+ < Input
279+ label = "Vesting period"
280+ id = "unlock"
281+ placeholder = "in days"
282+ value = { unlock . toString ( ) }
283+ onChange = { ( value ) => {
284+ const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
285+ ? Number . parseInt ( value )
286+ : 0 ;
287+ setUnlock ( nextValue ) ;
288+ } }
289+ />
290+ < div >
291+ < Input
292+ label = "Vesting start date"
293+ id = "startTime"
294+ placeholder = "UNIX Timestamp"
295+ value = { startTime . toString ( ) }
296+ onChange = { ( value ) => {
297+ const nextValue = ! Number . isNaN ( Number . parseInt ( value ) )
298+ ? Number . parseInt ( value )
299+ : 0 ;
300+ setStartTime ( nextValue ) ;
301+ } }
302+ />
303+ < div className = "mt-[4px] text-[12px] leading-[24px] text-white/50" >
304+ { formatDate ( new Date ( startTime * 1000 ) ) }
305+ </ div >
306+ </ div >
313307
314- { /* <div>
308+ { /* <div>
315309 <Button
316310 onClick={handleCreateNewClick}
317311 variant={2}
@@ -320,8 +314,55 @@ function CreateVestingAccountForm() {
320314 Create new vesting account
321315 </Button>
322316 </div> */ }
323- </ div >
324- </ Container >
317+ </ div >
318+ < div className = "flex flex-1 flex-col gap-[32px] pt-[32px]" >
319+ < div className = "relative" >
320+ < div
321+ className = { clsx (
322+ 'prose w-full min-w-full max-w-fit' ,
323+ 'prose-pre:max-h-[444px] prose-pre:overflow-auto prose-pre:p-[12px] prose-pre:rounded-[8px] prose-pre:border' ,
324+ 'prose-pre:bg-transparent prose-pre:text-white prose-pre:border-[#252528]' ,
325+ 'focus:prose-pre:border-white/50 focus:prose-pre:bg-transparent focus:prose-pre:text-white' ,
326+ 'hover:prose-pre:border-white/20' ,
327+ 'prose-pre:transition-colors prose-pre:duration-150 prose-pre:ease-in prose-pre:will-change-[color,background]' ,
328+ ) }
329+ >
330+ < pre >
331+ < code > { JSON . stringify ( generatedTx , null , 2 ) } </ code >
332+ </ pre >
333+ </ div >
334+
335+ { ! isTargetValid && (
336+ < div className = "absolute inset-[1px] flex transform-gpu flex-row items-center justify-center rounded-[8px] bg-[#FFFFFF14] backdrop-blur-md" >
337+ Wrong parameters
338+ </ div >
339+ ) }
340+ </ div >
341+
342+ < div className = "flex flex-row gap-[16px]" >
343+ < div >
344+ < Button
345+ onClick = { handleSaveFileClick }
346+ variant = { 2 }
347+ disabled = { ! isTargetValid }
348+ >
349+ Save as file
350+ </ Button >
351+ </ div >
352+ < div >
353+ < Button
354+ onClick = { handleCopyClick }
355+ variant = { 2 }
356+ disabled = { ! isTargetValid }
357+ >
358+ { isCopied ? 'Copied!' : 'Copy' }
359+ </ Button >
360+ </ div >
361+ </ div >
362+ </ div >
363+ </ div >
364+ </ Container >
365+ </ div >
325366 ) ;
326367}
327368
@@ -355,7 +396,6 @@ function Input({
355396 'transition-colors duration-150 ease-in will-change-[color,background]' ,
356397 'focus:border-white/50 focus:bg-transparent focus:text-white' ,
357398 'hover:border-white/20' ,
358- 'max-w-xl' ,
359399 ) }
360400 type = "text"
361401 placeholder = { placeholder }
0 commit comments