diff --git a/src/renderer/components/header/lock/HeaderLock.tsx b/src/renderer/components/header/lock/HeaderLock.tsx
index 81ab351eb..d937e13b6 100644
--- a/src/renderer/components/header/lock/HeaderLock.tsx
+++ b/src/renderer/components/header/lock/HeaderLock.tsx
@@ -44,7 +44,7 @@ export const HeaderLock: React.FC = (props): JSX.Element => {
text-text2 dark:bg-gray0d
dark:text-text2d
">
- {truncateMiddle(name, { start: 4, end: 4, max: 16 })}
+ {truncateMiddle(name, { start: 3, end: 3, max: 11 })}
)
)
diff --git a/src/renderer/components/settings/WalletSettings.tsx b/src/renderer/components/settings/WalletSettings.tsx
index ab2d38127..2417d4cf5 100644
--- a/src/renderer/components/settings/WalletSettings.tsx
+++ b/src/renderer/components/settings/WalletSettings.tsx
@@ -60,7 +60,9 @@ import {
WalletAddressAsync,
KeystoreUnlocked,
ChangeKeystoreWalletHandler,
- ChangeKeystoreWalletRD
+ ChangeKeystoreWalletRD,
+ RenameKeystoreWalletHandler,
+ RenameKeystoreWalletRD
} from '../../services/wallet/types'
import { walletTypeToI18n } from '../../services/wallet/util'
import { AttentionIcon } from '../icons'
@@ -77,8 +79,9 @@ type Props = {
network: Network
walletAccounts: O.Option
lockWallet: FP.Lazy
- removeKeystore: RemoveKeystoreWalletHandler
- changeKeystore$: ChangeKeystoreWalletHandler
+ removeKeystoreWallet: RemoveKeystoreWalletHandler
+ changeKeystoreWallet$: ChangeKeystoreWalletHandler
+ renameKeystoreWallet$: RenameKeystoreWalletHandler
exportKeystore: () => Promise
addLedgerAddress: (chain: Chain, walletIndex: number) => void
verifyLedgerAddress: (chain: Chain, walletIndex: number) => Promise
@@ -100,13 +103,14 @@ export const WalletSettings: React.FC = (props): JSX.Element => {
network,
walletAccounts: oWalletAccounts,
lockWallet,
- removeKeystore,
- changeKeystore$,
+ removeKeystoreWallet,
+ changeKeystoreWallet$,
+ renameKeystoreWallet$,
exportKeystore,
addLedgerAddress,
verifyLedgerAddress,
removeLedgerAddress,
- keystore: { phrase, name: walletName },
+ keystore: { phrase, name: walletName, id: walletId },
wallets,
clickAddressLinkHandler,
validatePassword$,
@@ -125,7 +129,7 @@ export const WalletSettings: React.FC = (props): JSX.Element => {
const closeQrModal = useCallback(() => setShowQRModal(O.none), [setShowQRModal])
const removeWalletHandler = useCallback(async () => {
- const noWallets = await removeKeystore()
+ const noWallets = await removeKeystoreWallet()
if (noWallets >= 1) {
// goto unlock screen to unlock another wallet
navigate(walletRoutes.locked.path())
@@ -133,7 +137,7 @@ export const WalletSettings: React.FC = (props): JSX.Element => {
// no wallet -> go to homepage
navigate(appRoutes.base.template)
}
- }, [removeKeystore, navigate])
+ }, [removeKeystoreWallet, navigate])
const onSuccessPassword = useCallback(() => {
setShowPasswordModal(false)
@@ -448,11 +452,11 @@ export const WalletSettings: React.FC = (props): JSX.Element => {
const changeWalletHandler = useCallback(
(id: KeystoreId) => {
- subscribeChangeWalletState(changeKeystore$(id))
+ subscribeChangeWalletState(changeKeystoreWallet$(id))
// Jump to `UnlockView` to avoid staying at wallet settings
navigate(walletRoutes.locked.path())
},
- [changeKeystore$, navigate, subscribeChangeWalletState]
+ [changeKeystoreWallet$, navigate, subscribeChangeWalletState]
)
const renderChangeWalletError = useMemo(
@@ -474,9 +478,33 @@ export const WalletSettings: React.FC = (props): JSX.Element => {
[changeWalletState, intl]
)
- const changeWalletNameHandler = useCallback((walletName: string) => {
- console.log('walletName:', walletName)
- }, [])
+ const { state: renameWalletState, subscribe: subscribeRenameWalletState } =
+ useSubscriptionState(RD.initial)
+
+ const changeWalletNameHandler = useCallback(
+ (walletName: string) => {
+ subscribeRenameWalletState(renameKeystoreWallet$(walletId, walletName))
+ },
+ [renameKeystoreWallet$, subscribeRenameWalletState, walletId]
+ )
+
+ const renderRenameWalletError = useMemo(
+ () =>
+ FP.pipe(
+ renameWalletState,
+ RD.fold(
+ () => <>>,
+ () => <>>,
+ (error) => (
+
+ {intl.formatMessage({ id: 'wallet.name.error.rename' })} {error?.message ?? error.toString()}
+
+ ),
+ () => <>>
+ )
+ ),
+ [intl, renameWalletState]
+ )
return (
@@ -518,8 +546,13 @@ export const WalletSettings: React.FC
= (props): JSX.Element => {
{intl.formatMessage({ id: 'setting.wallet.management' })}
-
-
+
+ {renderRenameWalletError}
+
void
className?: string
}
@@ -21,9 +23,10 @@ type FormData = {
}
export const EditableWalletName: React.FC = (props): JSX.Element => {
- const { name, onChange, className = '' } = props
+ const { name: initialName, onChange, loading = false, className = '' } = props
const [editableName, setEditableName] = useState>(O.none)
+ const [name, setName] = useState(initialName)
const intl = useIntl()
@@ -39,18 +42,22 @@ export const EditableWalletName: React.FC = (props): JSX.Element => {
setEditableName(O.some(name))
}
return (
-
+
)
- }, [name])
+ }, [loading, name])
const renderEditableName = useCallback(
(name: string) => {
- const confirm = () => FP.pipe(editableName, O.fold(FP.constVoid, onChange))
const cancel = () => {
reset()
setEditableName(O.none)
@@ -58,25 +65,22 @@ export const EditableWalletName: React.FC
= (props): JSX.Element => {
const submit = ({ name }: FormData) => {
setEditableName(O.none)
onChange(name)
+ setName(name)
reset()
}
const keyDownHandler = (e: React.KeyboardEvent) => {
- console.log('key down', e.key)
if (e.key === 'Escape') {
cancel()
}
}
- const error = !!errors.name
-
return (
)
},
- [editableName, errors.name, handleSubmit, intl, onChange, register, reset]
+ [errors.name, handleSubmit, intl, onChange, register, reset]
)
return (
- {intl.formatMessage({ id: 'wallet.name' })}{' '}
+ {intl.formatMessage({ id: 'wallet.name' })}
+ {/* show info about max. chars in editable mode only */}
{FP.pipe(
editableName,
O.fold(
@@ -118,7 +123,12 @@ export const EditableWalletName: React.FC = (props): JSX.Element => {
)
)}
- {FP.pipe(editableName, O.fold(renderName, renderEditableName))}
+
+ {FP.pipe(editableName, O.fold(renderName, renderEditableName))}
+
)
}
diff --git a/src/renderer/hooks/useKeystoreState.ts b/src/renderer/hooks/useKeystoreState.ts
index c978d6a84..3dd903f7b 100644
--- a/src/renderer/hooks/useKeystoreState.ts
+++ b/src/renderer/hooks/useKeystoreState.ts
@@ -9,7 +9,8 @@ import {
KeystoreState,
Phrase,
RemoveKeystoreWalletHandler,
- ChangeKeystoreWalletHandler
+ ChangeKeystoreWalletHandler,
+ RenameKeystoreWalletHandler
} from '../services/wallet/types'
import { getPhrase, getWalletName, isLocked } from '../services/wallet/util'
@@ -19,12 +20,20 @@ export const useKeystoreState = (): {
walletName: O.Option
remove: RemoveKeystoreWalletHandler
change$: ChangeKeystoreWalletHandler
+ rename$: RenameKeystoreWalletHandler
unlock: (password: string) => Promise
lock: FP.Lazy
locked: boolean
} => {
const {
- keystoreService: { keystore$, unlock, lock, removeKeystoreWallet: remove, changeKeystoreWallet: change$ }
+ keystoreService: {
+ keystore$,
+ unlock,
+ lock,
+ removeKeystoreWallet: remove,
+ changeKeystoreWallet: change$,
+ renameKeystoreWallet: rename$
+ }
} = useWalletContext()
const state = useObservableState(keystore$, INITIAL_KEYSTORE_STATE)
@@ -33,5 +42,5 @@ export const useKeystoreState = (): {
const [walletName] = useObservableState(() => FP.pipe(keystore$, RxOp.map(FP.flow(getWalletName))), O.none)
const [locked] = useObservableState(() => FP.pipe(keystore$, RxOp.map(FP.flow(isLocked))), false)
- return { state, phrase, walletName, unlock, lock, locked, remove, change$ }
+ return { state, phrase, walletName, unlock, lock, locked, remove, change$, rename$ }
}
diff --git a/src/renderer/i18n/de/wallet.ts b/src/renderer/i18n/de/wallet.ts
index c8b500e80..068ad78c2 100644
--- a/src/renderer/i18n/de/wallet.ts
+++ b/src/renderer/i18n/de/wallet.ts
@@ -4,6 +4,7 @@ const wallet: WalletMessages = {
'wallet.name': 'Wallet Name',
'wallet.name.maxChars': 'Max. {max} Zeichen',
'wallet.name.error.empty': 'Bitte Namen der Wallet angeben',
+ 'wallet.name.error.rename': 'Error beim Umbenennen der Wallet',
'wallet.nav.deposits': 'Einzahlungen',
'wallet.nav.bonds': 'Bonds',
'wallet.nav.poolshares': 'Anteile',
diff --git a/src/renderer/i18n/en/wallet.ts b/src/renderer/i18n/en/wallet.ts
index bb495d33f..e8cee3e2e 100644
--- a/src/renderer/i18n/en/wallet.ts
+++ b/src/renderer/i18n/en/wallet.ts
@@ -4,6 +4,7 @@ const wallet: WalletMessages = {
'wallet.name': 'Wallet name',
'wallet.name.maxChars': 'Max. {max} chars',
'wallet.name.error.empty': 'Please enter a name for your wallet',
+ 'wallet.name.error.rename': 'Error while renaming the wallet',
'wallet.nav.deposits': 'Deposits',
'wallet.nav.bonds': 'Bonds',
'wallet.nav.poolshares': 'Shares',
diff --git a/src/renderer/i18n/fr/wallet.ts b/src/renderer/i18n/fr/wallet.ts
index 80cbc5036..f54d71c40 100644
--- a/src/renderer/i18n/fr/wallet.ts
+++ b/src/renderer/i18n/fr/wallet.ts
@@ -4,6 +4,7 @@ const wallet: WalletMessages = {
'wallet.name': 'Wallet name - FR',
'wallet.name.maxChars': 'Max. {max} chars - FR',
'wallet.name.error.empty': 'Please enter a name for your wallet - FR',
+ 'wallet.name.error.rename': 'Error while renaming the wallet - FR',
'wallet.nav.deposits': 'Dépots',
'wallet.nav.bonds': 'Cautions',
'wallet.nav.poolshares': 'Quote-part',
diff --git a/src/renderer/i18n/ru/wallet.ts b/src/renderer/i18n/ru/wallet.ts
index ca5eec4a1..cafedd8f2 100644
--- a/src/renderer/i18n/ru/wallet.ts
+++ b/src/renderer/i18n/ru/wallet.ts
@@ -4,6 +4,7 @@ const wallet: WalletMessages = {
'wallet.name': 'Wallet name - RU',
'wallet.name.maxChars': 'Max. {max} chars - RU',
'wallet.name.error.empty': 'Please enter a name for your wallet - RU',
+ 'wallet.name.error.rename': 'Error while renaming the wallet - RU',
'wallet.nav.deposits': 'Вклады',
'wallet.nav.bonds': 'Бонды',
'wallet.nav.poolshares': 'Доли',
diff --git a/src/renderer/i18n/types.ts b/src/renderer/i18n/types.ts
index 4d5d5a977..1f6baea9b 100644
--- a/src/renderer/i18n/types.ts
+++ b/src/renderer/i18n/types.ts
@@ -152,6 +152,7 @@ type WalletMessageKey =
| 'wallet.name'
| 'wallet.name.maxChars'
| 'wallet.name.error.empty'
+ | 'wallet.name.error.rename'
| 'wallet.nav.deposits'
| 'wallet.nav.bonds'
| 'wallet.nav.poolshares'
diff --git a/src/renderer/services/wallet/keystore.ts b/src/renderer/services/wallet/keystore.ts
index 46807bb23..5e6a3ba42 100644
--- a/src/renderer/services/wallet/keystore.ts
+++ b/src/renderer/services/wallet/keystore.ts
@@ -23,7 +23,9 @@ import {
AddKeystoreParams,
KeystoreWalletsLD,
KeystoreWalletsUI$,
- ChangeKeystoreWalletLD
+ RenameKeystoreWalletHandler,
+ ChangeKeystoreWalletHandler,
+ isKeystoreUnlocked
} from './types'
import {
getKeystore,
@@ -122,7 +124,7 @@ export const removeKeystoreWallet = async () => {
return wallets.length
}
-const changeKeystoreWallet = (keystoreId: KeystoreId): ChangeKeystoreWalletLD => {
+const changeKeystoreWallet: ChangeKeystoreWalletHandler = (keystoreId: KeystoreId) => {
const wallets = getKeystoreWallets()
// Get selected wallet
const selectedWallet = FP.pipe(
@@ -136,7 +138,7 @@ const changeKeystoreWallet = (keystoreId: KeystoreId): ChangeKeystoreWalletLD =>
const { id, name } = selectedWallet
const updatedWallets = FP.pipe(
- getKeystoreWallets(),
+ wallets,
A.map((wallet) => ({ ...wallet, selected: id === wallet.id }))
)
@@ -145,13 +147,13 @@ const changeKeystoreWallet = (keystoreId: KeystoreId): ChangeKeystoreWalletLD =>
// encode wallets first
ipcKeystoreWalletsIO.encode,
// Save updated `wallets` to disk
- (wallets) => Rx.of(window.apiKeystore.saveKeystoreWallets(wallets)),
+ (wallets) => Rx.from(window.apiKeystore.saveKeystoreWallets(wallets)),
RxOp.catchError((err) => Rx.of(RD.failure(err))),
RxOp.map(() => RD.success(true)),
liveData.map((_) => {
// Update states
setKeystoreWallets(updatedWallets)
- // set selected wallet
+ // set selected wallet as locked wallet
setKeystoreState(O.some({ id, name }))
return true
}),
@@ -159,6 +161,43 @@ const changeKeystoreWallet = (keystoreId: KeystoreId): ChangeKeystoreWalletLD =>
)
}
+const renameKeystoreWallet: RenameKeystoreWalletHandler = (id, name) => {
+ // get keystore state - needs to be UNLOCKED
+ const updatedKeystoreState = FP.pipe(
+ getKeystoreState(),
+ O.chain(FP.flow(O.fromPredicate(isKeystoreUnlocked))),
+ // rename in state
+ O.map((state) => ({ ...state, name })),
+ O.toNullable
+ )
+
+ if (!updatedKeystoreState)
+ return Rx.of(RD.failure(Error(`Could not rename wallet with id ${id} - it seems to be locked`)))
+
+ // update selected wallet in list of wallets
+ const updatedWallets = FP.pipe(
+ getKeystoreWallets(),
+ A.map((wallet) => (id === wallet.id ? { ...wallet, name } : wallet))
+ )
+ return FP.pipe(
+ updatedWallets,
+ // encode wallets first
+ ipcKeystoreWalletsIO.encode,
+ // Save updated `wallets` to disk
+ (wallets) => Rx.from(window.apiKeystore.saveKeystoreWallets(wallets)),
+ RxOp.catchError((err) => Rx.of(RD.failure(err))),
+ RxOp.map(() => RD.success(true)),
+ liveData.map((_) => {
+ // Update states of all wallets
+ setKeystoreWallets(updatedWallets)
+ // set selected wallet - still unlocked
+ setKeystoreState(O.some(updatedKeystoreState))
+ return true
+ }),
+ RxOp.startWith(RD.pending)
+ )
+}
+
const importKeystore = async ({ keystore, password, name, id }: ImportKeystoreParams): Promise => {
try {
setImportingKeystoreState(RD.pending)
@@ -311,6 +350,7 @@ export const keystoreService: KeystoreService = {
addKeystoreWallet,
removeKeystoreWallet,
changeKeystoreWallet,
+ renameKeystoreWallet,
importKeystore,
exportKeystore,
loadKeystore$,
diff --git a/src/renderer/services/wallet/types.ts b/src/renderer/services/wallet/types.ts
index ad3307c10..3fba2d1ae 100644
--- a/src/renderer/services/wallet/types.ts
+++ b/src/renderer/services/wallet/types.ts
@@ -58,6 +58,10 @@ export type ImportingKeystoreStateLD = Rx.Observable
export type RemoveKeystoreWalletHandler = () => Promise
+export type RenameKeystoreWalletRD = RD.RemoteData
+export type RenameKeystoreWalletLD = LiveData
+export type RenameKeystoreWalletHandler = (id: KeystoreId, name: string) => RenameKeystoreWalletLD
+
export type ChangeKeystoreWalletRD = RD.RemoteData
export type ChangeKeystoreWalletLD = LiveData
export type ChangeKeystoreWalletHandler = (id: KeystoreId) => ChangeKeystoreWalletLD
@@ -67,6 +71,7 @@ export type KeystoreService = {
addKeystoreWallet: (params: AddKeystoreParams) => Promise
removeKeystoreWallet: RemoveKeystoreWalletHandler
changeKeystoreWallet: ChangeKeystoreWalletHandler
+ renameKeystoreWallet: RenameKeystoreWalletHandler
loadKeystore$: () => LoadKeystoreLD
importKeystore: (params: ImportKeystoreParams) => Promise
exportKeystore: () => Promise
diff --git a/src/renderer/views/wallet/WalletSettingsView.tsx b/src/renderer/views/wallet/WalletSettingsView.tsx
index baf5bf2a2..4eaacd197 100644
--- a/src/renderer/views/wallet/WalletSettingsView.tsx
+++ b/src/renderer/views/wallet/WalletSettingsView.tsx
@@ -69,7 +69,7 @@ export const WalletSettingsView: React.FC = (): JSX.Element => {
keystoreService: { exportKeystore, validatePassword$ }
} = useWalletContext()
- const { state: keystore, lock, remove, change$ } = useKeystoreState()
+ const { state: keystore, lock, remove, change$, rename$ } = useKeystoreState()
const { network } = useNetwork()
@@ -417,8 +417,9 @@ export const WalletSettingsView: React.FC = (): JSX.Element => {