Account.tsx 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // Copyright 2017-2019 @polkadot/app-staking authors & contributors
  2. // This software may be modified and distributed under the terms
  3. // of the Apache-2.0 license. See the LICENSE file for details.
  4. import { ActionStatus } from '@polkadot/react-components/Status/types';
  5. import { I18nProps } from '@polkadot/react-components/types';
  6. import React, { useState, useEffect } from 'react';
  7. import { Popup } from 'semantic-ui-react';
  8. import styled from 'styled-components';
  9. import { AddressCard, AddressInfo, Button, ChainLock, Forget, Menu } from '@polkadot/react-components';
  10. import keyring from '@polkadot/ui-keyring';
  11. import Backup from './modals/Backup';
  12. import ChangePass from './modals/ChangePass';
  13. import Derive from './modals/Derive';
  14. import Transfer from './modals/Transfer';
  15. import translate from './translate';
  16. interface Props extends I18nProps {
  17. address: string;
  18. className?: string;
  19. }
  20. function Account ({ address, className, t }: Props): React.ReactElement<Props> {
  21. const [genesisHash, setGenesisHash] = useState<string | null>(null);
  22. const [isBackupOpen, setIsBackupOpen] = useState(false);
  23. const [{ isDevelopment, isEditable, isExternal }, setFlags] = useState({ isDevelopment: false, isEditable: false, isExternal: false });
  24. const [isDeriveOpen, setIsDeriveOpen] = useState(false);
  25. const [isForgetOpen, setIsForgetOpen] = useState(false);
  26. const [isPasswordOpen, setIsPasswordOpen] = useState(false);
  27. const [isSettingPopupOpen, setIsSettingPopupOpen] = useState(false);
  28. const [isTransferOpen, setIsTransferOpen] = useState(false);
  29. useEffect((): void => {
  30. const account = keyring.getAccount(address);
  31. setGenesisHash((account && account.meta.genesisHash) || null);
  32. setFlags({
  33. isDevelopment: (account && account.meta.isTesting) || false,
  34. isEditable: (account && !(account.meta.isInjected || account.meta.isHardware)) || false,
  35. isExternal: (account && account.meta.isExternal) || false
  36. });
  37. }, [address]);
  38. const _toggleBackup = (): void => setIsBackupOpen(!isBackupOpen);
  39. const _toggleDerive = (): void => setIsDeriveOpen(!isDeriveOpen);
  40. const _toggleForget = (): void => setIsForgetOpen(!isForgetOpen);
  41. const _togglePass = (): void => setIsPasswordOpen(!isPasswordOpen);
  42. const _toggleTransfer = (): void => setIsTransferOpen(!isTransferOpen);
  43. const _toggleSettingPopup = (): void => setIsSettingPopupOpen(!isSettingPopupOpen);
  44. const _onForget = (): void => {
  45. if (!address) {
  46. return;
  47. }
  48. const status: Partial<ActionStatus> = {
  49. account: address,
  50. action: 'forget'
  51. };
  52. try {
  53. keyring.forgetAccount(address);
  54. status.status = 'success';
  55. status.message = t('account forgotten');
  56. } catch (error) {
  57. status.status = 'error';
  58. status.message = error.message;
  59. }
  60. };
  61. const _onGenesisChange = (genesisHash: string | null): void => {
  62. const account = keyring.getPair(address);
  63. account && keyring.saveAccountMeta(account, { ...account.meta, genesisHash });
  64. setGenesisHash(genesisHash);
  65. };
  66. // FIXME It is a bit heavy-handled switching of being editable here completely
  67. // (and removing the tags, however the keyring cannot save these)
  68. return (
  69. <AddressCard
  70. buttons={
  71. <div className='accounts--Account-buttons buttons'>
  72. <div className='actions'>
  73. {isEditable && !isDevelopment && (
  74. <Button
  75. isNegative
  76. onClick={_toggleForget}
  77. icon='trash'
  78. size='small'
  79. tooltip={t('Forget this account')}
  80. />
  81. )}
  82. {isEditable && !isExternal && !isDevelopment && (
  83. <>
  84. <Button
  85. icon='cloud download'
  86. isPrimary
  87. onClick={_toggleBackup}
  88. size='small'
  89. tooltip={t('Create a backup file for this account')}
  90. />
  91. <Button
  92. icon='key'
  93. isPrimary
  94. onClick={_togglePass}
  95. size='small'
  96. tooltip={t("Change this account's password")}
  97. />
  98. </>
  99. )}
  100. <Button
  101. icon='paper plane'
  102. isPrimary
  103. label={t('send')}
  104. onClick={_toggleTransfer}
  105. size='small'
  106. tooltip={t('Send funds from this account')}
  107. />
  108. {isEditable && !isExternal && (
  109. <Popup
  110. onClose={_toggleSettingPopup}
  111. open={isSettingPopupOpen}
  112. position='bottom left'
  113. trigger={
  114. <Button
  115. icon='setting'
  116. onClick={_toggleSettingPopup}
  117. size='small'
  118. />
  119. }
  120. >
  121. <Menu
  122. vertical
  123. text
  124. onClick={_toggleSettingPopup}
  125. >
  126. <Menu.Item onClick={_toggleDerive}>
  127. {t('Derive account from source')}
  128. </Menu.Item>
  129. <Menu.Item disabled>
  130. {t('Change on-chain nickname')}
  131. </Menu.Item>
  132. </Menu>
  133. </Popup>
  134. )}
  135. </div>
  136. {isEditable && !isExternal && (
  137. <div className='others'>
  138. <ChainLock
  139. genesisHash={genesisHash}
  140. onChange={_onGenesisChange}
  141. />
  142. </div>
  143. )}
  144. </div>
  145. }
  146. className={className}
  147. isEditable={isEditable}
  148. type='account'
  149. value={address}
  150. withExplorer
  151. withIndexOrAddress={false}
  152. withTags
  153. >
  154. {address && (
  155. <>
  156. {isBackupOpen && (
  157. <Backup
  158. address={address}
  159. key='modal-backup-account'
  160. onClose={_toggleBackup}
  161. />
  162. )}
  163. {isDeriveOpen && (
  164. <Derive
  165. from={address}
  166. key='modal-derive-account'
  167. onClose={_toggleDerive}
  168. />
  169. )}
  170. {isForgetOpen && (
  171. <Forget
  172. address={address}
  173. onForget={_onForget}
  174. key='modal-forget-account'
  175. onClose={_toggleForget}
  176. />
  177. )}
  178. {isPasswordOpen && (
  179. <ChangePass
  180. address={address}
  181. key='modal-change-pass'
  182. onClose={_togglePass}
  183. />
  184. )}
  185. {isTransferOpen && (
  186. <Transfer
  187. key='modal-transfer'
  188. onClose={_toggleTransfer}
  189. senderId={address}
  190. />
  191. )}
  192. </>
  193. )}
  194. <AddressInfo
  195. address={address}
  196. withBalance
  197. withExtended
  198. />
  199. </AddressCard>
  200. );
  201. }
  202. export default translate(
  203. styled(Account)`
  204. .accounts--Account-buttons {
  205. text-align: right;
  206. .others {
  207. margin-right: 0.125rem;
  208. margin-top: 0.25rem;
  209. }
  210. }
  211. `
  212. );