Skip to content

Commit de8126e

Browse files
committed
feat(shell): add copy and download button for create vesting account page
1 parent f6c8fba commit de8126e

File tree

3 files changed

+150
-130
lines changed

3 files changed

+150
-130
lines changed

libs/islamic-website/shariah-page/src/lib/sharia-page-mobile-nav/sharia-page-mobile-nav.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ export function ShariPageMobileNav({
1313
activeSection: string;
1414
onSectionSelect: (newSection: string) => void;
1515
}) {
16-
1716
const [isBlurred, setBlurred] = useState(false);
1817

1918
useEffect(() => {

libs/shell/services-pages/src/lib/create-vesting-account-page/create-vesting-account-page.tsx

Lines changed: 148 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
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';
28
import { Button, Container } from '@haqq/shell-ui-kit';
39
import clsx from 'clsx';
4-
import { useEffect, useState } from 'react';
10+
import { useCallback, useEffect, useState } from 'react';
511
import { isAddress } from 'viem';
612
// import { useNetwork } from 'wagmi';
713
import { useVestingActions } from '../use-vesting-actions/use-vesting-actions';
@@ -52,9 +58,7 @@ export function CreateVestingAccountPage() {
5258
}
5359

5460
function 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}

libs/shell/services-pages/src/lib/use-vesting-actions/use-vesting-actions.tsx

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,12 @@
11
import { useCallback, useMemo } from 'react';
2-
import {
3-
// Sender,
4-
// signatureToWeb3Extension,
5-
// createTxRawEIP712,
6-
// TxGenerated,
7-
// createTxCreateClawbackVestingAccount,
8-
MessageMsgCreateClawbackVestingAccount,
9-
// Period,
10-
} from '@evmos/transactions';
2+
import { MessageMsgCreateClawbackVestingAccount } from '@evmos/transactions';
113
import {
124
useAddress,
13-
// DEFAULT_FEE,
145
getChainParams,
156
useCosmosService,
167
mapToCosmosChain,
178
} from '@haqq/shared';
189
import { useNetwork } from 'wagmi';
19-
// import { Timestamp } from 'cosmjs-types/google/protobuf/timestamp';
20-
// import { createMsgCreateClawbackVestingAccount as ConvertToProtoMsgCreateClawbackVestingAccount } from '@evmos/proto';
21-
// import * as vesting from '@evmos/proto/evmos/vesting/v1/tx';
22-
// import {
23-
// generateFee,
24-
// generateTypes,
25-
// generateMessage,
26-
// createEIP712,
27-
// } from '@evmos/eip712';
28-
// import { createTransaction } from '@evmos/proto';
2910

3011
export function useVestingActions() {
3112
const { chain } = useNetwork();
@@ -117,7 +98,7 @@ export function useVestingActions() {
11798

11899
const unlockCoins = {
119100
denom: denom,
120-
amount: (unlockAmount * 10 ** 18).toString(),
101+
amount: BigInt(unlockAmount * 10 ** 18).toString(),
121102
};
122103

123104
const period = {

0 commit comments

Comments
 (0)