Changeset View
Changeset View
Standalone View
Standalone View
cashtab/src/components/Wallets/index.tsx
| // Copyright (c) 2024 The Bitcoin developers | // Copyright (c) 2024 The Bitcoin developers | ||||
| // Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
| // file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
| import React, { useState, useContext, useEffect } from 'react'; | import React, { useState, useContext, useEffect } from 'react'; | ||||
| import { WalletContext, isWalletContextLoaded } from 'wallet/context'; | import { WalletContext, isWalletContextLoaded } from 'wallet/context'; | ||||
| import { | import { | ||||
| TrashcanIcon, | TrashcanIcon, | ||||
| EditIcon, | EditIcon, | ||||
| AddContactIcon, | AddContactIcon, | ||||
| BankIcon, | |||||
| } from 'components/Common/CustomIcons'; | } from 'components/Common/CustomIcons'; | ||||
| import Modal from 'components/Common/Modal'; | import Modal from 'components/Common/Modal'; | ||||
| import { ModalInput, ModalTextArea } from 'components/Common/Inputs'; | import { ModalInput, ModalTextArea } from 'components/Common/Inputs'; | ||||
| import { toast } from 'react-toastify'; | import { toast } from 'react-toastify'; | ||||
| import PrimaryButton, { | import PrimaryButton, { | ||||
| SecondaryButton, | SecondaryButton, | ||||
| IconButton, | IconButton, | ||||
| CopyIconButton, | CopyIconButton, | ||||
| } from 'components/Common/Buttons'; | } from 'components/Common/Buttons'; | ||||
| import { | import { | ||||
| WalletsList, | WalletsList, | ||||
| WalletsPanel, | WalletsPanel, | ||||
| Wallet, | Wallet, | ||||
| WalletRow, | WalletRow, | ||||
| ActionsRow, | WalletLeftColumn, | ||||
| ActiveWalletName, | |||||
| WalletName, | WalletName, | ||||
| ButtonPanel, | |||||
| SvgButtonPanel, | SvgButtonPanel, | ||||
| ActivateButton, | ActivateButton, | ||||
| AddressShareModal, | AddressShareModal, | ||||
| WalletAddressRow, | WalletAddressRow, | ||||
| WalletInfo, | WalletInfo, | ||||
| WalletNameText, | WalletNameText, | ||||
| WalletAddress, | WalletAddress, | ||||
| CopyButton, | CopyButton, | ||||
| ActiveIndicator, | ActiveIndicator, | ||||
| } from 'components/Wallets/styles'; | } from 'components/Wallets/styles'; | ||||
| import { getWalletNameError, validateMnemonic } from 'validation'; | import { getWalletNameError, validateMnemonic } from 'validation'; | ||||
| import { | import { | ||||
| createCashtabWallet, | createCashtabWallet, | ||||
| generateMnemonic, | generateMnemonic, | ||||
| StoredCashtabWallet, | StoredCashtabWallet, | ||||
| } from 'wallet'; | } from 'wallet'; | ||||
| import { previewAddress } from 'helpers'; | import { previewAddress } from 'helpers'; | ||||
| import { sortWalletsForDisplay } from 'wallet'; | import { sortWalletsForDisplay } from 'wallet'; | ||||
| import { Event } from 'components/Common/GoogleAnalytics'; | import { Event } from 'components/Common/GoogleAnalytics'; | ||||
| import debounce from 'lodash.debounce'; | import debounce from 'lodash.debounce'; | ||||
| import { PageHeader } from 'components/Common/Atoms'; | import { | ||||
| SettingsPageHeaderLink, | |||||
| BackIcon, | |||||
| StyledConfigure, | |||||
| } from 'components/Configure/Configure'; | |||||
| interface WalletsFormData { | interface WalletsFormData { | ||||
| renamedWalletName: string; | renamedWalletName: string; | ||||
| walletToBeDeletedName: string; | walletToBeDeletedName: string; | ||||
| newWalletName: string; | newWalletName: string; | ||||
| mnemonic: string; | mnemonic: string; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 391 Lines • ▼ Show 20 Lines | const activateWallet = async (walletToActivate: StoredCashtabWallet) => { | ||||
| console.error('Error activating wallet:', error); | console.error('Error activating wallet:', error); | ||||
| toast.error('Failed to activate wallet. Please try again.'); | toast.error('Failed to activate wallet. Please try again.'); | ||||
| } finally { | } finally { | ||||
| setLoading(false); | setLoading(false); | ||||
| } | } | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <> | <StyledConfigure> | ||||
| <PageHeader> | <SettingsPageHeaderLink | ||||
| Wallets <BankIcon /> | to="/configure" | ||||
| </PageHeader> | aria-label="Back to settings" | ||||
| > | |||||
| <BackIcon aria-hidden="true" /> | |||||
| Wallets | |||||
| </SettingsPageHeaderLink> | |||||
| {walletToBeRenamed !== null && ( | {walletToBeRenamed !== null && ( | ||||
| <Modal | <Modal | ||||
| height={180} | height={180} | ||||
| title={`Rename "${walletToBeRenamed.name}"?`} | title={`Rename "${walletToBeRenamed.name}"?`} | ||||
| handleOk={renameWallet} | handleOk={renameWallet} | ||||
| handleCancel={() => setWalletToBeRenamed(null)} | handleCancel={() => setWalletToBeRenamed(null)} | ||||
| showCancelButton | showCancelButton | ||||
| disabled={ | disabled={ | ||||
| ▲ Show 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | return ( | ||||
| ), | ), | ||||
| )} | )} | ||||
| </AddressShareModal> | </AddressShareModal> | ||||
| </Modal> | </Modal> | ||||
| )} | )} | ||||
| <WalletsList title="Wallets"> | <WalletsList title="Wallets"> | ||||
| <WalletsPanel> | <WalletsPanel> | ||||
| {sortWalletsForDisplay(activeStoredWallet, wallets).map( | {sortWalletsForDisplay(activeStoredWallet, wallets).map( | ||||
| (wallet, index) => | (wallet, index) => { | ||||
| index === 0 ? ( | const isActive = index === 0; | ||||
| return ( | |||||
| <Wallet key={`${wallet.name}_${index}`}> | <Wallet key={`${wallet.name}_${index}`}> | ||||
| <WalletRow> | <WalletLeftColumn> | ||||
| <ActiveWalletName className="notranslate"> | <WalletName className="notranslate"> | ||||
| {wallet.name} | {wallet.name} | ||||
| </ActiveWalletName> | </WalletName> | ||||
| <h4>(active)</h4> | <ActivateButton | ||||
| $active={isActive} | |||||
| aria-label={ | |||||
| isActive | |||||
| ? `${wallet.name} is active` | |||||
| : `Activate ${wallet.name}` | |||||
| } | |||||
| onClick={ | |||||
| isActive | |||||
| ? undefined | |||||
| : debounce( | |||||
| () => | |||||
| activateWallet( | |||||
| wallet, | |||||
| ), | |||||
| 500, | |||||
| ) | |||||
| } | |||||
| disabled={isActive} | |||||
| > | |||||
| {isActive ? 'Active' : 'Activate'} | |||||
| </ActivateButton> | |||||
| </WalletLeftColumn> | |||||
| <SvgButtonPanel> | <SvgButtonPanel> | ||||
| <CopyIconButton | |||||
| name={`Copy address of ${wallet.name}`} | |||||
| data={wallet.address} | |||||
| showToast | |||||
| /> | |||||
| <IconButton | <IconButton | ||||
| name={`Rename ${wallet.name}`} | name={`Delete ${wallet.name}`} | ||||
| icon={<EditIcon />} | icon={<TrashcanIcon />} | ||||
| onClick={() => | onClick={() => | ||||
| setWalletToBeRenamed(wallet) | setWalletToBeDeleted(wallet) | ||||
| } | } | ||||
| /> | /> | ||||
| <IconButton | <IconButton | ||||
| name={`Add ${wallet.name} to contacts`} | name={`Add ${wallet.name} to contacts`} | ||||
| icon={<AddContactIcon />} | icon={<AddContactIcon />} | ||||
| onClick={() => | onClick={() => | ||||
| addWalletToContacts(wallet) | addWalletToContacts(wallet) | ||||
| } | } | ||||
| /> | /> | ||||
| </SvgButtonPanel> | |||||
| </WalletRow> | |||||
| </Wallet> | |||||
| ) : ( | |||||
| <Wallet key={`${wallet.name}_${index}`}> | |||||
| <WalletRow> | |||||
| <WalletName> | |||||
| <h3 className="overflow notranslate"> | |||||
| {wallet.name} | |||||
| </h3> | |||||
| </WalletName> | |||||
| </WalletRow> | |||||
| <ActionsRow> | |||||
| <ButtonPanel> | |||||
| <SvgButtonPanel> | |||||
| <CopyIconButton | |||||
| name={`Copy address of ${wallet.name}`} | |||||
| data={wallet.address} | |||||
| showToast | |||||
| /> | |||||
| <IconButton | <IconButton | ||||
| name={`Rename ${wallet.name}`} | name={`Rename ${wallet.name}`} | ||||
| icon={<EditIcon />} | icon={<EditIcon />} | ||||
| onClick={() => | onClick={() => | ||||
| setWalletToBeRenamed( | setWalletToBeRenamed(wallet) | ||||
| wallet, | |||||
| ) | |||||
| } | |||||
| /> | |||||
| <IconButton | |||||
| name={`Add ${wallet.name} to contacts`} | |||||
| icon={<AddContactIcon />} | |||||
| onClick={() => | |||||
| addWalletToContacts( | |||||
| wallet, | |||||
| ) | |||||
| } | } | ||||
| /> | /> | ||||
| <IconButton | |||||
| name={`Delete ${wallet.name}`} | <CopyIconButton | ||||
| icon={<TrashcanIcon />} | name={`Copy address of ${wallet.name}`} | ||||
| onClick={() => | data={wallet.address} | ||||
| setWalletToBeDeleted( | showToast | ||||
| wallet, | |||||
| ) | |||||
| } | |||||
| /> | /> | ||||
| </SvgButtonPanel> | </SvgButtonPanel> | ||||
| <ActivateButton | |||||
| aria-label={`Activate ${wallet.name}`} | |||||
| onClick={debounce( | |||||
| () => | |||||
| activateWallet(wallet), | |||||
| 500, | |||||
| )} | |||||
| > | |||||
| Activate | |||||
| </ActivateButton> | |||||
| </ButtonPanel> | |||||
| </ActionsRow> | |||||
| </Wallet> | </Wallet> | ||||
| ), | ); | ||||
| }, | |||||
| )} | )} | ||||
| </WalletsPanel> | </WalletsPanel> | ||||
| <WalletRow> | <WalletRow> | ||||
| <PrimaryButton onClick={() => addNewWallet()}> | <PrimaryButton onClick={() => addNewWallet()}> | ||||
| New Wallet | New Wallet | ||||
| </PrimaryButton> | </PrimaryButton> | ||||
| </WalletRow> | </WalletRow> | ||||
| <WalletRow> | <WalletRow> | ||||
| <SecondaryButton | <SecondaryButton | ||||
| onClick={() => setShowImportWalletModal(true)} | onClick={() => setShowImportWalletModal(true)} | ||||
| > | > | ||||
| Import Wallet | Import Wallet | ||||
| </SecondaryButton> | </SecondaryButton> | ||||
| </WalletRow> | </WalletRow> | ||||
| </WalletsList> | </WalletsList> | ||||
| </> | </StyledConfigure> | ||||
| ); | ); | ||||
| }; | }; | ||||
| export default Wallets; | export default Wallets; | ||||