From 4d67745ab63e3b760f10f4ee1065cae6504968f4 Mon Sep 17 00:00:00 2001 From: Chris Duncan Date: Fri, 25 Oct 2024 15:34:04 -0700 Subject: [PATCH] Lots of fixes to loading, selecting, and adding wallets and accounts. Account creation still throwing wallet lock error on second account. --- app/pages/nemo-wallet.html | 311 ++++++++++++++++++++----------------- 1 file changed, 167 insertions(+), 144 deletions(-) diff --git a/app/pages/nemo-wallet.html b/app/pages/nemo-wallet.html index 759d845..adb43b4 100644 --- a/app/pages/nemo-wallet.html +++ b/app/pages/nemo-wallet.html @@ -42,23 +42,12 @@ console.log('loading data') const walletSelect = document.querySelector('#wallet') const accountSelect = document.querySelector('#account') - const wallets = await getFromStorage('wallets') - for (const wallet of wallets) { - const { id, name, accounts } = JSON.parse(wallet) - const walletOption = new Option(name, id) - walletSelect.add(walletOption) - for (const a of accounts ?? []) { - const { id, name } = JSON.parse(a) - const accountOption = new Option(name, id) - accountSelect.add(accountOption) - } - } + await reloadWalletSelect() if (walletSelect.value.substring(0, 1) === '_') { walletSelect.value = '' - } else { - updateWalletSelect() } - if (accountSelect.value.substring(0, 1) === '_') { + await reloadAccountSelect() + if (walletSelect.value === '' || accountSelect.value.substring(0, 1) === '_') { accountSelect.setAttribute('disabled', '') accountSelect.value = '' } @@ -169,83 +158,91 @@ } } - async function updateWalletSelect () { - const select = document.querySelector('#wallet') - switch (select.value) { + async function selectWallet () { + const walletSelect = document.getElementById('wallet') + switch (walletSelect.value) { + case undefined: + case null: case '': { - await updateAccountSelect('') - return + break } case '_new': { try { - await document.querySelector('#wallet-new').showModal() + await document.getElementById('wallet-new').showModal() } catch (err) { - select.value = '' - notify.error(`Error creating wallet: ${err}`) + walletSelect.value = '' + console.error(err) + notify.error(`Error creating wallet`) } finally { - return + break } } case '_import': { try { - await document.querySelector('#wallet-import').showModal() + await document.getElementById('wallet-import').showModal() } catch (err) { - select.value = '' - notify.error(`Error importing wallet: ${err}`) + walletSelect.value = '' + console.error(err) + notify.error(`Error importing wallet`) } finally { - return + break } } case '_ledger': { try { - return await LedgerWallet.create() + await LedgerWallet.create() } catch (err) { - select.value = '' - notify.error(`Error importing wallet: ${err}`) - return + walletSelect.value = '' + console.error(err) + notify.error(`Error opening Ledger`) + } finally { + break } } default: { try { - const wallet = await loadWallet(select.value) - await updateAccountSelect(wallet) + await reloadAccountSelect() } catch (err) { - select.value = '' - notify.error(`Error loading wallet: ${err}`) - return + walletSelect.value = '' + console.error(err) + notify.error(`Error loading wallet accounts`) + } finally { + break } } } + return await selectAccount() } - async function loadWallet (walletId) { - walletId ??= document.querySelector('#wallet')?.value - if (!walletId) { - throw new TypeError(`Wallet ID not found`) - } + async function loadWallets () { const wallets = await getFromStorage('wallets') - const walletData = wallets.find(w => { - const { id, algorithm } = JSON.parse(w) - return id === walletId - }) - const { id, algorithm } = JSON.parse(walletData) - const walletClass = getWalletClass(algorithm) - const wallet = await walletClass.restore(id) - return wallet + return wallets.map(w => JSON.parse(w)) + } + + async function loadWallet () { + const walletSelect = document.getElementById('wallet') + if (walletSelect?.value) { + const wallets = await loadWallets() + const { id, algorithm } = wallets.find(w => w.id === walletSelect.value) + const walletClass = getWalletClass(algorithm) + const wallet = await walletClass.restore(id) + return wallet + } + throw new TypeError(`Wallet not found`) } async function createWallet () { - const walletSelect = document.querySelector('#wallet') - const form = document.querySelector('#wallet-new') - const name = form.querySelector('#wallet-new-name input').value + const walletSelect = document.getElementById('wallet') + const form = document.getElementById('wallet-new') + const name = document.getElementById('wallet-new-name-input').value if (name.substring(0, 1) === '_') { notify.error(`Wallet name cannot start with an underscore`) return } - const algorithm = form.querySelector('#wallet-new-algorithm select').value + const algorithm = document.getElementById('wallet-new-algorithm-select').value const walletClass = getWalletClass(algorithm) - const salt = form.querySelector('#wallet-new-salt input')?.value - const password = form.querySelector('#wallet-new-password input')?.value + const salt = document.getElementById('wallet-new-salt-input')?.value + const password = document.getElementById('wallet-new-password-input')?.value if (!password) { notify.error('Password is required') return @@ -260,10 +257,10 @@ } await addToStorage(`wallets`, JSON.stringify(walletData)) - const select = document.querySelector('#wallet') + const select = document.getElementById('wallet') const option = new Option(walletData.name, walletData.id, false, true) select.add(option) - await updateWalletSelect() + await selectWallet() } catch (err) { option?.remove() notify.error(err.msg) @@ -274,95 +271,141 @@ } function updateWalletForm (id) { - const form = document.querySelector(id) + const form = document.getElementById(id) if (!form) { notify.error(`Form ID not found, contact developer`) return } - const algorithmContainer = document.querySelector(`${id} -algorithm`) - const algorithm = document.querySelector(`${id} -algorithm select`) - const typeContainer = document.querySelector(`${id} -type`) - const type = document.querySelector(`${id} -type select`) - const saltContainer = document.querySelector(`${id} -salt`) - const salt = document.querySelector(`${id} -salt input`) + const algorithmContainer = document.getElementById(`${id}-algorithm`) + const algorithm = document.getElementById(`${id}-algorithm-select`) + const typeContainer = document.getElementById(`${id}-type`) + const type = document.getElementById(`${id}-type-select`) + const saltContainer = document.getElementById(`${id}-salt`) + const salt = document.getElementById(`${id}-salt-input`) if (algorithm.value === 'bip44' && type?.value !== 'seed') { saltContainer.classList.remove('hide') } else { saltContainer.classList.add('hide') } - const importValue = document.querySelector(`${id} -value input`) - const importValueLabel = document.querySelector(`${id} -value label`) + const importValue = document.getElementById(`${id}-value-input`) + const importValueLabel = document.querySelector(`${id}-value label`) if (importValueLabel) { importValueLabel.innerText = type.value } } - async function updateAccountSelect (wallet) { + async function selectAccount () { const accountSelect = document.querySelector('#account') - wallet ??= loadWallet() - if (wallet == null || wallet === '') { + const walletId = document.querySelector('#wallet')?.value + if (walletId == null || walletId === '') { accountSelect.value = '' accountSelect.setAttribute('disabled', '') return } - switch (accountSelect.value) { - case '': { - accountSelect.removeAttribute('disabled') + accountSelect.removeAttribute('disabled') + if (accountSelect.value === '_new') { + try { + return await document.querySelector('#account-new').showModal() + } catch (err) { + accountSelect.value = '' + console.error(err) + notify.error(`Error creating account`) return } - case '_new': { - try { - return await document.querySelector('#account-new').showModal() - } catch (err) { - accountSelect.value = '' - notify.error(`Error creating account: ${err}`) - return + } + } + + async function reloadWalletSelect () { + const wallets = await loadWallets() + const walletOptions = wallets.map(w => { + return { text: w.name, value: w.id } + }) + await resetSelectOptions('wallet', walletOptions) + } + + async function reloadAccountSelect () { + const accounts = await loadAccounts() + const accountOptions = accounts.map(a => { + return { text: a.name, value: a.index } + }) + await resetSelectOptions('account', accountOptions) + } + + async function resetSelectOptions (id, options) { + try { + if (!Array.isArray(options)) { + options = [options] + } + const select = document.getElementById(id) + if (!select) { + throw new TypeError(`Select ${id} not found`) + } + const oldOptions = [select.children].filter(o => o.tagName === 'option') + for (const oldOption of oldOptions) { + if (oldOption.value.substring(0, 1) === '_') { + oldOption.remove() } } - default: { - accountSelect.removeAttribute('disabled') - return await wallet.accounts(accountSelect.value) + const newOptions = options.map(o => new Option(o.text, o.value)) + if (newOptions.length > 0) { + select.add(...newOptions) } + } catch (err) { + console.error(err) + notify.error(`Error resetting options for select ${id}`) } } - async function createAccount (wallet) { - const accountSelect = document.querySelector('#account') + async function loadAccounts () { + walletSelect = document.getElementById('wallet') + if (walletSelect?.value) { + const accounts = await getFromStorage('accounts') + const accountData = accounts.filter(a => { + console.log(JSON.parse(a)) + const { walletId } = JSON.parse(a) + return walletId === walletSelect.value + }) + return accountData + } + return [] + } + + async function createAccount () { + let account, option, wallet + const accountSelect = document.getElementById('account') try { - wallet ??= await loadWallet() + wallet = await loadWallet() } catch (err) { - notify.error(`Error creating account: ${err}`) + console.error(err) + notify.error(`Error creating account`) return } - const form = document.querySelector('#account-new') - const name = form.querySelector('#account-new-name input').value - if (name.substring(0, 1) === '_') { + const form = document.getElementById('account-new') + const name = document.getElementById('account-new-name-input')?.value + if (name?.substring(0, 1) === '_') { notify.error(`Account name cannot start with an underscore`) return } - const index = form.querySelector('#account-new-index input')?.value - const password = form.querySelector('#account-new-password input')?.value + const index = document.getElementById('account-new-index-input')?.value + const password = document.getElementById('account-new-password-input')?.value try { - console.log(`locked wallet: ${wallet}`) - const unlockResult = await wallet.unlock(password) - console.log(`unlockResult: ${unlockResult}`) - console.log(`unlocked wallet: ${wallet}`) - const account = await wallet.accounts(index) - console.log(`account: ${account}`) - const lockResult = await wallet.lock(password) - console.log(`lockResult: ${lockResult}`) - console.log(`locked wallet: ${wallet}`) + await wallet.unlock(password) + const account = await wallet.accounts(+index) + await wallet.lock(password) const accountData = { - id: index, - name: name || index + walletId: wallet.id, + index: account.index, + name: `${index}${name ? ': ' : ''}${name}` } await addToStorage(`accounts`, JSON.stringify(accountData)) - const option = new Option(accountData.name, accountData.id, false, true) - select.add(option) - await updateAccountSelect(wallet) + option = new Option(accountData.name, accountData.id, false, true) + accountSelect.add(option) + await selectAccount() } catch (err) { + accountSelect.value = '' option?.remove() - notify.error(err.msg) + console.error(err) + notify.error(`Error creating account`) } finally { await form.close() return account @@ -370,43 +413,23 @@ } async function cancelDialog (id) { - const dialog = document.getElementById(id) - const fields = dialog.querySelectorAll('input, select') + await resetDialogInputs() + await document.getElementById(id).close() + } + + async function resetDialogInputs () { + const fields = document.querySelectorAll('dialog input, dialog select') for (const field of fields) { field.value = '' } - const wallet = document.querySelector('#wallet') + const wallet = document.getElementById('wallet') if (wallet.value.substring(0, 1) === '_') { wallet.value = '' } - const account = document.querySelector('#account') - if (account.value.substring(0, 1) === '_') { + const account = document.getElementById('account') + if (wallet.value === '' || account.value.substring(0, 1) === '_') { account.value = '' } - await dialog.close() - } - - async function showWallets () { - const card = document.querySelector('#walletCard') - const storedWalletData = JSON.parse(sessionStorage.getItem('wallets') ?? '[]') - const wallets = [] - for (const walletData of storedWalletData) { - const w = JSON.parse(walletData) - console.dir(w) - if (w.id && w.name && w.type) { - const walletType = getWalletClass(w.type) - wallets.push(await walletType.restore(w.id)) - } - } - const walletElements = [] - for (const wallet of wallets) { - const walletElement = document.createElement('label') - await wallet.unlock('password') - walletElement.innerText = `${wallet.name}: ${wallet.mnemonic} ` - await wallet.lock('password') - walletElements.push(walletElement) - } - card.replaceChildren(...walletElements) } async function clearStorage () { @@ -421,7 +444,7 @@ } document.querySelector('#wallet').value = '' document.querySelector('#account').value = '' - await updateWalletSelect() + await selectWallet() notify.ok(`Session storage cleared`) btn.removeAttribute('disabled') } @@ -688,7 +711,7 @@
-
@@ -711,7 +734,7 @@
+ onchange="updateWalletForm('wallet-import')" required> @@ -757,7 +780,7 @@
+ + max="2147483647" required value="0" />
@@ -823,7 +846,7 @@
+ onclick="createAccount().then(a => { console.log(a) })">OK
-- 2.34.1