diff --git a/packages/apps/dev-wallet/src/Components/AccountItem/AccountItem.tsx b/packages/apps/dev-wallet/src/Components/AccountItem/AccountItem.tsx index 42f4444a3d..0b9cec5152 100644 --- a/packages/apps/dev-wallet/src/Components/AccountItem/AccountItem.tsx +++ b/packages/apps/dev-wallet/src/Components/AccountItem/AccountItem.tsx @@ -4,6 +4,8 @@ import { } from '@/modules/account/account.repository'; import { useWallet } from '@/modules/wallet/wallet.hook'; import { noStyleLinkClass } from '@/pages/home/style.css'; +import { hashStyle } from '@/pages/transactions/style.css'; +import { shorten } from '@/utils/helpers'; import { MonoContentCopy } from '@kadena/kode-icons/system'; import { Button, Stack, Text } from '@kadena/kode-ui'; import { Link } from 'react-router-dom'; @@ -26,16 +28,15 @@ export function AccountItem({ alignItems={'center'} > - - {alias ? ( - <> - {alias} - ({address}) - - ) : ( - {address} - )} - + {alias ? ( + + {alias} + ({shorten(address, 10)}) + + ) : ( + {shorten(address, 10)} + )} + {overallBalance} {getSymbol(contract)} diff --git a/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx b/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx index a55b2fb986..37b8c4b644 100644 --- a/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx +++ b/packages/apps/dev-wallet/src/Components/FundOnTestnet/FundOnTestnet.tsx @@ -1,7 +1,5 @@ import { IAccount } from '@/modules/account/account.repository'; -import { syncAccount } from '@/modules/account/account.service'; import { ITransaction } from '@/modules/transaction/transaction.repository'; -import { useWallet } from '@/modules/wallet/wallet.hook'; import { TxContainer } from '@/pages/transaction/components/TxContainer'; import { ChainId } from '@kadena/client'; import { MonoAutorenew } from '@kadena/kode-icons/system'; @@ -10,7 +8,6 @@ import classNames from 'classnames'; import { useState } from 'react'; export function FundOnTestnetButton({ - account, chainId, fundAccountHandler, className, @@ -21,7 +18,6 @@ export function FundOnTestnetButton({ className?: string; }) { const [fundTx, setFundTx] = useState(); - const { syncAllAccounts } = useWallet(); const [done, setDone] = useState(false); return ( @@ -50,11 +46,6 @@ export function FundOnTestnetButton({ as="minimized" onDone={(tx) => { setFundTx(tx); - if (account) { - syncAccount(account); - } else { - syncAllAccounts(); - } setDone(true); }} /> diff --git a/packages/apps/dev-wallet/src/Components/ListItem/style.css.ts b/packages/apps/dev-wallet/src/Components/ListItem/style.css.ts index 6f1caeca01..f41f5f9e8e 100644 --- a/packages/apps/dev-wallet/src/Components/ListItem/style.css.ts +++ b/packages/apps/dev-wallet/src/Components/ListItem/style.css.ts @@ -27,6 +27,7 @@ export const listItemClass = style([ { border: 'none', flex: 1, + maxWidth: '100%', minHeight: '50px', background: tokens.kda.foundation.color.background.surface.default, selectors: { diff --git a/packages/apps/dev-wallet/src/modules/db/db.service.tsx b/packages/apps/dev-wallet/src/modules/db/db.service.tsx index 55d32db296..b3d45ed409 100644 --- a/packages/apps/dev-wallet/src/modules/db/db.service.tsx +++ b/packages/apps/dev-wallet/src/modules/db/db.service.tsx @@ -158,6 +158,17 @@ const injectDb = Promise>( type EventTypes = 'add' | 'update' | 'delete'; // eslint-disable-next-line @typescript-eslint/no-explicit-any type Listener = (type: EventTypes, storeName: string, ...data: any[]) => void; + +export interface ISubscribe { + /** + * Subscribe to changes in a store + */ + (cb: Listener): () => void; + /** + * Subscribe to changes in a store + */ + (storeName: string, uuid: string, cb: (data: any) => void): () => void; +} export interface IDBService { getAll: ( storeName: string, @@ -177,12 +188,32 @@ export interface IDBService { key?: string | undefined, ) => Promise; remove: (storeName: string, key: string) => Promise; - subscribe: (cb: Listener) => () => void; + subscribe: ISubscribe; } export const createDbService = () => { const listeners: Listener[] = []; - const subscribe: IDBService['subscribe'] = (cb) => { + const subscribe: ISubscribe = ( + first: string | Listener, + second?: string, + third?: (data: any) => void, + ) => { + let cb: Listener; + if (typeof first === 'string' && second && third) { + cb = (event, storeName, data) => { + if (storeName === first && event) { + if (event === 'delete' && data === second) { + third(undefined); + } else if (data.uuid === second) { + third(data); + } + } + }; + } else if (typeof first === 'function') { + cb = first; + } else { + throw new Error('Invalid arguments'); + } listeners.push(cb); return () => { const index = listeners.indexOf(cb); diff --git a/packages/apps/dev-wallet/src/modules/db/useSubscribe.ts b/packages/apps/dev-wallet/src/modules/db/useSubscribe.ts new file mode 100644 index 0000000000..a2b6a61b3d --- /dev/null +++ b/packages/apps/dev-wallet/src/modules/db/useSubscribe.ts @@ -0,0 +1,20 @@ +import { useEffect, useState } from 'react'; +import { dbService } from './db.service'; + +export function useSubscribe(table: string, uuid: string | undefined) { + const [state, setState] = useState(); + + useEffect(() => { + if (!uuid) return; + let unsubscribe: () => void = () => {}; + const run = async () => { + const dbState: T = await dbService.getOne(table, uuid); + setState(dbState); + unsubscribe = dbService.subscribe(table, uuid, setState); + }; + run(); + return () => unsubscribe(); + }, [table, uuid]); + + return state; +} diff --git a/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts b/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts index 06f394d5d6..52f6da32e0 100644 --- a/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts +++ b/packages/apps/dev-wallet/src/modules/transaction/transaction.service.ts @@ -166,7 +166,7 @@ export async function syncTransactionStatus( }, }; await transactionRepository.updateTransaction(updatedTx); - await onSubmitTransaction(contTx, client); + await submitTransaction(contTx, client); const txd = await transactionRepository.getTransaction(tx.uuid); const updatedTxd = { ...txd, @@ -179,7 +179,7 @@ export async function syncTransactionStatus( return tx; } -export const onSubmitTransaction = async ( +export const submitTransaction = async ( tx: ITransaction, client: IClient, onUpdate: (tx: ITransaction) => void = () => {}, @@ -301,7 +301,7 @@ export const onSubmitTransaction = async ( }; await transactionRepository.updateTransaction(updatedTx); onUpdate(updatedTx); - await onSubmitTransaction(contTx, client, (tx) => { + await submitTransaction(contTx, client, (tx) => { updatedTx = { ...updatedTx, continuation: { diff --git a/packages/apps/dev-wallet/src/modules/wallet/wallet.hook.tsx b/packages/apps/dev-wallet/src/modules/wallet/wallet.hook.tsx index 2c52db83df..476fa3cdfb 100644 --- a/packages/apps/dev-wallet/src/modules/wallet/wallet.hook.tsx +++ b/packages/apps/dev-wallet/src/modules/wallet/wallet.hook.tsx @@ -283,9 +283,9 @@ export const useWallet = () => { const availableKey = keySource.keys.find( (key) => !usedKeys.includes(key.publicKey), ); - // prompt for password anyway for account creation even if the key is available. - await askForPassword(); if (availableKey) { + // prompt for password anyway for account creation even if the key is available. + await askForPassword(); return createAccountByKey({ key: availableKey, contract, alias }); } // If no available key, create a new one diff --git a/packages/apps/dev-wallet/src/pages/account/account.tsx b/packages/apps/dev-wallet/src/pages/account/account.tsx index b1c73fee00..6b4c0a4fe0 100644 --- a/packages/apps/dev-wallet/src/pages/account/account.tsx +++ b/packages/apps/dev-wallet/src/pages/account/account.tsx @@ -1,6 +1,6 @@ import { useWallet } from '@/modules/wallet/wallet.hook'; -import { fundAccount } from '@/modules/account/account.service'; +import { fundAccount, syncAccount } from '@/modules/account/account.service'; import { AccountBalanceDistribution } from '@/Components/AccountBalanceDistribution/AccountBalanceDistribution'; import { ConfirmDeletion } from '@/Components/ConfirmDeletion/ConfirmDeletion'; @@ -12,6 +12,7 @@ import { isWatchedAccount, } from '@/modules/account/account.repository'; import { getTransferActivities } from '@/modules/activity/activity.service'; +import * as transactionService from '@/modules/transaction/transaction.service'; import { useAsync } from '@/utils/useAsync'; import { ChainId } from '@kadena/client'; import { MonoKey, MonoRemoveRedEye } from '@kadena/kode-icons/system'; @@ -26,7 +27,7 @@ import { Redistribute } from './Components/Redistribute'; export function AccountPage() { const { accountId } = useParams(); const prompt = usePrompt(); - const { activeNetwork, fungibles, accounts, profile, watchAccounts } = + const { activeNetwork, fungibles, accounts, profile, watchAccounts, client } = useWallet(); const [redistributionGroupId, setRedistributionGroupId] = useState(); const account = @@ -64,7 +65,7 @@ export function AccountPage() { if (!activeNetwork) { throw new Error('No active network found'); } - const tx = await fundAccount({ + const fundTx = await fundAccount({ address: account?.address ?? keyset.principal, chainId, keyset, @@ -72,7 +73,18 @@ export function AccountPage() { network: activeNetwork, }); - return tx; + transactionService + .submitTransaction(fundTx, client) + .then((tx) => { + if (tx.result?.result.status === 'success') { + syncAccount(account); + } + }) + .catch((e) => { + console.error(e); + }); + + return fundTx; }; const isOwnedAccount = !isWatchedAccount(account) && account.profileId === profile?.uuid; @@ -200,6 +212,7 @@ export function AccountPage() { groupId={redistributionGroupId} onDone={() => { setRedistributionGroupId(undefined); + syncAccount(account); }} /> )} diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx index a01e1f27f3..d1cfd839fb 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxContainer.tsx @@ -1,4 +1,4 @@ -import { dbService } from '@/modules/db/db.service'; +import { useSubscribe } from '@/modules/db/useSubscribe'; import { ITransaction, transactionRepository, @@ -29,62 +29,46 @@ export const TxContainer = React.memo( onUpdate?: (tx: ITransaction) => void; onDone?: (tx: ITransaction) => void; }) => { - const [localTransaction, setLocalTransaction] = - useState(null); - - const [contTx, setContTx] = useState(); const [expandedModal, setExpandedModal] = useState(false); const { sign, client } = useWallet(); const syncing = useRef(false); + const doneRef = useRef(false); + + const localTransaction = useSubscribe( + 'transaction', + transaction.uuid, + ); + const contTx = useSubscribe( + 'transaction', + transaction.continuation?.continuationTxId, + ); useEffect(() => { - if (!transaction) return; - const unsubscribe = dbService.subscribe((event, table, data) => { - if (table !== 'transaction' || event !== 'update') return; - if (data.uuid === transaction.uuid) { - setLocalTransaction(data); - console.log( - 'data.continuation?.continuationTxId', - data.continuation?.continuationTxId, - 'contTx?.uuid', - contTx?.uuid, - ); - if (data.continuation?.continuationTxId && !contTx?.uuid) { - console.log('fetching contTx'); - transactionRepository - .getTransaction(data.continuation.continuationTxId) - .then(setContTx); - } - return; - } - if (contTx?.uuid === data.uuid) { - setContTx(data); - return; + if ( + localTransaction && + localTransaction.status === 'success' && + (!localTransaction.continuation?.autoContinue || + contTx?.status === 'success') + ) { + if (onDone && !doneRef.current) { + doneRef.current = true; + console.log('onDone', localTransaction); + onDone(localTransaction); } - }); - if (!syncing.current) { - syncing.current = true; - transactionService.syncTransactionStatus(transaction, client); } - return () => { - unsubscribe(); - }; - }, [transaction.uuid, contTx?.uuid, transaction, client]); + if (localTransaction?.status === 'submitted' && onUpdate) { + console.log('onUpdate', localTransaction); + onUpdate(localTransaction); + } + }, [localTransaction?.status, contTx?.status]); useEffect(() => { if (!transaction) return; - const run = async () => { - const tx = await transactionRepository.getTransaction(transaction.uuid); - setLocalTransaction(tx); - if (tx.continuation?.continuationTxId) { - const cont = await transactionRepository.getTransaction( - tx.continuation.continuationTxId, - ); - setContTx(cont); - } - }; - run(); - }, [transaction]); + if (transaction && !syncing.current) { + syncing.current = true; + transactionService.syncTransactionStatus(transaction, client); + } + }, [transaction.uuid]); const onSign = async (tx: ITransaction) => { const signed = (await sign(tx)) as IUnsignedCommand; @@ -124,7 +108,7 @@ export const TxContainer = React.memo( const onSubmit = useCallback( async (tx: ITransaction) => { - const result = await transactionService.onSubmitTransaction( + const result = await transactionService.submitTransaction( tx, client, // (updatedTx) => { @@ -132,10 +116,10 @@ export const TxContainer = React.memo( // }, ); if (onUpdate) onUpdate(result); - if (onDone) onDone(result); + return result; }, - [client, onDone, onUpdate], + [client, onUpdate], ); if (!localTransaction) return null; diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx index 1175839d88..aa9b59a814 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxList.tsx @@ -75,7 +75,7 @@ export const TxList = React.memo( const onSendAll = async () => { const onSubmit = async (tx: ITransaction) => { - return transactionService.onSubmitTransaction(tx, client, updateTx); + return transactionService.submitTransaction(tx, client, updateTx); }; const txs = await Promise.all( diff --git a/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx b/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx index c9314835e7..cb3871b235 100644 --- a/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx +++ b/packages/apps/dev-wallet/src/pages/transaction/components/TxMinimized.tsx @@ -3,7 +3,6 @@ import { ITransaction } from '@/modules/transaction/transaction.repository'; import { MonoOpenInFull } from '@kadena/kode-icons/system'; import { Button, Stack } from '@kadena/kode-ui'; -import { useEffect, useRef } from 'react'; import { TxPipeLine } from './TxPipeLine'; import { txMinimizedClass } from './style.css'; @@ -24,13 +23,6 @@ export const TxMinimized = ({ sendDisabled?: boolean; interactive?: boolean; }) => { - const submittedRef = useRef(false); - useEffect(() => { - if (tx.status === 'signed' && !submittedRef.current) { - submittedRef.current = true; - onSubmit(); - } - }, [onSubmit, tx.status]); return ( )} - {(step === 'sign' || step === 'result') && renderSignStep()} + {(step === 'sign' || step === 'result' || step === 'summary') && + renderSignStep()} ); }