Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Named Accounts #1699

Merged
merged 15 commits into from
Nov 14, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Save wallet name in redux
buberdds committed Nov 14, 2023
commit ff81487f50b5034f0023cda8dd98e986468bad27
Original file line number Diff line number Diff line change
@@ -4,11 +4,13 @@ import { ManageableAccountDetails } from './ManageableAccountDetails'
import { Wallet } from '../../../../state/wallet/types'

export const ManageableAccount = ({
editHandler,
wallet,
isActive,
deleteWallet,
selectWallet,
}: {
editHandler: (name: string) => void
wallet: Wallet
isActive: boolean
deleteWallet?: (address: string) => void
@@ -34,11 +36,13 @@ export const ManageableAccount = ({
displayManageButton={{
onClickManage: () => setLayerVisibility(true),
}}
name={wallet.name}
/>
{layerVisibility && (
<ManageableAccountDetails
closeHandler={() => setLayerVisibility(false)}
deleteAccount={handleDelete}
editHandler={editHandler}
wallet={wallet}
/>
)}
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import { useContext, useState } from 'react'
import copy from 'copy-to-clipboard'
import { Box } from 'grommet/es6/components/Box'
import { Button } from 'grommet/es6/components/Button'
import { Form } from 'grommet/es6/components/Form'
import { FormField } from 'grommet/es6/components/FormField'
import { Notification } from 'grommet/es6/components/Notification'
import { ResponsiveContext } from 'grommet/es6/contexts/ResponsiveContext'
@@ -22,21 +23,28 @@ import { LayerContainer } from './../LayerContainer'
import { uintToBase64, hex2uint } from '../../../../lib/helpers'
import { DeleteAccount } from './DeleteAccount'

interface FormValue {
name: string
}

interface ManageableAccountDetailsProps {
animation?: boolean
closeHandler: () => void
/** If undefined: delete button is disabled */
deleteAccount: undefined | ((address: string) => void)
editHandler: (name: string) => void
wallet: Wallet
}

export const ManageableAccountDetails = ({
animation,
closeHandler,
deleteAccount,
editHandler,
wallet,
}: ManageableAccountDetailsProps) => {
const { t } = useTranslation()
const [value, setValue] = useState({ name: wallet.name || '' })
const [layerVisibility, setLayerVisibility] = useState(false)
const [deleteLayerVisibility, setDeleteLayerVisibility] = useState(false)
const [acknowledge, setAcknowledge] = useState(false)
@@ -64,69 +72,79 @@ export const ManageableAccountDetails = ({
height={{ min: isMobile ? 'auto' : layerOverlayMinHeight }}
pad={{ vertical: 'medium' }}
>
<Box gap="medium">
<FormField
name="name"
validate={(name: string) =>
name.trim().length > 16
? {
message: t('toolbar.settings.nameLengthError', 'No more than 16 characters'),
status: 'error',
}
: undefined
}
>
<TextInput
<Form<FormValue>
onSubmit={({ value }) => {
editHandler(value.name)
closeHandler()
}}
value={value}
onChange={nextValue => setValue(nextValue)}
>
<Box gap="medium">
<FormField
name="name"
placeholder={t('toolbar.settings.optionalName', 'Name (optional)')}
/>
</FormField>
<Box>
<AddressBox address={wallet.address} border />
<Text size="small" margin={'small'}>
<DerivationFormatter pathDisplay={wallet.pathDisplay} type={wallet.type} />
</Text>
</Box>
<Box justify="between" direction="row">
<Button
alignSelf="start"
label={t('toolbar.settings.exportPrivateKey.title', 'Export Private Key')}
disabled={!wallet.privateKey}
onClick={() => setLayerVisibility(true)}
/>

{deleteAccount ? (
validate={(name: string) =>
name.trim().length > 16
? {
message: t('toolbar.settings.nameLengthError', 'No more than 16 characters'),
status: 'error',
}
: undefined
}
>
<TextInput
name="name"
placeholder={t('toolbar.settings.optionalName', 'Name (optional)')}
/>
</FormField>
<Box>
<AddressBox address={wallet.address} border />
<Text size="small" margin={'small'}>
<DerivationFormatter pathDisplay={wallet.pathDisplay} type={wallet.type} />
</Text>
</Box>
<Box justify="between" direction="row">
<Button
plain
color="status-error"
label={t('toolbar.settings.delete.title', 'Delete Account')}
onClick={() => setDeleteLayerVisibility(true)}
alignSelf="start"
label={t('toolbar.settings.exportPrivateKey.title', 'Export Private Key')}
disabled={!wallet.privateKey}
onClick={() => setLayerVisibility(true)}
/>
) : (
<Tip
content={t(
'toolbar.settings.delete.tooltip',
'You must have at least one account at all times.',
)}
dropProps={{ align: { bottom: 'top' } }}
>
<Box>
<Button
icon={<CircleInformation size="18px" color="status-error" />}
disabled={true}
plain
color="status-error"
label={t('toolbar.settings.delete.title', 'Delete Account')}
onClick={() => setDeleteLayerVisibility(true)}
/>
</Box>
</Tip>
)}

{deleteAccount ? (
<Button
plain
color="status-error"
label={t('toolbar.settings.delete.title', 'Delete Account')}
onClick={() => setDeleteLayerVisibility(true)}
/>
) : (
<Tip
content={t(
'toolbar.settings.delete.tooltip',
'You must have at least one account at all times.',
)}
dropProps={{ align: { bottom: 'top' } }}
>
<Box>
<Button
icon={<CircleInformation size="18px" color="status-error" />}
disabled={true}
plain
color="status-error"
label={t('toolbar.settings.delete.title', 'Delete Account')}
onClick={() => setDeleteLayerVisibility(true)}
/>
</Box>
</Tip>
)}
</Box>
</Box>
</Box>
<Box direction="row" justify="between" pad={{ top: 'large' }}>
<Button secondary label={t('toolbar.settings.cancel', 'Cancel')} onClick={closeHandler} />
</Box>
<Box direction="row" justify="between" pad={{ top: 'large' }}>
<Button secondary label={t('toolbar.settings.cancel', 'Cancel')} onClick={closeHandler} />
<Button primary label={t('toolbar.settings.save', 'Save')} type="submit" />
</Box>
</Form>
</Box>
</Tab>
</Tabs>
3 changes: 3 additions & 0 deletions src/app/components/Toolbar/Features/AccountSelector/index.tsx
Original file line number Diff line number Diff line change
@@ -31,6 +31,9 @@ export const AccountSelector = memo((props: Props) => {

const accounts = Object.values(wallets).map(wallet => (
<ManageableAccount
editHandler={(name: string) => {
dispatch(walletActions.setWalletName({ address: wallet.address, name }))
}}
key={wallet.address}
wallet={wallet}
deleteWallet={
3 changes: 3 additions & 0 deletions src/app/pages/AccountPage/Features/AccountSummary/index.tsx
Original file line number Diff line number Diff line change
@@ -90,6 +90,7 @@ export interface AccountSummaryProps {
address: string
balance: BalanceDetails
deleteWallet?: (address: string) => void
editHandler: (name: string) => void
walletHasAccounts?: boolean
wallet?: Wallet
}
@@ -98,6 +99,7 @@ export function AccountSummary({
address,
balance,
deleteWallet,
editHandler,
wallet,
walletHasAccounts,
}: AccountSummaryProps) {
@@ -185,6 +187,7 @@ export function AccountSummary({
}
: undefined
}
editHandler={editHandler}
wallet={wallet}
/>
)}
8 changes: 7 additions & 1 deletion src/app/pages/AccountPage/index.tsx
Original file line number Diff line number Diff line change
@@ -94,7 +94,12 @@ export function AccountPage(props: AccountPageProps) {
? null
: (BigInt(account.available) + balanceDelegations + balanceDebondingDelegations).toString(),
}

const editWalletHandler = (name: string) => {
if (!wallet) {
return
}
dispatch(walletActions.setWalletName({ address: wallet.address, name }))
}
// Restart fetching account balances if address or network changes
useEffect(() => {
dispatch(accountActions.openAccountPage(address))
@@ -142,6 +147,7 @@ export function AccountPage(props: AccountPageProps) {
wallet!.address === address && dispatch(walletActions.selectFirstWallet())
}
}
editHandler={editWalletHandler}
wallet={wallet}
walletHasAccounts={walletHasAccounts}
/>
3 changes: 3 additions & 0 deletions src/app/state/wallet/index.ts
Original file line number Diff line number Diff line change
@@ -56,6 +56,9 @@ const slice = createSlice({
state.wallets[newWallet.address] = newWallet
state.selectedWallet ??= newWallet.address
},
setWalletName(state, action: PayloadAction<{ address: string; name: string }>) {
state.wallets[action.payload.address].name = action.payload.name
},
},
})

1 change: 1 addition & 0 deletions src/app/state/wallet/types.ts
Original file line number Diff line number Diff line change
@@ -19,6 +19,7 @@ export interface Wallet {
pathDisplay?: string
privateKey?: string
balance: BalanceDetails
name?: string
buberdds marked this conversation as resolved.
Show resolved Hide resolved
}

export interface AddWalletPayload extends Wallet {
1 change: 1 addition & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
@@ -449,6 +449,7 @@
"nameLengthError": "No more than 16 characters",
"optionalName": "Name (optional)",
"profile": "Profile",
"save": "Save",
"settings": "Settings"
},
"wallets": {