add unlock transaction
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
"endOfLine": "lf",
|
||||
"jsxBracketSameLine": false,
|
||||
"trailingComma": "es5",
|
||||
"printWidth": 100,
|
||||
"overrides": [
|
||||
{
|
||||
"files": "*.json",
|
||||
|
||||
@@ -81,7 +81,11 @@ const Delegates = observer(() => {
|
||||
<TransactionsTable
|
||||
data={delegates}
|
||||
lockedFor={lockedFor}
|
||||
rowClick={(delegate) => setCurrentDelegate(delegate)}
|
||||
rowClick={(delegate) =>
|
||||
(lockedFor === 'Voiting' ||
|
||||
store.accountLockedVotesCanReturnSum[delegate.address]) &&
|
||||
setCurrentDelegate(delegate)
|
||||
}
|
||||
/>
|
||||
|
||||
{/*/!* Pagination *!/*/}
|
||||
@@ -99,9 +103,11 @@ const Delegates = observer(() => {
|
||||
transactionPanelOpen={!!currentDelegate}
|
||||
onClose={() => setCurrentDelegate(null)}
|
||||
delegate={currentDelegate || {}}
|
||||
postTransaction={(address, amount) =>
|
||||
store.pushVoteTransaction(address, amount)
|
||||
}
|
||||
unlocking={lockedFor !== 'Voiting'}
|
||||
postTransaction={(address, amount) => {
|
||||
if (lockedFor === 'Voiting') store.pushVoteTransaction(address, amount);
|
||||
else store.pushUnlockTransaction(address);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import Image from '../../images/transactions-image-04.svg';
|
||||
import moment from 'moment';
|
||||
@@ -9,16 +9,19 @@ import UserAvatar from '../../images/user-avatar-32.png';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
const TransactionPanel = observer(
|
||||
({ transactionPanelOpen, onClose, delegate, postTransaction }) => {
|
||||
({ transactionPanelOpen, onClose, delegate, postTransaction, unlocking }) => {
|
||||
const closeBtn = useRef(null);
|
||||
const panelContent = useRef(null);
|
||||
|
||||
const [amount, setAmount] = useState(0);
|
||||
|
||||
const status = useMemo(() => (unlocking ? 'Unlock' : delegate.status), [unlocking, delegate]);
|
||||
|
||||
const statusColor = () => {
|
||||
switch (delegate.status) {
|
||||
switch (status) {
|
||||
case 'Vote':
|
||||
return 'bg-emerald-100 text-emerald-600';
|
||||
case 'Unlock':
|
||||
case 'Unvote':
|
||||
return 'bg-rose-100 text-rose-500';
|
||||
default:
|
||||
@@ -26,8 +29,7 @@ const TransactionPanel = observer(
|
||||
}
|
||||
};
|
||||
|
||||
const amountLabel =
|
||||
delegate.status === 'Vote' ? 'Voiting amount' : 'Unvoiting amount';
|
||||
const amountLabel = delegate.status === 'Vote' ? 'Voiting amount' : 'Unvoiting amount';
|
||||
|
||||
// close if the esc key is pressed
|
||||
useEffect(() => {
|
||||
@@ -40,12 +42,13 @@ const TransactionPanel = observer(
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const status = delegate.status;
|
||||
|
||||
if (status === 'Unvote') {
|
||||
setAmount(store.accountSentVotes[delegate.address].toString());
|
||||
}
|
||||
}, [delegate]);
|
||||
if (status === 'Unlock') {
|
||||
setAmount(store.accountLockedVotesCanReturnSum[delegate.address]?.toString());
|
||||
}
|
||||
}, [delegate, status]);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -70,9 +73,7 @@ const TransactionPanel = observer(
|
||||
</button>
|
||||
<div className="py-8 px-4 lg:px-8">
|
||||
<div className="max-w-sm mx-auto lg:max-w-none">
|
||||
<div className="text-slate-800 font-semibold text-center mb-1">
|
||||
Vote Transaction
|
||||
</div>
|
||||
<div className="text-slate-800 font-semibold text-center mb-1">Vote Transaction</div>
|
||||
<div className="text-sm text-center italic">
|
||||
{moment().format('DD/MM/YYYY hh:mm A')}
|
||||
</div>
|
||||
@@ -89,40 +90,28 @@ const TransactionPanel = observer(
|
||||
alt="Transaction 04"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={`text-2xl font-semibold mb-1 ${statusColor()} bg-transparent`}
|
||||
>
|
||||
<div className={`text-2xl font-semibold mb-1 ${statusColor()} bg-transparent`}>
|
||||
{amount}/idn
|
||||
</div>
|
||||
<div className="text-sm font-medium text-slate-800 mb-3">
|
||||
{delegate?.dpos?.delegate?.username ||
|
||||
formatAddressBig(delegate.address || '')}
|
||||
{delegate?.dpos?.delegate?.username || formatAddressBig(delegate.address || '')}
|
||||
</div>
|
||||
<div
|
||||
className={`text-xs inline-flex font-medium rounded-full text-center px-2.5 py-1 ${statusColor()} justify-center`}
|
||||
style={{ minWidth: '84px' }}
|
||||
>
|
||||
{delegate.status}
|
||||
{status}
|
||||
</div>
|
||||
</div>
|
||||
{/* Divider */}
|
||||
<div
|
||||
className="flex justify-between items-center"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<svg
|
||||
className="w-5 h-5 fill-white"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<div className="flex justify-between items-center" aria-hidden="true">
|
||||
<svg className="w-5 h-5 fill-white" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 20c5.523 0 10-4.477 10-10S5.523 0 0 0h20v20H0Z" />
|
||||
</svg>
|
||||
<div className="grow w-full h-5 bg-white flex flex-col justify-center">
|
||||
<div className="h-px w-full border-t border-dashed border-slate-200" />
|
||||
</div>
|
||||
<svg
|
||||
className="w-5 h-5 fill-white rotate-180"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<svg className="w-5 h-5 fill-white rotate-180" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0 20c5.523 0 10-4.477 10-10S5.523 0 0 0h20v20H0Z" />
|
||||
</svg>
|
||||
</div>
|
||||
@@ -136,9 +125,7 @@ const TransactionPanel = observer(
|
||||
</div>
|
||||
<div className="flex justify-between space-x-1">
|
||||
<span className="italic">FEE:</span>
|
||||
<span className="font-medium text-slate-700 text-right">
|
||||
145/idn
|
||||
</span>
|
||||
<span className="font-medium text-slate-700 text-right">145/idn</span>
|
||||
</div>
|
||||
<div className="flex justify-between space-x-1">
|
||||
<span className="italic">Nonce:</span>
|
||||
@@ -156,11 +143,9 @@ const TransactionPanel = observer(
|
||||
</div>
|
||||
{/* Receipts */}
|
||||
<div className="mt-6">
|
||||
<label
|
||||
className="block text-sm font-medium mb-1"
|
||||
htmlFor="mandatory"
|
||||
>
|
||||
{amountLabel} <span className="text-rose-500">*</span>
|
||||
<label className="block text-sm font-medium mb-1" htmlFor="mandatory">
|
||||
{unlocking ? 'Unlock amount' : amountLabel}{' '}
|
||||
<span className="text-rose-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="amount"
|
||||
@@ -169,13 +154,12 @@ const TransactionPanel = observer(
|
||||
required
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
value={amount}
|
||||
disabled={unlocking}
|
||||
/>
|
||||
</div>
|
||||
{/* Notes */}
|
||||
<div className="mt-6">
|
||||
<div className="text-sm font-semibold text-slate-800 mb-2">
|
||||
Transaction details
|
||||
</div>
|
||||
<div className="text-sm font-semibold text-slate-800 mb-2">Transaction details</div>
|
||||
<div className="flex p-2 justify-between items-center border border-slate-300 rounded-md">
|
||||
<div className="flex gap-2">
|
||||
<img
|
||||
@@ -185,9 +169,7 @@ const TransactionPanel = observer(
|
||||
height="32"
|
||||
alt="User"
|
||||
/>
|
||||
<div className="flex items-center text-sm text-slate-700">
|
||||
Balance
|
||||
</div>
|
||||
<div className="flex items-center text-sm text-slate-700">Balance</div>
|
||||
</div>
|
||||
<div className="flex items-center text-sm text-slate-700">
|
||||
{store.accountBalance}/idn
|
||||
|
||||
@@ -47,22 +47,16 @@ const TransactionsTable = observer(({ data, rowClick, lockedFor }) => {
|
||||
balance={delegate?.token?.balance}
|
||||
name={delegate.dpos?.delegate?.username || delegate.address}
|
||||
total={delegate.dpos?.delegate?.totalVotesReceived || ''}
|
||||
hasSevice={
|
||||
delegate.dpos?.delegate?.username === 'delegate_0'
|
||||
}
|
||||
hasSevice={delegate.dpos?.delegate?.username === 'delegate_0'}
|
||||
date={delegate.date}
|
||||
displayReturn={lockedFor === 'Unlocking'}
|
||||
status={delegate.status}
|
||||
amount={
|
||||
(lockedFor === 'Voiting'
|
||||
? store.accountSentVotes[delegate.address]
|
||||
: store.accountLockedVotesCanReturnSum[
|
||||
delegate.address
|
||||
]) || ''
|
||||
}
|
||||
handleClick={() =>
|
||||
lockedFor === 'Voiting' && rowClick(delegate)
|
||||
: store.accountLockedVotesCanReturnSum[delegate.address]) || ''
|
||||
}
|
||||
handleClick={() => rowClick(delegate)}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -24,11 +24,6 @@ const TransactionsTableItem = observer((props) => {
|
||||
}
|
||||
};
|
||||
|
||||
const clickReturn = (e) => {
|
||||
e.stopPropagation();
|
||||
store.pushUnlockTransaction(props.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<tr className="cursor-pointer" onClick={() => props.handleClick()}>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap md:w-1/2">
|
||||
@@ -71,14 +66,14 @@ const TransactionsTableItem = observer((props) => {
|
||||
</td>
|
||||
<td className="px-2 first:pl-5 last:pr-5 py-3 whitespace-nowrap">
|
||||
<div className="text-center">
|
||||
{props.displayReturn ? (
|
||||
{props.displayReturn && props.status !== 'Pending' ? (
|
||||
store.accountLockedVotesCanReturn[props.id] && (
|
||||
<span
|
||||
className="truncate font-medium text-indigo-500 group-hover:text-indigo-600 ml-2"
|
||||
onClick={clickReturn}
|
||||
<div
|
||||
className={`text-xs inline-flex font-medium rounded-full justify-center px-2.5 py-1 bg-rose-100 text-rose-500`}
|
||||
style={{ minWidth: '84px' }}
|
||||
>
|
||||
Return votes
|
||||
</span>
|
||||
Unlock
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
import {
|
||||
reaction,
|
||||
makeAutoObservable,
|
||||
onBecomeObserved,
|
||||
onBecomeUnobserved,
|
||||
} from 'mobx';
|
||||
import { reaction, makeAutoObservable, onBecomeObserved, onBecomeUnobserved } from 'mobx';
|
||||
import { cryptography, transactions } from '@liskhq/lisk-client';
|
||||
import { passphrase } from '@liskhq/lisk-client';
|
||||
import { getNodeInfo } from '../api/node';
|
||||
@@ -67,20 +62,12 @@ class Store {
|
||||
() => this.address,
|
||||
() => this.fetchAccountInfo()
|
||||
);
|
||||
onBecomeObserved(this, 'decryptedAccountData', () =>
|
||||
this.fetchNewAccountData()
|
||||
);
|
||||
onBecomeUnobserved(this, 'decryptedAccountData', () =>
|
||||
this.unobservedAccountData()
|
||||
);
|
||||
onBecomeObserved(this, 'decryptedAccountData', () => this.fetchNewAccountData());
|
||||
onBecomeUnobserved(this, 'decryptedAccountData', () => this.unobservedAccountData());
|
||||
onBecomeObserved(this, 'sharedData', () => this.fetchKeysArray());
|
||||
onBecomeUnobserved(this, 'sharedData', () => this.unobservedSharedData());
|
||||
onBecomeObserved(this, 'transactionsInfo', () =>
|
||||
this.fetchTransactionsInfo()
|
||||
);
|
||||
onBecomeUnobserved(this, 'transactionsInfo', () =>
|
||||
this.unobservedTransactionsInfo()
|
||||
);
|
||||
onBecomeObserved(this, 'transactionsInfo', () => this.fetchTransactionsInfo());
|
||||
onBecomeUnobserved(this, 'transactionsInfo', () => this.unobservedTransactionsInfo());
|
||||
|
||||
this.fetchNodeInfo();
|
||||
}
|
||||
@@ -342,8 +329,7 @@ class Store {
|
||||
fetchAccountInfoSuccess(res) {
|
||||
this._accountInfo = res.data;
|
||||
if (this.accountInfo?.sequence?.nonce)
|
||||
this.accountInfo.sequence.nonce =
|
||||
parseInt(this.accountInfo.sequence.nonce) || 0;
|
||||
this.accountInfo.sequence.nonce = parseInt(this.accountInfo.sequence.nonce) || 0;
|
||||
}
|
||||
|
||||
fetchTempTransactionsSuccess(res) {
|
||||
@@ -370,24 +356,23 @@ class Store {
|
||||
.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
sender_avatar:
|
||||
item.asset.recipientAddress &&
|
||||
generateSvgAvatar(item.senderPublicKey),
|
||||
sender_avatar: item?.asset?.recipientAddress && generateSvgAvatar(item.senderPublicKey),
|
||||
avatar_size: 24,
|
||||
transaction: item.asset.features.map((asset) => {
|
||||
return {
|
||||
transaction_id: item.id,
|
||||
address:
|
||||
item.asset.recipientAddress &&
|
||||
cryptography.bufferToHex(
|
||||
cryptography.getAddressFromPublicKey(
|
||||
cryptography.hexToBuffer(item.senderPublicKey)
|
||||
)
|
||||
),
|
||||
value: asset.value,
|
||||
label: labelMap[asset.label] || asset.label,
|
||||
};
|
||||
}),
|
||||
transaction:
|
||||
item.asset?.features?.map((asset) => {
|
||||
return {
|
||||
transaction_id: item.id,
|
||||
address:
|
||||
item.asset.recipientAddress &&
|
||||
cryptography.bufferToHex(
|
||||
cryptography.getAddressFromPublicKey(
|
||||
cryptography.hexToBuffer(item.senderPublicKey)
|
||||
)
|
||||
),
|
||||
value: asset.value,
|
||||
label: labelMap[asset.label] || asset.label,
|
||||
};
|
||||
}) || [],
|
||||
};
|
||||
});
|
||||
}
|
||||
@@ -402,13 +387,11 @@ class Store {
|
||||
}
|
||||
|
||||
get firstName() {
|
||||
return this.decryptedAccountData.find((item) => item.key === 'firstname')
|
||||
?.value;
|
||||
return this.decryptedAccountData.find((item) => item.key === 'firstname')?.value;
|
||||
}
|
||||
|
||||
get lastName() {
|
||||
return this.decryptedAccountData.find((item) => item.key === 'secondname')
|
||||
?.value;
|
||||
return this.decryptedAccountData.find((item) => item.key === 'secondname')?.value;
|
||||
}
|
||||
|
||||
get accountName() {
|
||||
@@ -440,16 +423,12 @@ class Store {
|
||||
}
|
||||
|
||||
get privateKey() {
|
||||
return cryptography.getPrivateAndPublicKeyFromPassphrase(this.passPhrase)
|
||||
?.privateKey;
|
||||
return cryptography.getPrivateAndPublicKeyFromPassphrase(this.passPhrase)?.privateKey;
|
||||
}
|
||||
|
||||
get vpnPrivateKey() {
|
||||
let x25519_sk = Buffer.alloc(sodium.crypto_box_SECRETKEYBYTES);
|
||||
sodium.crypto_sign_ed25519_sk_to_curve25519(
|
||||
x25519_sk,
|
||||
Buffer.from(this.privateKey, 'hex')
|
||||
);
|
||||
sodium.crypto_sign_ed25519_sk_to_curve25519(x25519_sk, Buffer.from(this.privateKey, 'hex'));
|
||||
return x25519_sk.toString('Base64');
|
||||
}
|
||||
|
||||
@@ -462,8 +441,7 @@ class Store {
|
||||
}
|
||||
|
||||
get tokenKey() {
|
||||
const stringToSign =
|
||||
this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID;
|
||||
const stringToSign = this.nodeInfo.networkIdentifier + this.nodeInfo.lastBlockID;
|
||||
if (!stringToSign) return '';
|
||||
const sign = cryptography
|
||||
.signDataWithPassphrase(Buffer.from(stringToSign, 'hex'), this.passPhrase)
|
||||
@@ -480,17 +458,14 @@ class Store {
|
||||
}
|
||||
|
||||
get accountBalance() {
|
||||
return (
|
||||
BigInt(this.accountInfo?.token?.balance || 0) / 100000000n
|
||||
).toString();
|
||||
return (BigInt(this.accountInfo?.token?.balance || 0) / 100000000n).toString();
|
||||
}
|
||||
|
||||
get accountSentVotes() {
|
||||
return (this.accountInfo?.dpos?.sentVotes || []).reduce(
|
||||
(acc, e) => ({
|
||||
...acc,
|
||||
[e.delegateAddress]:
|
||||
BigInt(e.amount || 0) / 100000000n + (acc[e.delegateAddress] || 0n),
|
||||
[e.delegateAddress]: BigInt(e.amount || 0) / 100000000n + (acc[e.delegateAddress] || 0n),
|
||||
}),
|
||||
{}
|
||||
);
|
||||
@@ -500,8 +475,7 @@ class Store {
|
||||
return (this.accountInfo?.dpos?.unlocking || []).reduce(
|
||||
(acc, e) => ({
|
||||
...acc,
|
||||
[e.delegateAddress]:
|
||||
BigInt(e.amount || 0) / 100000000n + (acc[e.delegateAddress] || 0n),
|
||||
[e.delegateAddress]: BigInt(e.amount || 0) / 100000000n + (acc[e.delegateAddress] || 0n),
|
||||
}),
|
||||
{}
|
||||
);
|
||||
@@ -563,10 +537,7 @@ class Store {
|
||||
const { features } = item.asset;
|
||||
return {
|
||||
...acc,
|
||||
...(features?.reduce(
|
||||
(obj, feature) => ({ ...obj, [feature.label]: true }),
|
||||
{}
|
||||
) || {}),
|
||||
...(features?.reduce((obj, feature) => ({ ...obj, [feature.label]: true }), {}) || {}),
|
||||
};
|
||||
}, {});
|
||||
}
|
||||
@@ -582,10 +553,7 @@ class Store {
|
||||
(obj, vote) => ({
|
||||
...obj,
|
||||
[vote.delegateAddress]:
|
||||
BigInt(
|
||||
Number(vote.amount) > 0 ? vote.amount : vote.amount.slice(1)
|
||||
) /
|
||||
100000000n +
|
||||
BigInt(Number(vote.amount) > 0 ? vote.amount : vote.amount.slice(1)) / 100000000n +
|
||||
(obj[vote.delegateAddress] || 0n),
|
||||
}),
|
||||
{}
|
||||
@@ -605,8 +573,7 @@ class Store {
|
||||
(obj, vote) => ({
|
||||
...obj,
|
||||
[vote.delegateAddress]:
|
||||
BigInt(vote.amount) / 100000000n +
|
||||
(obj[vote.delegateAddress] || 0n),
|
||||
BigInt(vote.amount) / 100000000n + (obj[vote.delegateAddress] || 0n),
|
||||
}),
|
||||
{}
|
||||
) || {}),
|
||||
@@ -617,9 +584,7 @@ class Store {
|
||||
get vpnServers() {
|
||||
return this._vpnServers?.map((server) => ({
|
||||
...server,
|
||||
transferSum: formatBytes(
|
||||
Number(server.transferTx || 0) + Number(server.transferRx || 0)
|
||||
),
|
||||
transferSum: formatBytes(Number(server.transferTx || 0) + Number(server.transferRx || 0)),
|
||||
trafficUsed: Math.floor(
|
||||
((Number(server.transferTx || 0) + Number(server.transferRx || 0)) /
|
||||
(50 * 1024 * 1024 * 1024)) *
|
||||
@@ -638,7 +603,7 @@ class Store {
|
||||
const getStatus = (delegate) => {
|
||||
const { address } = delegate;
|
||||
|
||||
let amount = this.processedVotes[address];
|
||||
let amount = this.processedVotes[address] || this.processedUnlocking[address];
|
||||
|
||||
if (amount) return 'Pending';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user