]> zoso.dev Git - nemo-wallet.git/commitdiff
Lots of fixes to loading, selecting, and adding wallets and accounts. Account creatio...
authorChris Duncan <chris@zoso.dev>
Fri, 25 Oct 2024 22:34:04 +0000 (15:34 -0700)
committerChris Duncan <chris@zoso.dev>
Fri, 25 Oct 2024 22:34:04 +0000 (15:34 -0700)
app/pages/nemo-wallet.html

index 759d845201e72c55d3244e4d3c7afdb35d2211e4..adb43b454ec4ee5c46b7ff6026cbac188414d368 100644 (file)
                        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 = ''
                        }
                        }
                }
 
-               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
                                }
                                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)
                }
 
                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
                }
 
                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 () {
                        }
                        document.querySelector('#wallet').value = ''
                        document.querySelector('#account').value = ''
-                       await updateWalletSelect()
+                       await selectWallet()
                        notify.ok(`Session storage cleared`)
                        btn.removeAttribute('disabled')
                }
 
                <div id="wallets" class="grid-x">
                        <label for="wallet" class="grid x-3">Wallet</label>
-                       <select id="wallet" class="grid x-9" onchange="updateWalletSelect()">
+                       <select id="wallet" class="grid x-9" onchange="selectWallet()">
                                <option disabled selected value>Choose...</option>
                                <hr />
                                <option value="_new">New</option>
                                <div id="wallet-new-algorithm" class="flex x-left x-mid">
                                        <label for="wallet-new-algorithm-select">Algorithm</label>
                                        <select id="wallet-new-algorithm-select" name="wallet-new-algorithm" autocomplete="off"
-                                               onchange="updateWalletForm('#wallet-new')" required>
+                                               onchange="updateWalletForm('wallet-new')" required>
                                                <option disabled selected value>Choose...</option>
                                                <option value="bip44">BIP-44</option>
                                                <option value="blake2b">BLAKE2b</option>
                                <div id="wallet-import-algorithm" class="flex x-left x-mid">
                                        <label for="wallet-import-algorithm-select">Algorithm</label>
                                        <select id="wallet-import-algorithm-select" name="wallet-import-algorithm" autocomplete="off"
-                                               onchange="updateWalletForm('#wallet-import')" required>
+                                               onchange="updateWalletForm('wallet-import')" required>
                                                <option disabled selected value>Choose...</option>
                                                <option value="bip44">BIP-44</option>
                                                <option value="blake2b">BLAKE2b</option>
                                <div id="wallet-import-type" class="flex x-left x-mid hide">
                                        <label for="wallet-import-type-select">Type</label>
                                        <select id="wallet-import-type-select" name="wallet-import-type" autocomplete="off"
-                                               onchange="updateWalletForm('#wallet-import')" required>
+                                               onchange="updateWalletForm('wallet-import')" required>
                                                <option disabled selected value>Choose...</option>
                                                <option value="mnemonic">Import mnemonic</option>
                                                <option value="seed">Import seed</option>
                                        <div class="grid x-4"></div>
                                        <button id="wallet-import-cancel" class="cancel grid x-4">Cancel</button>
                                        <button id="wallet-import-ok" class="grid x-4"
-                                               onclick="importWallet().then(w => { console.log(w);showWallets() })">OK</button>
+                                               onclick="importWallet().then(w => { console.log(w) })">OK</button>
                                </div>
                        </div>
                </dialog>
 
                <div id="accounts" class="grid-x">
                        <label for="account" class="grid x-3">Account</label>
-                       <select id="account" class="grid x-9" disabled onchange="updateAccountSelect()">
+                       <select id="account" class="grid x-9" disabled onchange="selectAccount()">
                                <option disabled selected value>Choose...</option>
                                <hr />
                                <option value="_new">New</option>
                                <div id="account-new-index" class="flex x-left x-mid">
                                        <label for="account-new-index-input">Index</label>
                                        <input id="account-new-index-input" name="account-new-index" type="number" autocomplete="off" min="0"
-                                               max="2147483647" required />
+                                               max="2147483647" required value="0" />
                                </div>
                                <div id="account-new-password" class="flex x-left x-mid">
                                        <label for="account-new-password-input">Unlock</label>
                                        <div class="grid x-4"></div>
                                        <button id="account-new-cancel" class="cancel grid x-4">Cancel</button>
                                        <button id="account-new-ok" class="grid x-4"
-                                               onclick="createAccount().then(w => { console.log(w) })">OK</button>
+                                               onclick="createAccount().then(a => { console.log(a) })">OK</button>
                                </div>
                        </div>
                </dialog>