From a1b5abe78ea57cd2d845a998f85205a4bfaefbf7 Mon Sep 17 00:00:00 2001 From: Keith Date: Tue, 7 May 2019 18:08:54 +0800 Subject: [PATCH] refactor(neuron-ui): complement hook deps in several components, remove useless code, rename some method names --- .../src/components/Addresses/Address.ts | 7 - .../src/components/Addresses/index.tsx | 111 ++++---- .../src/components/NetworkEditor/hooks.ts | 18 +- .../src/components/NetworkEditor/index.tsx | 4 +- .../neuron-ui/src/components/Router/index.tsx | 1 + .../src/components/Transfer/hooks.ts | 130 ++++++++++ .../src/components/Transfer/index.tsx | 155 +++-------- .../src/components/WalletEditor/hooks.ts | 10 +- .../src/components/WalletEditor/index.tsx | 29 ++- .../src/components/WalletWizard/index.tsx | 4 +- .../MainContent/actionCreators/wallets.ts | 27 +- .../src/containers/MainContent/hooks.ts | 15 ++ .../src/containers/MainContent/reducer.ts | 9 - .../src/containers/MainContent/state.ts | 17 -- .../src/containers/Providers/hooks.ts | 243 ++++++++++++++++++ .../src/containers/Providers/index.tsx | 240 +---------------- .../neuron-ui/src/widgets/QRScanner/index.tsx | 20 +- packages/neuron-wallet/src/utils/store.ts | 2 +- 18 files changed, 549 insertions(+), 493 deletions(-) delete mode 100644 packages/neuron-ui/src/components/Addresses/Address.ts create mode 100644 packages/neuron-ui/src/components/Transfer/hooks.ts create mode 100644 packages/neuron-ui/src/containers/MainContent/hooks.ts create mode 100644 packages/neuron-ui/src/containers/Providers/hooks.ts diff --git a/packages/neuron-ui/src/components/Addresses/Address.ts b/packages/neuron-ui/src/components/Addresses/Address.ts deleted file mode 100644 index c98840ab6e..0000000000 --- a/packages/neuron-ui/src/components/Addresses/Address.ts +++ /dev/null @@ -1,7 +0,0 @@ -export const Change = 'Change' -export const Receiving = 'Receiving' - -export interface Address { - type: string - address: string -} diff --git a/packages/neuron-ui/src/components/Addresses/index.tsx b/packages/neuron-ui/src/components/Addresses/index.tsx index 4285baf461..5743291a89 100644 --- a/packages/neuron-ui/src/components/Addresses/index.tsx +++ b/packages/neuron-ui/src/components/Addresses/index.tsx @@ -1,11 +1,12 @@ -import React, { useCallback } from 'react' +import React, { useCallback, useMemo } from 'react' import { Container } from 'react-bootstrap' import { RouteComponentProps } from 'react-router-dom' import { useTranslation } from 'react-i18next' import { History } from 'history' -import { Routes, EXPLORER } from 'utils/const' + import Table from 'widgets/Table' import ContextMenuZone from 'widgets/ContextMenuZone' +import { Routes, EXPLORER } from 'utils/const' import { useNeuronWallet } from 'utils/hooks' const headers = [ @@ -29,35 +30,39 @@ const headers = [ const AddressPanel = ({ address, history }: { address: string; history: History }) => { const [t] = useTranslation() - const actionItems = [ - { - label: t('addresses.actions.copy-address'), - click: () => { - window.clipboard.writeText(address) + const actionItems = useMemo( + () => [ + { + label: t('addresses.actions.copy-address'), + click: () => { + window.clipboard.writeText(address) + }, }, - }, - { - label: t('addresses.actions.request-payment'), - click: () => { - window.clipboard.writeText(address) - history.push(`${Routes.Receive}/${address}`) + { + label: t('addresses.actions.request-payment'), + click: () => { + window.clipboard.writeText(address) + history.push(`${Routes.Receive}/${address}`) + }, }, - }, - { - label: t('addresses.actions.spend-from'), - click: () => { - window.clipboard.writeText(address) - // TODO: navigate to send page with address + { + label: t('addresses.actions.spend-from'), + click: () => { + window.clipboard.writeText(address) + history.push(`${Routes.Send}/${address}`) + }, }, - }, - { - label: t('addresses.actions.view-on-explorer'), - click: () => { - window.clipboard.writeText(address) - window.open(EXPLORER) + { + label: t('addresses.actions.view-on-explorer'), + click: () => { + window.clipboard.writeText(address) + window.open(EXPLORER) + }, }, - }, - ] + ], + [history, address, t], + ) + return ( {address} @@ -65,30 +70,40 @@ const AddressPanel = ({ address, history }: { address: string; history: History ) } -const Addresses = (props: React.PropsWithoutRef) => { +const Addresses = ({ history }: React.PropsWithoutRef) => { const { - wallet: { addresses }, + wallet: { + addresses: { receiving, change }, + }, } = useNeuronWallet() const [t] = useTranslation() - const [pageNo, pageSize, totalCount] = [0, 20, 20] const onPageChange = useCallback(() => {}, []) - const { history } = props - const receivingAddresses = addresses.receiving.map(address => ({ - type: 'Receiving', - address: , - balance: '0', - transactions: '0', - key: address, - })) + const receivingAddresses = useMemo( + () => + receiving.map(address => ({ + type: 'Receiving', + address: , + balance: '0', + transactions: '0', + key: address, + })), + [receiving, history], + ) + + const changeAddresses = useMemo( + () => + change.map(address => ({ + type: 'Change', + address: , + balance: '0', + transactions: '0', + key: address, + })), + [change, history], + ) - const changeAddresses = addresses.change.map(address => ({ - type: 'Change', - address: , - balance: '0', - transactions: '0', - key: address, - })) + const count = useMemo(() => receiving.length + change.length, [receiving, change]) return ( @@ -99,9 +114,9 @@ const Addresses = (props: React.PropsWithoutRef) => { label: t(header.label), }))} items={[...receivingAddresses, ...changeAddresses]} - pageNo={pageNo} - pageSize={pageSize} - totalCount={totalCount} + pageNo={0} + pageSize={count} + totalCount={count} onPageChange={onPageChange} tableAttrs={{ bordered: false, diff --git a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts index d5abdbcd68..f564d42c74 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/hooks.ts +++ b/packages/neuron-ui/src/components/NetworkEditor/hooks.ts @@ -21,12 +21,16 @@ export const useNetworkEditor = ( ) => { const [name, setName] = useState(currentName) const [remote, setRemote] = useState(currentRemote) - - return { - initiate: ({ name: initName, remote: initRemote }: { name: string; remote: string }) => { + const initialize = useCallback( + ({ name: initName, remote: initRemote }: { name: string; remote: string }) => { setName(initName) setRemote(initRemote) }, + [setName, setRemote], + ) + + return { + initialize, name: { value: name, onChange: (e: React.FormEvent>) => { @@ -48,12 +52,12 @@ type DispatchType = React.Dispatch<{ payload?: any }> -export const useInitiate = (id: string, networks: Network[], editor: EditorType, dispatch: DispatchType) => { +export const useInitialize = (id: string, networks: Network[], initialize: Function, dispatch: DispatchType) => { useEffect(() => { if (id !== 'new') { const network = networks.find(n => n.id === id) if (network) { - editor.initiate(network) + initialize(network) } else { dispatch({ type: MainActions.ErrorMessage, @@ -71,7 +75,7 @@ export const useInitiate = (id: string, networks: Network[], editor: EditorType, }, }) } - }, [dispatch, id]) + }, [dispatch, id, initialize, networks]) } export const useInputs = (editor: EditorType) => { @@ -119,7 +123,7 @@ export const useHandleSubmit = ( }, [id, name, remote, networks, dispatch]) export default { - useInitiate, + useInitialize, useInputs, useNetworkEditor, useIsInputsValid, diff --git a/packages/neuron-ui/src/components/NetworkEditor/index.tsx b/packages/neuron-ui/src/components/NetworkEditor/index.tsx index a279958116..fbb6fdcb31 100644 --- a/packages/neuron-ui/src/components/NetworkEditor/index.tsx +++ b/packages/neuron-ui/src/components/NetworkEditor/index.tsx @@ -7,7 +7,7 @@ import { ContentProps } from 'containers/MainContent' import InlineInput, { InputProps } from 'widgets/InlineInput' import { useNeuronWallet } from 'utils/hooks' -import { useInitiate, useInputs, useNetworkEditor, useIsInputsValid, useHandleSubmit } from './hooks' +import { useInitialize, useInputs, useNetworkEditor, useIsInputsValid, useHandleSubmit } from './hooks' export interface RawNetwork { name: string @@ -29,7 +29,7 @@ const NetworkEditor = (props: React.PropsWithoutRef network.id === id) diff --git a/packages/neuron-ui/src/components/Router/index.tsx b/packages/neuron-ui/src/components/Router/index.tsx index 62ce4db7d2..cf7b820978 100644 --- a/packages/neuron-ui/src/components/Router/index.tsx +++ b/packages/neuron-ui/src/components/Router/index.tsx @@ -73,6 +73,7 @@ export const mainContents: CustomRoute[] = [ { name: `Send`, path: Routes.Send, + params: `/:address?`, exact: false, component: Send, }, diff --git a/packages/neuron-ui/src/components/Transfer/hooks.ts b/packages/neuron-ui/src/components/Transfer/hooks.ts new file mode 100644 index 0000000000..b7ab34d230 --- /dev/null +++ b/packages/neuron-ui/src/components/Transfer/hooks.ts @@ -0,0 +1,130 @@ +import React, { useCallback, useEffect } from 'react' +import { History } from 'history' +import UILayer, { TransferItem } from 'services/UILayer' +import { MainActions, actionCreators } from 'containers/MainContent/reducer' +import { Channel, Routes, CapacityUnit } from 'utils/const' +import initState from 'containers/MainContent/state' + +export const useUpdateTransferItem = (dispatch: React.Dispatch) => + useCallback( + (field: string) => (idx: number) => (value: string) => { + dispatch({ + type: MainActions.UpdateItemInTransfer, + payload: { + idx, + item: { + [field]: value, + }, + }, + }) + }, + [dispatch], + ) + +export const useOnSubmit = (dispatch: React.Dispatch) => + useCallback( + (items: TransferItem[]) => () => { + dispatch(actionCreators.submitTransfer(items)) + }, + [dispatch], + ) + +export const useOnPasswordChange = (dispatch: React.Dispatch) => + useCallback( + (e: React.SyntheticEvent) => { + dispatch({ + type: MainActions.UpdatePassword, + payload: e.currentTarget.value, + }) + }, + [dispatch], + ) + +export const useOnConfirm = (dispatch: React.Dispatch) => + useCallback( + (items: TransferItem[], pwd: string) => () => { + dispatch({ + type: MainActions.SetDialog, + payload: { + open: false, + }, + }) + dispatch({ + type: MainActions.UpdatePassword, + payload: '', + }) + setTimeout(() => { + dispatch( + actionCreators.confirmTransfer({ + items, + password: pwd, + }), + ) + }, 10) + }, + [dispatch], + ) + +export const useOnItemChange = (updateTransferItem: Function) => (field: string, idx: number) => ( + e: React.FormEvent<{ value: string }>, +) => { + updateTransferItem(field)(idx)(e.currentTarget.value) +} + +export const useDropdownItems = (updateTransferItem: Function) => + useCallback( + (idx: number) => + Object.values(CapacityUnit) + .filter(unit => typeof unit === 'string') + .map((unit: string) => ({ + label: unit.toUpperCase(), + key: unit, + onClick: () => updateTransferItem('unit')(idx)(unit), + })), + [updateTransferItem], + ) + +export const useInitialize = ( + address: string, + dispatch: React.Dispatch, + history: History, + updateTransferItem: Function, +) => + useEffect(() => { + if (address) { + updateTransferItem('address')(0)(address) + } + UILayer.on(Channel.SendCapacity, (_e: Event, args: ChannelResponse) => { + if (args.status) { + history.push(`${Routes.Transaction}/${args.result}`) + } else { + dispatch({ + type: MainActions.UpdateTransfer, + payload: { + submitting: false, + }, + }) + dispatch({ + type: MainActions.ErrorMessage, + payload: { transfer: args.msg }, + }) + } + }) + return () => { + UILayer.removeAllListeners(Channel.SendCapacity) + dispatch({ + type: MainActions.UpdateTransfer, + payload: initState.transfer, + }) + } + }, [address, dispatch, history, updateTransferItem]) + +export default { + useUpdateTransferItem, + useOnSubmit, + useOnPasswordChange, + useOnConfirm, + useOnItemChange, + useDropdownItems, + useInitialize, +} diff --git a/packages/neuron-ui/src/components/Transfer/index.tsx b/packages/neuron-ui/src/components/Transfer/index.tsx index 1f3aeada46..64bb058440 100644 --- a/packages/neuron-ui/src/components/Transfer/index.tsx +++ b/packages/neuron-ui/src/components/Transfer/index.tsx @@ -1,131 +1,58 @@ -import React, { useCallback, useEffect } from 'react' +import React from 'react' import { RouteComponentProps } from 'react-router-dom' import { Container, Row, Col, Card, Form, Button, Alert, InputGroup } from 'react-bootstrap' import { useTranslation } from 'react-i18next' +import TransferItemList from 'components/TransferItemList' +import TransferConfirm from 'components/TransferConfirm' + import Dialog from 'widgets/Dialog' import QRScanner from 'widgets/QRScanner' import InlineInputWithDropdown from 'widgets/InlineInput/InlineInputWithDropdown' import { Spinner } from 'widgets/Loading' import { ContentProps } from 'containers/MainContent' -import { MainActions, actionCreators } from 'containers/MainContent/reducer' -import initState from 'containers/MainContent/state' -import UILayer, { TransferItem } from 'services/UILayer' -import { CapacityUnit, PlaceHolders, Channel, Routes } from 'utils/const' -import TransferItemList from '../TransferItemList' -import TransferConfirm from '../TransferConfirm' - -const Transfer = (props: React.PropsWithoutRef) => { +import { useOnDialogCancel } from 'containers/MainContent/hooks' +import { PlaceHolders } from 'utils/const' + +import { + useUpdateTransferItem, + useOnSubmit, + useOnPasswordChange, + useOnConfirm, + useOnItemChange, + useDropdownItems, + useInitialize, +} from './hooks' + +const Transfer = ({ + transfer, + dispatch, + password, + dialog, + errorMsgs, + history, + match: { + params: { address }, + }, +}: React.PropsWithoutRef>) => { const { t } = useTranslation() - const { transfer, dispatch, password, dialog, errorMsgs, history } = props - - useEffect(() => { - UILayer.on(Channel.SendCapacity, (_e: Event, args: ChannelResponse) => { - if (args.status) { - history.push(`${Routes.Transaction}/${args.result}`) - } else { - dispatch({ - type: MainActions.UpdateTransfer, - payload: { - submitting: false, - }, - }) - dispatch({ - type: MainActions.ErrorMessage, - payload: { transfer: args.msg }, - }) - } - }) - return () => { - UILayer.removeAllListeners(Channel.SendCapacity) - dispatch({ - type: MainActions.UpdateTransfer, - payload: initState.transfer, - }) - } - }, [dispatch, history]) - - const updateTransferItem = useCallback( - (field: string) => (idx: number) => (value: string) => { - dispatch({ - type: MainActions.UpdateItemInTransfer, - payload: { - idx, - item: { - [field]: value, - }, - }, - }) - }, - [dispatch], - ) - const onSubmit = useCallback( - (items: TransferItem[]) => () => { - dispatch(actionCreators.submitTransfer(items)) - }, - [dispatch], - ) + const updateTransferItem = useUpdateTransferItem(dispatch) - const onPswChange = useCallback( - (e: React.SyntheticEvent) => { - dispatch({ - type: MainActions.UpdatePassword, - payload: e.currentTarget.value, - }) - }, - [dispatch], - ) + const onSubmit = useOnSubmit(dispatch) - const onConfirm = useCallback( - (items: TransferItem[], pwd: string) => () => { - dispatch({ - type: MainActions.SetDialog, - payload: { - open: false, - }, - }) - dispatch({ - type: MainActions.UpdatePassword, - payload: '', - }) - setTimeout(() => { - dispatch( - actionCreators.confirmTransfer({ - items, - password: pwd, - }), - ) - }, 10) - }, - [dispatch], - ) + const onPasswordChange = useOnPasswordChange(dispatch) - const onCancel = useCallback(() => { - dispatch({ - type: MainActions.SetDialog, - payload: { - open: false, - }, - }) - }, [dispatch]) - - const onItemChange = (field: string, idx: number) => (e: React.FormEvent<{ value: string }>) => { - updateTransferItem(field)(idx)(e.currentTarget.value) - } - - const dropdownItems = useCallback( - (idx: number) => - Object.values(CapacityUnit) - .filter(unit => typeof unit === 'string') - .map((unit: string) => ({ - label: unit.toUpperCase(), - key: unit, - onClick: () => updateTransferItem('unit')(idx)(unit), - })), - [updateTransferItem], - ) + const onConfirm = useOnConfirm(dispatch) + + const onCancel = useOnDialogCancel(dispatch) + + const onItemChange = useOnItemChange(updateTransferItem) + + const dropdownItems = useDropdownItems(updateTransferItem) + + useInitialize(address, dispatch, history, updateTransferItem) const disabled = transfer.submitting && !errorMsgs.transfer @@ -195,7 +122,7 @@ const Transfer = (props: React.PropsWithoutRef} password={password} - onChange={onPswChange} + onChange={onPasswordChange} onSubmit={onConfirm(transfer.items, password)} onCancel={onCancel} /> diff --git a/packages/neuron-ui/src/components/WalletEditor/hooks.ts b/packages/neuron-ui/src/components/WalletEditor/hooks.ts index fbe82a5117..9a1b2a653a 100644 --- a/packages/neuron-ui/src/components/WalletEditor/hooks.ts +++ b/packages/neuron-ui/src/components/WalletEditor/hooks.ts @@ -7,10 +7,14 @@ export const useWalletEditor = () => { const [password, setPassword] = useState('') const [newPassword, setNewPassword] = useState('') const [confirmNewPassword, setConfirmNewPassword] = useState('') - return { - initiate: (initName: string = '') => { + const initialize = useCallback( + (initName: string = '') => { setName(initName) }, + [setName], + ) + return { + initialize, name: { value: name, onChange: (e: React.FormEvent>) => setName(e.currentTarget.value), @@ -52,7 +56,7 @@ export const useInputs = ({ name, newPassword, confirmNewPassword }: ReturnType< inputType: 'password', }, ], - [name.value, newPassword.value, confirmNewPassword.value], + [name, newPassword, confirmNewPassword], ) } diff --git a/packages/neuron-ui/src/components/WalletEditor/index.tsx b/packages/neuron-ui/src/components/WalletEditor/index.tsx index 4596452a43..9440f82945 100644 --- a/packages/neuron-ui/src/components/WalletEditor/index.tsx +++ b/packages/neuron-ui/src/components/WalletEditor/index.tsx @@ -4,6 +4,7 @@ import { Card, Form, Button, Col, Row } from 'react-bootstrap' import { useTranslation } from 'react-i18next' import { ContentProps } from 'containers/MainContent' +import { useOnDialogCancel } from 'containers/MainContent/hooks' import InlineInput, { InputProps } from 'widgets/InlineInput' import { MainActions, actionCreators } from 'containers/MainContent/reducer' import { useNeuronWallet } from 'utils/hooks' @@ -11,11 +12,13 @@ import Dialog from 'widgets/Dialog' import { useWalletEditor, useInputs, useAreParamsValid, useToggleDialog } from './hooks' -export default (props: React.PropsWithoutRef>) => { - const { match, dialog, dispatch } = props - const { +export default ({ + dialog, + dispatch, + match: { params: { id }, - } = match + }, +}: React.PropsWithoutRef>) => { const [t] = useTranslation() const { settings: { wallets }, @@ -29,10 +32,11 @@ export default (props: React.PropsWithoutRef { - editor.initiate(wallet.name) - }, [id]) + initialize(wallet.name) + }, [id, initialize, wallet.name]) const inputs: InputProps[] = useInputs(editor) const areParamsValid = useAreParamsValid(editor.name.value, editor.newPassword.value, editor.confirmNewPassword.value) @@ -57,7 +61,9 @@ export default (props: React.PropsWithoutRef @@ -72,12 +78,7 @@ export default (props: React.PropsWithoutRef - { - toggleDialog(false) - }} - > + ) => { e.preventDefault() @@ -97,7 +98,7 @@ export default (props: React.PropsWithoutRef {t('common.confirm')} - diff --git a/packages/neuron-ui/src/components/WalletWizard/index.tsx b/packages/neuron-ui/src/components/WalletWizard/index.tsx index 43146b1fed..0b6066455e 100644 --- a/packages/neuron-ui/src/components/WalletWizard/index.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/index.tsx @@ -85,7 +85,7 @@ const Mnemonic = ({ // TODO: Better Error Handle .catch(err => console.error(err)) } - }, [dispatch, helpersCall]) + }, [dispatch, type]) const onChange = useCallback( e => { @@ -102,7 +102,7 @@ const Mnemonic = ({ } else { history.push(`${rootPath}${WalletWizardPath.Submission}/${type === MnemonicAction.Verify ? 'create' : 'import'}`) } - }, [isCreate]) + }, [isCreate, history, rootPath, type]) return ( diff --git a/packages/neuron-ui/src/containers/MainContent/actionCreators/wallets.ts b/packages/neuron-ui/src/containers/MainContent/actionCreators/wallets.ts index 7651ca7f5d..109b874b8b 100644 --- a/packages/neuron-ui/src/containers/MainContent/actionCreators/wallets.ts +++ b/packages/neuron-ui/src/containers/MainContent/actionCreators/wallets.ts @@ -1,4 +1,7 @@ -import { initState, MainActions } from '../reducer' +import { + // initState, + MainActions, +} from '../reducer' import { walletsCall } from '../../../services/UILayer' export default { @@ -34,34 +37,12 @@ export default { payload: id, } }, - importMnemonic: (params: { name: string; password: string; mnemonic: string }) => { - walletsCall.importMnemonic(params) - return { - type: MainActions.Wallet, - } - }, - importKeystore: (params: { name: string; keystore: string; password: string }) => { - walletsCall.importKeystore(params) - return { - type: MainActions.Wallet, - } - }, updateWallet: (params: { id: string; password: string; newPassword?: string; name?: string }) => { walletsCall.update(params) return { type: MainActions.Wallet, } }, - importWallet: (isKeystore: boolean, params: typeof initState.tempWallet) => { - if (isKeystore) { - walletsCall.importKeystore(params) - } else { - walletsCall.importMnemonic(params) - } - return { - type: MainActions.Wallet, - } - }, exportWallet: (id: string) => { walletsCall.export(id) return { diff --git a/packages/neuron-ui/src/containers/MainContent/hooks.ts b/packages/neuron-ui/src/containers/MainContent/hooks.ts new file mode 100644 index 0000000000..c4013f0cd1 --- /dev/null +++ b/packages/neuron-ui/src/containers/MainContent/hooks.ts @@ -0,0 +1,15 @@ +import React, { useCallback } from 'react' +import { MainActions } from './reducer' + +export const useOnDialogCancel = (dispatch: React.Dispatch) => + useCallback(() => { + dispatch({ + type: MainActions.SetDialog, + payload: { + open: false, + }, + }) + }, [dispatch]) +export default { + useOnDialogCancel, +} diff --git a/packages/neuron-ui/src/containers/MainContent/reducer.ts b/packages/neuron-ui/src/containers/MainContent/reducer.ts index aa34802ecf..b9cc3c9dfb 100644 --- a/packages/neuron-ui/src/containers/MainContent/reducer.ts +++ b/packages/neuron-ui/src/containers/MainContent/reducer.ts @@ -12,15 +12,6 @@ export type MainDispatch = React.Dispatch<{ type: MainActions; payload?: any }> export type InitState = typeof initState export const reducer = (state: typeof initState, action: { type: MainActions; payload: any }) => { switch (action.type) { - case MainActions.UpdateMnemonic: { - return { - ...state, - mnemonic: { - ...state.mnemonic, - ...action.payload, - }, - } - } case MainActions.AddItemInTransfer: { return { ...state, diff --git a/packages/neuron-ui/src/containers/MainContent/state.ts b/packages/neuron-ui/src/containers/MainContent/state.ts index 8f0708a7e0..1e88f2acf5 100644 --- a/packages/neuron-ui/src/containers/MainContent/state.ts +++ b/packages/neuron-ui/src/containers/MainContent/state.ts @@ -1,23 +1,6 @@ import { CapacityUnit } from 'utils/const' export const initState = { - mnemonic: { - generated: '', - imported: '', - name: '', - password: '', - confirmPassword: '', - }, - tempWallet: { - name: '', - password: '', - mnemonic: '', - keystore: '', - }, - createWallet: { - name: '', - password: '', - }, transfer: { items: [ { diff --git a/packages/neuron-ui/src/containers/Providers/hooks.ts b/packages/neuron-ui/src/containers/Providers/hooks.ts new file mode 100644 index 0000000000..83a720717a --- /dev/null +++ b/packages/neuron-ui/src/containers/Providers/hooks.ts @@ -0,0 +1,243 @@ +import React, { useEffect } from 'react' +import { history } from 'components/Router' + +import UILayer, { NetworksMethod, TransactionsMethod, WalletsMethod } from 'services/UILayer' +import { Channel, ConnectStatus, Routes } from 'utils/const' +import { ProviderActions } from './reducer' + +export const useChannelListeners = (i18n: any, chain: any, dispatch: React.Dispatch) => + useEffect(() => { + UILayer.on( + Channel.Initiate, + ( + _e: Event, + args: ChannelResponse<{ + networks: any + activeNetworkId: string + wallets: any + activeWallet: any + locale: string + }>, + ) => { + if (args.status) { + const { locale, networks, activeNetworkId: networkId, wallets, activeWallet: wallet } = args.result + if (locale !== i18n.language) { + i18n.changeLanguage(locale) + } + if (networks.length) { + dispatch({ + type: ProviderActions.Initiate, + payload: { networks, networkId, wallet, wallets }, + }) + } + } else { + // TODO: better prompt + window.alert(i18n.t('messages.failed-to-initiate,-please-reopen-Neuron')) + window.close() + } + }, + ) + + UILayer.on(Channel.NavTo, (_e: Event, args: ChannelResponse<{ router: string }>) => { + history.push(args.result.router) + }) + + UILayer.on(Channel.GetBalance, (_e: Event, args: ChannelResponse) => { + if (args.status) { + dispatch({ + type: ProviderActions.Wallet, + payload: { balance: args.result }, + }) + } + }) + + UILayer.on(Channel.Transactions, (_e: Event, method: TransactionsMethod, args: ChannelResponse) => { + if (args.status) { + switch (method) { + case TransactionsMethod.GetAll: { + dispatch({ + type: ProviderActions.Chain, + payload: { transactions: { ...chain.transactions, ...args.result } }, + }) + break + } + case TransactionsMethod.Get: { + dispatch({ + type: ProviderActions.Chain, + payload: { transaction: { ...chain.transaction, ...args.result } }, + }) + break + } + default: { + break + } + } + } else { + // TODO: handle error + } + }) + + UILayer.on(Channel.Wallets, (_e: Event, method: WalletsMethod, args: ChannelResponse) => { + if (args.status) { + switch (method) { + case WalletsMethod.Create: + case WalletsMethod.ImportMnemonic: + case WalletsMethod.Update: { + let template = '' + if (method === WalletsMethod.Create) { + template = 'messages.wallet-created-successfully' + } else if (method === WalletsMethod.Update) { + template = 'messages.wallet-updated-successfully' + } else { + template = 'messages.wallet-imported-successfully' + } + const content = i18n.t(template, { name: args.result.name }) + const time = new Date().getTime() + dispatch({ + type: ProviderActions.AddMessage, + payload: { + category: 'success', + title: 'Wallet', + content, + actions: [], + time, + dismiss: () => { + dispatch({ + type: ProviderActions.DismissMessage, + payload: time, + }) + }, + }, + }) + // TODO: so imperative, better refactor + history.push(Routes.SettingsWallets) + break + } + case WalletsMethod.GetAll: { + dispatch({ + type: ProviderActions.Settings, + payload: { wallets: args.result }, + }) + break + } + case WalletsMethod.GetActive: { + dispatch({ + type: ProviderActions.Wallet, + payload: args.result, + }) + break + } + case WalletsMethod.Delete: { + dispatch({ + type: ProviderActions.Settings, + payload: { wallets: args.result.allWallets }, + }) + dispatch({ + type: ProviderActions.Wallet, + payload: args.result.activeWallet, + }) + break + } + default: { + break + } + } + } else { + const time = new Date().getTime() + if (method === WalletsMethod.GetActive) { + // don't show this error in wizard view + return + } + + dispatch({ + type: ProviderActions.AddMessage, + payload: { + category: 'danger', + title: 'Wallet', + content: args.msg, + time, + actions: [], + dismiss: () => { + dispatch({ + type: ProviderActions.DismissMessage, + payload: time, + }) + }, + }, + }) + } + }) + + UILayer.on(Channel.Networks, (_e: Event, method: NetworksMethod, args: ChannelResponse) => { + if (args.status) { + switch (method) { + case NetworksMethod.GetAll: { + dispatch({ + type: ProviderActions.Settings, + payload: { networks: args.result }, + }) + break + } + case NetworksMethod.ActiveId: { + dispatch({ + type: ProviderActions.Chain, + payload: { networkId: args.result }, + }) + break + } + case NetworksMethod.Create: + case NetworksMethod.Update: { + // TODO: so imperative, better refactor + history.push(Routes.SettingsNetworks) + break + } + case NetworksMethod.Activate: { + dispatch({ + type: ProviderActions.Chain, + payload: { network: args.result }, + }) + break + } + case NetworksMethod.Status: { + dispatch({ + type: ProviderActions.Chain, + payload: { + connectStatus: args.result ? ConnectStatus.Online : ConnectStatus.Offline, + }, + }) + break + } + default: { + break + } + } + } else { + const time = new Date().getTime() + dispatch({ + type: ProviderActions.AddMessage, + payload: { + category: 'danger', + title: 'Networks', + content: args.msg, + time, + actions: [ + { + label: 'view', + action: Routes.SettingsNetworks, + }, + ], + dismiss: () => { + dispatch({ + type: ProviderActions.DismissMessage, + payload: time, + }) + }, + }, + }) + } + }) + }, [i18n, chain, dispatch]) + +export default { + useChannelListeners, +} diff --git a/packages/neuron-ui/src/containers/Providers/index.tsx b/packages/neuron-ui/src/containers/Providers/index.tsx index 36292d1f29..f9b4b71c72 100644 --- a/packages/neuron-ui/src/containers/Providers/index.tsx +++ b/packages/neuron-ui/src/containers/Providers/index.tsx @@ -1,11 +1,8 @@ -import React, { useEffect, useReducer } from 'react' +import React, { useReducer } from 'react' import { useTranslation } from 'react-i18next' -import { history } from 'components/Router' import NeuronWalletContext from 'contexts/NeuronWallet' - -import UILayer, { NetworksMethod, TransactionsMethod, WalletsMethod } from 'services/UILayer' -import { Channel, ConnectStatus, Routes } from 'utils/const' -import { initProviders, ProviderActions, ProviderDispatch, reducer } from './reducer' +import { initProviders, ProviderDispatch, reducer } from './reducer' +import { useChannelListeners } from './hooks' const withProviders = (Comp: React.ComponentType<{ providerDispatch: ProviderDispatch }>) => ( props: React.Props, @@ -13,237 +10,8 @@ const withProviders = (Comp: React.ComponentType<{ providerDispatch: ProviderDis const [providers, dispatch] = useReducer(reducer, initProviders) const { chain } = providers const [, i18n] = useTranslation() - useEffect(() => { - UILayer.on( - Channel.Initiate, - ( - _e: Event, - args: ChannelResponse<{ - networks: any - activeNetworkId: string - wallets: any - activeWallet: any - locale: string - }>, - ) => { - if (args.status) { - const { locale, networks, activeNetworkId: networkId, wallets, activeWallet: wallet } = args.result - if (locale !== i18n.language) { - i18n.changeLanguage(locale) - } - if (networks.length) { - dispatch({ - type: ProviderActions.Initiate, - payload: { networks, networkId, wallet, wallets }, - }) - } - } else { - // TODO: better prompt - window.alert(i18n.t('messages.failed-to-initiate,-please-reopen-Neuron')) - window.close() - } - }, - ) - - UILayer.on(Channel.NavTo, (_e: Event, args: ChannelResponse<{ router: string }>) => { - history.push(args.result.router) - }) - - UILayer.on(Channel.GetBalance, (_e: Event, args: ChannelResponse) => { - if (args.status) { - dispatch({ - type: ProviderActions.Wallet, - payload: { balance: args.result }, - }) - } - }) - - UILayer.on(Channel.Transactions, (_e: Event, method: TransactionsMethod, args: ChannelResponse) => { - if (args.status) { - switch (method) { - case TransactionsMethod.GetAll: { - dispatch({ - type: ProviderActions.Chain, - payload: { transactions: { ...chain.transactions, ...args.result } }, - }) - break - } - case TransactionsMethod.Get: { - dispatch({ - type: ProviderActions.Chain, - payload: { transaction: { ...chain.transaction, ...args.result } }, - }) - break - } - default: { - break - } - } - } else { - // TODO: handle error - } - }) - - UILayer.on(Channel.Wallets, (_e: Event, method: WalletsMethod, args: ChannelResponse) => { - if (args.status) { - switch (method) { - case WalletsMethod.Create: - case WalletsMethod.ImportMnemonic: - case WalletsMethod.Update: { - let template = '' - if (method === WalletsMethod.Create) { - template = 'messages.wallet-created-successfully' - } else if (method === WalletsMethod.Update) { - template = 'messages.wallet-updated-successfully' - } else { - template = 'messages.wallet-imported-successfully' - } - const content = i18n.t(template, { name: args.result.name }) - const time = new Date().getTime() - dispatch({ - type: ProviderActions.AddMessage, - payload: { - category: 'success', - title: 'Wallet', - content, - actions: [], - time, - dismiss: () => { - dispatch({ - type: ProviderActions.DismissMessage, - payload: time, - }) - }, - }, - }) - // TODO: so imperative, better refactor - history.push(Routes.SettingsWallets) - break - } - case WalletsMethod.GetAll: { - dispatch({ - type: ProviderActions.Settings, - payload: { wallets: args.result }, - }) - break - } - case WalletsMethod.GetActive: { - dispatch({ - type: ProviderActions.Wallet, - payload: args.result, - }) - break - } - case WalletsMethod.Delete: { - dispatch({ - type: ProviderActions.Settings, - payload: { wallets: args.result.allWallets }, - }) - dispatch({ - type: ProviderActions.Wallet, - payload: args.result.activeWallet, - }) - break - } - default: { - break - } - } - } else { - const time = new Date().getTime() - if (method === WalletsMethod.GetActive) { - // don't show this error in wizard view - return - } - - dispatch({ - type: ProviderActions.AddMessage, - payload: { - category: 'danger', - title: 'Wallet', - content: args.msg, - time, - actions: [], - dismiss: () => { - dispatch({ - type: ProviderActions.DismissMessage, - payload: time, - }) - }, - }, - }) - } - }) - UILayer.on(Channel.Networks, (_e: Event, method: NetworksMethod, args: ChannelResponse) => { - if (args.status) { - switch (method) { - case NetworksMethod.GetAll: { - dispatch({ - type: ProviderActions.Settings, - payload: { networks: args.result }, - }) - break - } - case NetworksMethod.ActiveId: { - dispatch({ - type: ProviderActions.Chain, - payload: { networkId: args.result }, - }) - break - } - case NetworksMethod.Create: - case NetworksMethod.Update: { - // TODO: so imperative, better refactor - history.push(Routes.SettingsNetworks) - break - } - case NetworksMethod.Activate: { - dispatch({ - type: ProviderActions.Chain, - payload: { network: args.result }, - }) - break - } - case NetworksMethod.Status: { - dispatch({ - type: ProviderActions.Chain, - payload: { - connectStatus: args.result ? ConnectStatus.Online : ConnectStatus.Offline, - }, - }) - break - } - default: { - break - } - } - } else { - const time = new Date().getTime() - dispatch({ - type: ProviderActions.AddMessage, - payload: { - category: 'danger', - title: 'Networks', - content: args.msg, - time, - actions: [ - { - label: 'view', - action: Routes.SettingsNetworks, - }, - ], - dismiss: () => { - dispatch({ - type: ProviderActions.DismissMessage, - payload: time, - }) - }, - }, - }) - } - }) - }, [i18n, chain]) + useChannelListeners(i18n, chain, dispatch) return ( diff --git a/packages/neuron-ui/src/widgets/QRScanner/index.tsx b/packages/neuron-ui/src/widgets/QRScanner/index.tsx index 3ec699d866..1544657290 100644 --- a/packages/neuron-ui/src/widgets/QRScanner/index.tsx +++ b/packages/neuron-ui/src/widgets/QRScanner/index.tsx @@ -15,6 +15,15 @@ interface QRScannerProps { styles?: { [index: string]: any } } +const stopScan = (v: any) => { + if (v && v.srcObject) { + const track = v.srcObject.getTracks()[0] + if (track) { + track.stop() + } + } +} + const QRScanner = ({ title, label, onConfirm, styles }: QRScannerProps) => { const [open, setOpen] = useState(false) const [data, setData] = useState('') @@ -62,15 +71,6 @@ const QRScanner = ({ title, label, onConfirm, styles }: QRScannerProps) => { }) }, [video]) - const stopScan = (v: any) => { - if (v && v.srcObject) { - const track = v.srcObject.getTracks()[0] - if (track) { - track.stop() - } - } - } - useEffect(() => { if (open) { scan() @@ -78,7 +78,7 @@ const QRScanner = ({ title, label, onConfirm, styles }: QRScannerProps) => { stopScan(video) } return () => stopScan(video) - }, [video, open, scan, stopScan]) + }, [video, open, scan]) return ( <> diff --git a/packages/neuron-wallet/src/utils/store.ts b/packages/neuron-wallet/src/utils/store.ts index 25d55f6e32..ad10b538dc 100644 --- a/packages/neuron-wallet/src/utils/store.ts +++ b/packages/neuron-wallet/src/utils/store.ts @@ -43,7 +43,7 @@ class Store extends EventEmitter { } resolve(content) } catch (parseErr) { - console.error('\x1b[33m%s\x1b[0m', `Failed to parse data, backup to ${this.location}.brk and initiate data`) + console.error('\x1b[33m%s\x1b[0m', `Failed to parse data, backup to ${this.location}.brk and initialize data`) this.backup(data) this.init() reject(parseErr)