Changeset View
Changeset View
Standalone View
Standalone View
web/cashtab/src/components/Configure/Configure.js
/* eslint-disable react-hooks/exhaustive-deps */ | /* eslint-disable react-hooks/exhaustive-deps */ | ||||
import React, { useState, useEffect } from 'react'; | import React, { useState, useEffect } from 'react'; | ||||
import styled from 'styled-components'; | import styled from 'styled-components'; | ||||
import { Collapse, Form, Input, Modal, Spin, Alert } from 'antd'; | import { Collapse, Form, Input, Modal, Alert } from 'antd'; | ||||
import { | import { | ||||
PlusSquareOutlined, | PlusSquareOutlined, | ||||
WalletFilled, | WalletFilled, | ||||
ImportOutlined, | ImportOutlined, | ||||
LockOutlined, | LockOutlined, | ||||
} from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||
import { WalletContext } from '@utils/context'; | import { WalletContext } from '@utils/context'; | ||||
import { StyledCollapse } from '@components/Common/StyledCollapse'; | import { StyledCollapse } from '@components/Common/StyledCollapse'; | ||||
import { | import { | ||||
AntdFormWrapper, | AntdFormWrapper, | ||||
CurrencySelectDropdown, | CurrencySelectDropdown, | ||||
} from '@components/Common/EnhancedInputs'; | } from '@components/Common/EnhancedInputs'; | ||||
import PrimaryButton, { | import PrimaryButton, { | ||||
SecondaryButton, | SecondaryButton, | ||||
SmartButton, | SmartButton, | ||||
} from '@components/Common/PrimaryButton'; | } from '@components/Common/PrimaryButton'; | ||||
import { | import { | ||||
CashLoader, | CashLoader, | ||||
CashLoadingIcon, | |||||
ThemedCopyOutlined, | ThemedCopyOutlined, | ||||
ThemedWalletOutlined, | ThemedWalletOutlined, | ||||
ThemedDollarOutlined, | ThemedDollarOutlined, | ||||
} from '@components/Common/CustomIcons'; | } from '@components/Common/CustomIcons'; | ||||
import { ReactComponent as Trashcan } from '@assets/trashcan.svg'; | import { ReactComponent as Trashcan } from '@assets/trashcan.svg'; | ||||
import { ReactComponent as Edit } from '@assets/edit.svg'; | import { ReactComponent as Edit } from '@assets/edit.svg'; | ||||
import { Event } from '@utils/GoogleAnalytics'; | import { Event } from '@utils/GoogleAnalytics'; | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | const StyledSpacer = styled.div` | ||||
height: 1px; | height: 1px; | ||||
width: 100%; | width: 100%; | ||||
background-color: ${props => props.theme.wallet.borders.color}; | background-color: ${props => props.theme.wallet.borders.color}; | ||||
margin: 60px 0 50px; | margin: 60px 0 50px; | ||||
`; | `; | ||||
const Configure = () => { | const Configure = () => { | ||||
const ContextValue = React.useContext(WalletContext); | const ContextValue = React.useContext(WalletContext); | ||||
const { wallet, loading, apiError } = ContextValue; | const { wallet, apiError } = ContextValue; | ||||
const { | const { | ||||
addNewSavedWallet, | addNewSavedWallet, | ||||
activateWallet, | activateWallet, | ||||
renameWallet, | renameWallet, | ||||
deleteWallet, | deleteWallet, | ||||
validateMnemonic, | validateMnemonic, | ||||
getSavedWallets, | getSavedWallets, | ||||
▲ Show 20 Lines • Show All 197 Lines • ▼ Show 20 Lines | const handleWalletToDeleteInput = e => { | ||||
setWalletDeleteValid(true); | setWalletDeleteValid(true); | ||||
} else { | } else { | ||||
setWalletDeleteValid(false); | setWalletDeleteValid(false); | ||||
} | } | ||||
setConfirmationOfWalletToBeDeleted(value); | setConfirmationOfWalletToBeDeleted(value); | ||||
}; | }; | ||||
return ( | return ( | ||||
<Spin spinning={loading} indicator={CashLoadingIcon}> | |||||
<StyledConfigure> | <StyledConfigure> | ||||
{walletToBeRenamed !== null && ( | {walletToBeRenamed !== null && ( | ||||
<Modal | <Modal | ||||
title={`Rename Wallet ${walletToBeRenamed.name}`} | title={`Rename Wallet ${walletToBeRenamed.name}`} | ||||
visible={showRenameWalletModal} | visible={showRenameWalletModal} | ||||
onOk={changeWalletName} | onOk={changeWalletName} | ||||
onCancel={() => cancelRenameWallet()} | onCancel={() => cancelRenameWallet()} | ||||
> | > | ||||
<AntdFormWrapper> | <AntdFormWrapper> | ||||
<Form style={{ width: 'auto' }}> | <Form style={{ width: 'auto' }}> | ||||
<Form.Item | <Form.Item | ||||
validateStatus={ | validateStatus={ | ||||
newWalletNameIsValid === null || | newWalletNameIsValid === null || | ||||
newWalletNameIsValid | newWalletNameIsValid | ||||
? '' | ? '' | ||||
: 'error' | : 'error' | ||||
} | } | ||||
help={ | help={ | ||||
newWalletNameIsValid === null || | newWalletNameIsValid === null || | ||||
newWalletNameIsValid | newWalletNameIsValid | ||||
? '' | ? '' | ||||
: 'Wallet name must be a string between 1 and 24 characters long' | : 'Wallet name must be a string between 1 and 24 characters long' | ||||
} | } | ||||
> | > | ||||
<Input | <Input | ||||
prefix={<WalletFilled />} | prefix={<WalletFilled />} | ||||
placeholder="Enter new wallet name" | placeholder="Enter new wallet name" | ||||
name="newName" | name="newName" | ||||
value={newWalletName} | value={newWalletName} | ||||
onChange={e => handleWalletNameInput(e)} | onChange={e => handleWalletNameInput(e)} | ||||
/> | /> | ||||
</Form.Item> | </Form.Item> | ||||
</Form> | </Form> | ||||
</AntdFormWrapper> | </AntdFormWrapper> | ||||
</Modal> | </Modal> | ||||
)} | )} | ||||
{walletToBeDeleted !== null && ( | {walletToBeDeleted !== null && ( | ||||
<Modal | <Modal | ||||
title={`Are you sure you want to delete wallet "${walletToBeDeleted.name}"?`} | title={`Are you sure you want to delete wallet "${walletToBeDeleted.name}"?`} | ||||
visible={showDeleteWalletModal} | visible={showDeleteWalletModal} | ||||
onOk={deleteSelectedWallet} | onOk={deleteSelectedWallet} | ||||
onCancel={() => cancelDeleteWallet()} | onCancel={() => cancelDeleteWallet()} | ||||
> | > | ||||
<AntdFormWrapper> | <AntdFormWrapper> | ||||
<Form style={{ width: 'auto' }}> | <Form style={{ width: 'auto' }}> | ||||
<Form.Item | <Form.Item | ||||
validateStatus={ | validateStatus={ | ||||
walletDeleteValid === null || | walletDeleteValid === null || | ||||
walletDeleteValid | walletDeleteValid | ||||
? '' | ? '' | ||||
: 'error' | : 'error' | ||||
} | } | ||||
help={ | help={ | ||||
walletDeleteValid === null || | walletDeleteValid === null || | ||||
walletDeleteValid | walletDeleteValid | ||||
? '' | ? '' | ||||
: 'Your confirmation phrase must match exactly' | : 'Your confirmation phrase must match exactly' | ||||
} | } | ||||
> | > | ||||
<Input | <Input | ||||
prefix={<WalletFilled />} | prefix={<WalletFilled />} | ||||
placeholder={`Type "delete ${walletToBeDeleted.name}" to confirm`} | placeholder={`Type "delete ${walletToBeDeleted.name}" to confirm`} | ||||
name="walletToBeDeletedInput" | name="walletToBeDeletedInput" | ||||
value={confirmationOfWalletToBeDeleted} | value={confirmationOfWalletToBeDeleted} | ||||
onChange={e => | onChange={e => handleWalletToDeleteInput(e)} | ||||
handleWalletToDeleteInput(e) | |||||
} | |||||
/> | /> | ||||
</Form.Item> | </Form.Item> | ||||
</Form> | </Form> | ||||
</AntdFormWrapper> | </AntdFormWrapper> | ||||
</Modal> | </Modal> | ||||
)} | )} | ||||
<h2> | <h2> | ||||
<ThemedCopyOutlined /> Backup your wallet | <ThemedCopyOutlined /> Backup your wallet | ||||
</h2> | </h2> | ||||
<Alert | <Alert | ||||
style={{ marginBottom: '12px' }} | style={{ marginBottom: '12px' }} | ||||
description="Your seed phrase is the only way to restore your wallet. Write it down. Keep it safe." | description="Your seed phrase is the only way to restore your wallet. Write it down. Keep it safe." | ||||
type="warning" | type="warning" | ||||
showIcon | showIcon | ||||
/> | /> | ||||
{wallet && wallet.mnemonic && ( | {wallet && wallet.mnemonic && ( | ||||
<StyledCollapse> | <StyledCollapse> | ||||
<Panel header="Click to reveal seed phrase" key="1"> | <Panel header="Click to reveal seed phrase" key="1"> | ||||
<p className="notranslate"> | <p className="notranslate"> | ||||
{wallet && wallet.mnemonic | {wallet && wallet.mnemonic ? wallet.mnemonic : ''} | ||||
? wallet.mnemonic | |||||
: ''} | |||||
</p> | </p> | ||||
</Panel> | </Panel> | ||||
</StyledCollapse> | </StyledCollapse> | ||||
)} | )} | ||||
<StyledSpacer /> | <StyledSpacer /> | ||||
<h2> | <h2> | ||||
<ThemedWalletOutlined /> Manage Wallets | <ThemedWalletOutlined /> Manage Wallets | ||||
</h2> | </h2> | ||||
{apiError ? ( | {apiError ? ( | ||||
<> | <> | ||||
<CashLoader /> | <CashLoader /> | ||||
<p style={{ color: 'red' }}> | <p style={{ color: 'red' }}> | ||||
<b>An error occured on our end. Reconnecting...</b> | <b>An error occured on our end. Reconnecting...</b> | ||||
</p> | </p> | ||||
</> | </> | ||||
) : ( | ) : ( | ||||
<> | <> | ||||
<PrimaryButton | <PrimaryButton onClick={() => updateSavedWalletsOnCreate()}> | ||||
onClick={() => updateSavedWalletsOnCreate()} | |||||
> | |||||
<PlusSquareOutlined /> New Wallet | <PlusSquareOutlined /> New Wallet | ||||
</PrimaryButton> | </PrimaryButton> | ||||
<SecondaryButton | <SecondaryButton onClick={() => openSeedInput(!seedInput)}> | ||||
onClick={() => openSeedInput(!seedInput)} | |||||
> | |||||
<ImportOutlined /> Import Wallet | <ImportOutlined /> Import Wallet | ||||
</SecondaryButton> | </SecondaryButton> | ||||
{seedInput && ( | {seedInput && ( | ||||
<> | <> | ||||
<p> | <p> | ||||
Copy and paste your mnemonic seed phrase | Copy and paste your mnemonic seed phrase below | ||||
below to import an existing wallet | to import an existing wallet | ||||
</p> | </p> | ||||
<AntdFormWrapper> | <AntdFormWrapper> | ||||
<Form style={{ width: 'auto' }}> | <Form style={{ width: 'auto' }}> | ||||
<Form.Item | <Form.Item | ||||
validateStatus={ | validateStatus={ | ||||
isValidMnemonic === null || | isValidMnemonic === null || | ||||
isValidMnemonic | isValidMnemonic | ||||
? '' | ? '' | ||||
: 'error' | : 'error' | ||||
} | } | ||||
help={ | help={ | ||||
isValidMnemonic === null || | isValidMnemonic === null || | ||||
isValidMnemonic | isValidMnemonic | ||||
? '' | ? '' | ||||
: 'Valid mnemonic seed phrase required' | : 'Valid mnemonic seed phrase required' | ||||
} | } | ||||
> | > | ||||
<Input | <Input | ||||
prefix={<LockOutlined />} | prefix={<LockOutlined />} | ||||
type="email" | type="email" | ||||
placeholder="mnemonic (seed phrase)" | placeholder="mnemonic (seed phrase)" | ||||
name="mnemonic" | name="mnemonic" | ||||
autoComplete="off" | autoComplete="off" | ||||
onChange={e => handleChange(e)} | onChange={e => handleChange(e)} | ||||
required | required | ||||
/> | /> | ||||
</Form.Item> | </Form.Item> | ||||
<SmartButton | <SmartButton | ||||
disabled={!isValidMnemonic} | disabled={!isValidMnemonic} | ||||
onClick={() => submit()} | onClick={() => submit()} | ||||
> | > | ||||
Import | Import | ||||
</SmartButton> | </SmartButton> | ||||
</Form> | </Form> | ||||
</AntdFormWrapper> | </AntdFormWrapper> | ||||
</> | </> | ||||
)} | )} | ||||
</> | </> | ||||
)} | )} | ||||
{savedWallets && savedWallets.length > 0 && ( | {savedWallets && savedWallets.length > 0 && ( | ||||
<> | <> | ||||
<StyledCollapse> | <StyledCollapse> | ||||
<Panel header="Saved wallets" key="2"> | <Panel header="Saved wallets" key="2"> | ||||
<AWRow> | <AWRow> | ||||
<h3>{wallet.name}</h3> | <h3>{wallet.name}</h3> | ||||
<h4>Currently active</h4> | <h4>Currently active</h4> | ||||
</AWRow> | </AWRow> | ||||
<div> | <div> | ||||
{savedWallets.map(sw => ( | {savedWallets.map(sw => ( | ||||
<SWRow key={sw.name}> | <SWRow key={sw.name}> | ||||
<SWName> | <SWName> | ||||
<h3>{sw.name}</h3> | <h3>{sw.name}</h3> | ||||
</SWName> | </SWName> | ||||
<SWButtonCtn> | <SWButtonCtn> | ||||
<Edit | <Edit | ||||
onClick={() => | onClick={() => | ||||
showPopulatedRenameWalletModal( | showPopulatedRenameWalletModal( | ||||
sw, | sw, | ||||
) | ) | ||||
} | } | ||||
/> | /> | ||||
<Trashcan | <Trashcan | ||||
onClick={() => | onClick={() => | ||||
showPopulatedDeleteWalletModal( | showPopulatedDeleteWalletModal( | ||||
sw, | sw, | ||||
) | ) | ||||
} | } | ||||
/> | /> | ||||
<button | <button | ||||
onClick={() => | onClick={() => | ||||
updateSavedWalletsOnLoad( | updateSavedWalletsOnLoad(sw) | ||||
sw, | |||||
) | |||||
} | } | ||||
> | > | ||||
Activate | Activate | ||||
</button> | </button> | ||||
</SWButtonCtn> | </SWButtonCtn> | ||||
</SWRow> | </SWRow> | ||||
))} | ))} | ||||
</div> | </div> | ||||
</Panel> | </Panel> | ||||
</StyledCollapse> | </StyledCollapse> | ||||
</> | </> | ||||
)} | )} | ||||
<StyledSpacer /> | <StyledSpacer /> | ||||
<h2> | <h2> | ||||
<ThemedDollarOutlined /> Fiat Currency | <ThemedDollarOutlined /> Fiat Currency | ||||
</h2> | </h2> | ||||
<AntdFormWrapper> | <AntdFormWrapper> | ||||
<CurrencySelectDropdown | <CurrencySelectDropdown | ||||
defaultValue={ | defaultValue={ | ||||
cashtabSettings && cashtabSettings.fiatCurrency | cashtabSettings && cashtabSettings.fiatCurrency | ||||
? cashtabSettings.fiatCurrency | ? cashtabSettings.fiatCurrency | ||||
: 'usd' | : 'usd' | ||||
} | } | ||||
onChange={fiatCode => | onChange={fiatCode => | ||||
changeCashtabSettings('fiatCurrency', fiatCode) | changeCashtabSettings('fiatCurrency', fiatCode) | ||||
} | } | ||||
/> | /> | ||||
</AntdFormWrapper> | </AntdFormWrapper> | ||||
<StyledSpacer />[ | <StyledSpacer />[ | ||||
<SettingsLink | <SettingsLink | ||||
type="link" | type="link" | ||||
href="https://docs.cashtabapp.com/docs/" | href="https://docs.cashtabapp.com/docs/" | ||||
target="_blank" | target="_blank" | ||||
rel="noreferrer" | rel="noreferrer" | ||||
> | > | ||||
Documentation | Documentation | ||||
</SettingsLink> | </SettingsLink> | ||||
] | ] | ||||
</StyledConfigure> | </StyledConfigure> | ||||
</Spin> | |||||
); | ); | ||||
}; | }; | ||||
export default Configure; | export default Configure; |