diff --git a/packages/neuron-ui/src/components/Send/hooks.ts b/packages/neuron-ui/src/components/Send/hooks.ts index 42d892b5e3..f53ac59705 100644 --- a/packages/neuron-ui/src/components/Send/hooks.ts +++ b/packages/neuron-ui/src/components/Send/hooks.ts @@ -2,12 +2,16 @@ import React, { useCallback, useEffect } from 'react' import { IDropdownOption } from 'office-ui-fabric-react' import { AppActions, StateDispatch } from 'states/stateProvider/reducer' +import { calculateCycles } from 'services/remote/wallets' import { Message } from 'utils/const' import { verifyAddress, verifyAmountRange } from 'utils/validators' +import { CKBToShannonFormatter } from 'utils/formatters' import { TransactionOutput } from '.' -const validateTransactionParams = ({ items, dispatch }: { items: TransactionOutput[]; dispatch: StateDispatch }) => { +let cyclesTimer: ReturnType + +const validateTransactionParams = ({ items, dispatch }: { items: TransactionOutput[]; dispatch?: StateDispatch }) => { const errorAction = { type: AppActions.AddNotification, payload: { @@ -17,7 +21,9 @@ const validateTransactionParams = ({ items, dispatch }: { items: TransactionOutp }, } if (!items.length || !items[0].address) { - dispatch(errorAction) + if (dispatch) { + dispatch(errorAction) + } return false } const invalid = items.some( @@ -42,7 +48,7 @@ const validateTransactionParams = ({ items, dispatch }: { items: TransactionOutp return false } ) - if (invalid) { + if (invalid && dispatch) { dispatch(errorAction) return false } @@ -84,6 +90,42 @@ const useRemoveTransactionOutput = (dispatch: StateDispatch) => [dispatch] ) +const useOnTransactionChange = (walletID: string, items: TransactionOutput[], dispatch: StateDispatch) => { + useEffect(() => { + clearTimeout(cyclesTimer) + cyclesTimer = setTimeout(() => { + if (validateTransactionParams({ items })) { + calculateCycles({ + walletID, + items: items.map(item => ({ + address: item.address, + capacity: CKBToShannonFormatter(item.amount, item.unit), + })), + }) + .then(response => { + if (response.status) { + if (Number.isNaN(+response.result)) { + throw new Error('Invalid Cycles') + } + dispatch({ + type: AppActions.UpdateSendCycles, + payload: response.result, + }) + } else { + throw new Error('Cycles Not Calculated') + } + }) + .catch(() => { + dispatch({ + type: AppActions.UpdateSendCycles, + payload: '0', + }) + }) + } + }, 300) + }, [walletID, items, dispatch]) +} + const useOnSubmit = (items: TransactionOutput[], dispatch: StateDispatch) => useCallback( (walletID: string = '') => () => { @@ -188,6 +230,7 @@ export const useInitialize = ( }, [address, dispatch, history, updateTransactionOutput]) return { + useOnTransactionChange, updateTransactionOutput, onItemChange, onCapacityUnitChange, diff --git a/packages/neuron-ui/src/components/Send/index.tsx b/packages/neuron-ui/src/components/Send/index.tsx index f4ed70e96b..6f77bee3ee 100644 --- a/packages/neuron-ui/src/components/Send/index.tsx +++ b/packages/neuron-ui/src/components/Send/index.tsx @@ -45,6 +45,7 @@ const Send = ({ }: React.PropsWithoutRef>) => { const { t } = useTranslation() const { + useOnTransactionChange, updateTransactionOutput, onItemChange, onSubmit, @@ -54,6 +55,7 @@ const Send = ({ onDescriptionChange, onClear, } = useInitialize(address, send.outputs, dispatch, history) + useOnTransactionChange(walletID, send.outputs, dispatch) const leftStackWidth = '70%' const labelWidth = '140px' const actionSpacer = ( diff --git a/packages/neuron-ui/src/services/remote/wallets.ts b/packages/neuron-ui/src/services/remote/wallets.ts index 8c3ca86b5d..81934fdc3b 100644 --- a/packages/neuron-ui/src/services/remote/wallets.ts +++ b/packages/neuron-ui/src/services/remote/wallets.ts @@ -42,6 +42,10 @@ export const updateAddressDescription = controllerMethodWrapper(CONTROLLER_NAME) controller => (params: Controller.UpdateAddressDescriptionParams) => controller.updateAddressDescription(params) ) +export const calculateCycles = controllerMethodWrapper(CONTROLLER_NAME)( + controller => (params: Controller.CalculateCycles) => controller.calculateCycles(params) +) + export default { updateWallet, getWalletList, @@ -52,6 +56,7 @@ export default { backupWallet, getCurrentWallet, sendCapacity, + calculateCycles, getAddressesByWalletID, updateAddressDescription, } diff --git a/packages/neuron-ui/src/states/stateProvider/reducer.ts b/packages/neuron-ui/src/states/stateProvider/reducer.ts index 830e3bcb22..e5d47ccda4 100644 --- a/packages/neuron-ui/src/states/stateProvider/reducer.ts +++ b/packages/neuron-ui/src/states/stateProvider/reducer.ts @@ -26,6 +26,7 @@ export enum AppActions { RemoveSendOutput = 'removeSendOutput', UpdateSendOutput = 'updateSendOutput', UpdateSendPrice = 'updateSendPrice', + UpdateSendCycles = 'updateSendCycles', UpdateSendDescription = 'updateSendDescription', ClearSendState = 'clearSendState', UpdateSendLoading = 'updateSendLoading', @@ -336,6 +337,21 @@ export const reducer = ( }, } } + case AppActions.UpdateSendCycles: { + /** + * payload: new cycles + */ + return { + ...state, + app: { + ...app, + send: { + ...app.send, + cycles: payload, + }, + }, + } + } case AppActions.UpdateSendDescription: { /** * payload: new description diff --git a/packages/neuron-ui/src/types/Controller/index.d.ts b/packages/neuron-ui/src/types/Controller/index.d.ts index 7cb8215b0b..fd0a527f51 100644 --- a/packages/neuron-ui/src/types/Controller/index.d.ts +++ b/packages/neuron-ui/src/types/Controller/index.d.ts @@ -45,6 +45,14 @@ declare namespace Controller { description: string } + interface CalculateCycles { + walletID: string + items: { + address: string + capacity: string + } + } + type GetAddressesByWalletIDParams = string interface UpdateAddressDescriptionParams { walletID: string diff --git a/packages/neuron-wallet/src/controllers/wallets/index.ts b/packages/neuron-wallet/src/controllers/wallets/index.ts index f749127c7d..726b3665ec 100644 --- a/packages/neuron-wallet/src/controllers/wallets/index.ts +++ b/packages/neuron-wallet/src/controllers/wallets/index.ts @@ -392,6 +392,16 @@ export default class WalletsController { } } + @CatchControllerError + public static async calculateCycles(params: { walletID: string; items: { address: string; capacity: string }[] }) { + // TODO: This is a mock cycles + const cycles = params.items.filter(item => +item.capacity > 0).length.toString() + return { + status: ResponseCode.Success, + result: cycles, + } + } + @CatchControllerError public static async updateAddressDescription({ walletID,