From 778d8c87aeac9b05daa1c20cb6b1490998aa8ead Mon Sep 17 00:00:00 2001 From: jojobyte <184880+jojobyte@users.noreply.github.com> Date: Thu, 26 Oct 2023 06:43:46 -0600 Subject: [PATCH] fix(ui): :bug: improve reactivity of contacts & qr code --- TODO.md | 12 +- src/components/contacts-list.js | 36 ++- src/helpers/constants.js | 31 +++ src/helpers/utils.js | 236 ++++++++++++++++- src/helpers/wallet.js | 30 +-- src/main.js | 190 ++++++++------ src/rigs/add-contact.js | 321 ++++++++++++++--------- src/rigs/{profile.js => edit-profile.js} | 58 ++-- src/rigs/scan.js | 11 +- src/rigs/wallet-encrypt.js | 8 +- 10 files changed, 645 insertions(+), 288 deletions(-) create mode 100644 src/helpers/constants.js rename src/rigs/{profile.js => edit-profile.js} (78%) diff --git a/TODO.md b/TODO.md index e497d04..1bd8fb1 100644 --- a/TODO.md +++ b/TODO.md @@ -15,10 +15,14 @@ - [ ] Dialogs - [x] Send - [x] Request - - [ ] QR Code - - [ ] Share - - [ ] Scan - - [ ] Add a Contact + - [x] QR Code + - [x] Share + - [x] Scan + - [x] Add a Contact + - [x] Share QR Code not getting up to date name for Profile + - [x] Changing alias field removes wallet from localForage contact + - [x] `Finish pairing` contact in contacts list after save. + - should just be named contact - [ ] Send & Request Funds to / from Contact - [ ] Fiat balance from: - https://rates2.dashretail.org/rates?source=dashretail&%7B%7D= diff --git a/src/components/contacts-list.js b/src/components/contacts-list.js index c9fae38..79422ca 100644 --- a/src/components/contacts-list.js +++ b/src/components/contacts-list.js @@ -1,5 +1,9 @@ import { lit as html } from '../helpers/lit.js' -import { envoy, restate, } from '../helpers/utils.js' +import { + envoy, + restate, + sortContactsByAlias, +} from '../helpers/utils.js' // import { updateAllFunds, } from '../helpers/wallet.js' function getAvatar(info) { @@ -68,7 +72,7 @@ const initialState = { ${state.footer(state)} `, item: c => { - let user = c.info?.preferred_username + let user = c.alias || c.info?.preferred_username let name = c.info?.name let itemAlias = user @@ -110,16 +114,16 @@ const initialState = { ) }, handleContactsChange: (newState, oldState) => { - console.log( - 'handle contacts update', - {newState, oldState} - ) - // if ( - // newState?.walletFunds?.balance !== - // oldState?.walletFunds?.balance - // ) { - // newState.elements.figure.innerHTML = newState.content(newState) - // } + if (newState.contacts !== oldState.contacts) { + console.log( + 'handle contacts update', + {newState, oldState} + ) + + newState.render?.({ + contacts: newState.contacts?.sort(sortContactsByAlias), + }) + } } }, } @@ -132,6 +136,10 @@ let state = envoy( export async function setupContactsList( el, setupState = {} ) { + console.log( + 'setupContactsList state.contacts', + state.contacts + ) restate(state, setupState) // if (setupState?.events?.handleContactsChange) { // state._listeners = [ @@ -188,7 +196,7 @@ export async function setupContactsList( state.removeAllListeners = removeAllListeners - async function render ( + async function render( renderState = {}, position = 'afterbegin', ) { @@ -211,7 +219,7 @@ export async function setupContactsList( return { element: section, render, - restate, + restate: async newState => await restate(state, newState), } } diff --git a/src/helpers/constants.js b/src/helpers/constants.js new file mode 100644 index 0000000..078f6ca --- /dev/null +++ b/src/helpers/constants.js @@ -0,0 +1,31 @@ + +export const STOREAGE_SALT = 'b9f4088bd3a93783147e3d78aa10cc911a2449a0d79a226ae33a5957b368cc18' + +export const DUFFS = 100000000; + +export const OIDC_CLAIMS = { + preferred_username: '', + name: '', // [given_name,middle_name,family_name].join(' ') + given_name: '', + family_name: '', + middle_name: '', + nickname: '', + website: '', + address: {}, + email: '', + email_verified: false, + phone_number: '', + phone_number_verified: false, + profile: '', // 'https://imgur.com/gallery/y6sSvCr.json', + picture: '', // 'https://i.imgur.com/y6sSvCr.jpeg', // url to avatar img + sub: '', + xpub: '', + updated_at: (new Date()).toISOString(), +} + +export const PHRASE_REGEX = new RegExp( + /^([a-zA-Z]+\s){11,}([a-zA-Z]+)$/ +) +export const ALIAS_REGEX = new RegExp( + /^[a-zA-Z0-9]{1,}$/ +) \ No newline at end of file diff --git a/src/helpers/utils.js b/src/helpers/utils.js index de6ea42..63e08c3 100644 --- a/src/helpers/utils.js +++ b/src/helpers/utils.js @@ -3,6 +3,8 @@ import { DashPhrase, } from '../imports.js' +import { DUFFS } from './constants.js' + // export async function walletSchema( // phrase = 'zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong', // accountIndex = 0 @@ -223,8 +225,6 @@ export function phraseToEl(phrase, el = 'span', cls = 'tag') { )?.join(' ') } -export const DUFFS = 100000000; - /** * @param {Number} duffs - ex: 00000000 * @param {Number} [fix] - value for toFixed - ex: 8 @@ -312,6 +312,38 @@ export function setClipboard(event) { ); } +/** + * Creates a `Proxy` wrapped object with optional listeners + * that react to changes + * + * @example + * let fooHistory = [] + * + * let kung = envoy( + * { foo: 'bar' }, + * function firstListener(state, oldState) { + * if (state.foo !== oldState.foo) { + * localStorage.foo = state.foo + * }, + * }, + * async function secondListener(state, oldState) { + * if (state.foo !== oldState.foo) { + * fooHistory.push(oldState.foo) + * } + * } + * ) + * kung.foo = 'baz' + * console.log(localStorage.foo) // 'baz' + * kung.foo = 'boo' + * console.log(fooHistory) // ['bar','baz'] + * + * @param {Object} obj + * @param {...( + * state: any, oldState: any, prop: string | symbol + * ) => void | Promise?} [initListeners] + * + * @returns {obj} + */ export function envoy(obj, ...initListeners) { let _listeners = [...initListeners] return new Proxy(obj, { @@ -332,7 +364,8 @@ export function envoy(obj, ...initListeners) { _listeners.forEach( fn => fn( {...obj, [prop]: value}, - obj + obj, + prop ) ) @@ -460,4 +493,199 @@ export function parseAddressField(uri) { // } return result -} \ No newline at end of file +} + +export function isEmpty(value) { + if (value === null) { + return true + } + // if (typeof value === 'boolean' && value === false) { + // return true + // } + if (typeof value === 'string' && value?.length === 0) { + return true + } + if (typeof value === 'object' && Object.keys(value)?.length === 0) { + return true + } + if (Array.isArray(value) && value.length === 0) { + return true + } + return false; +} + +export function generateShareURI(state, protocol = 'web+dash') { + let claims = [ + ["xpub", state.wallet?.xpub || ''], + ["sub", state.wallet?.xkeyId || ''], + ] + + if (state.userInfo) { + let filteredInfo = Array.from(Object.entries(state.userInfo)) + .filter(p => { + let [key, val] = p + if ( + ![ + 'updated_at', + 'email_verified', + 'phone_number_verified', + ].includes(key) && + !isEmpty(val) + ) { + return true + } + }) + + claims = [ + ...claims, + ...filteredInfo, + ] + } + + let scope = claims.map(p => p[0]).join(',') + + console.log('Generate QR claims', claims, scope) + + return new URL( + `${protocol}://?${ + new URLSearchParams([ + ...claims, + ['scope', scope] + ]) + }` + ) +} + +export async function loadStore(store, callback) { + // let storeLen = await store.length() + let result = [] + + return await store.iterate((v, k, i) => { + result.push(v) + + // if (i === storeLen) { + // return result + // } + }) + .then(() => callback(result)) + .catch(err => { + console.error('loadStore', err) + return null + }); +} + +export async function loadStoreObject(store, callback) { + // let storeLen = await store.length() + let result = {} + + return await store.iterate((v, k, i) => { + result[k] = v + + // if (i === storeLen) { + // return result + // } + }) + .then(() => callback(result)) + .catch(err => { + console.error('loadStoreObject', err) + return null + }); +} + +/** + * promise debounce changes + * + * https://www.freecodecamp.org/news/javascript-debounce-example/ + * + * @example + * const change = debounce((a) => console.log('Saving data', a)); + * change('b');change('c');change('d'); + * 'Saving data d' + * + * @param {(...args) => void} callback + * @param {number} [delay] +* +* @returns {Promise} +*/ +export async function debouncePromise(callback, delay = 300) { + let timer + + return await new Promise(resolve => async (...args) => { + clearTimeout(timer) + + timer = setTimeout(() => { + resolve(callback.apply(this, args)) + }, delay) + }) + + // return async (...args) => { + // clearTimeout(timer) + + // timer = resolve => setTimeout(() => { + // resolve(callback.apply(this, args)) + // }, delay) + + // return await new Promise(timer) + // } +} + +/** + * debounce changes + * + * https://www.freecodecamp.org/news/javascript-debounce-example/ + * + * @example + * const change = debounce((a) => console.log('Saving data', a)); + * change('b');change('c');change('d'); + * 'Saving data d' + * + * @param {(...args) => void} callback + * @param {number} [delay] +* +* @returns {(...args) => void} +*/ +export function debounce(callback, delay = 300) { + let timer + + return (...args) => { + clearTimeout(timer) + + timer = setTimeout(() => { + return callback.apply(this, args) + }, delay) + + return timer + } +} + +/** + * debounce that immediately triggers and black holes any extra + * executions within the time delay + * + * https://www.freecodecamp.org/news/javascript-debounce-example/ + * + * @example + * const dry = nobounce((a) => console.log('Saving data', a)); + * dry('b');dry('c');dry('d'); + * 'Saving data b' + * + * @param {(...args) => void} callback + * @param {number} [delay] +* +* @returns {(...args) => void} +*/ +export function nobounce(callback, delay = 300) { + let timer + + return (...args) => { + if (!timer) { + callback.apply(this, args) + } + + clearTimeout(timer) + + timer = setTimeout(() => { + timer = undefined + }, delay) + } +} diff --git a/src/helpers/wallet.js b/src/helpers/wallet.js index 3454666..c701a55 100644 --- a/src/helpers/wallet.js +++ b/src/helpers/wallet.js @@ -4,8 +4,7 @@ import { Cryptic, } from '../imports.js' import { DatabaseSetup } from './db.js' - -const STOREAGE_SALT = 'b9f4088bd3a93783147e3d78aa10cc911a2449a0d79a226ae33a5957b368cc18' +import { STOREAGE_SALT, OIDC_CLAIMS } from './constants.js' // @ts-ignore let dashsight = DashSight.create({ @@ -34,10 +33,9 @@ export async function loadWallets() { export async function loadWalletsForAlias(alias) { let $alias = await store.aliases.getItem(alias) + $alias.$wallets = {} - if ($alias !== null) { - $alias.$wallets = {} - + if ($alias?.wallets) { for (let w of $alias.wallets) { let wallet = await store.wallets.getItem(w) $alias.$wallets[w] = wallet @@ -52,26 +50,8 @@ export async function initWalletsInfo( ) { let wallets = await loadWallets() - let initInfo = { - preferred_username: '', - name: '', // [given_name,middle_name,family_name].join(' ') - // given_name: '', - // family_name: '', - // middle_name: '', - nickname: '', - website: '', - phone_number: '', - address: '', - email: '', // gravatar? - // profile: 'https://imgur.com/gallery/y6sSvCr.json', - // picture: 'https://i.imgur.com/y6sSvCr.jpeg', // url to avatar img - sub: '', - xpub: '', - updated_at: (new Date()).toISOString(), - } - info = { - ...initInfo, + ...OIDC_CLAIMS, ...info, } @@ -354,4 +334,4 @@ export async function batchAddressGenerate( addresses, finalAddressIndex: addressIndex, } -} \ No newline at end of file +} diff --git a/src/main.js b/src/main.js index b8cdb2c..fdde31f 100644 --- a/src/main.js +++ b/src/main.js @@ -7,9 +7,16 @@ import { phraseToEl, envoy, sortContactsByAlias, + loadStore, // sortContactsByName, } from './helpers/utils.js' +import { + OIDC_CLAIMS, + ALIAS_REGEX, + PHRASE_REGEX, +} from './helpers/constants.js' + import { batchAddressGenerate, updateAllFunds, @@ -29,7 +36,7 @@ import setupInputAmount from './components/input-amount.js' import walletEncryptRig from './rigs/wallet-encrypt.js' import addContactRig from './rigs/add-contact.js' -import editProfileRig from './rigs/profile.js' +import editProfileRig from './rigs/edit-profile.js' import scanContactRig from './rigs/scan.js' // Example Dash URI's @@ -37,27 +44,26 @@ import scanContactRig from './rigs/scan.js' // let testDashReqUri = `dash:XYZdashAddressZYX?amount=0.50000000&label=test&message=give me monies` // let testDashExtUri = `web+dash://?xpub=xpub6FKUF6P1ULrfvSrhA9DKSS3MA3digsd27MSTMjBxCczsfYz7vcFLnbQwjP9CsAfEJsnD4UwtbU43iZaibv4vnzQNZmQAVcufN4r3pva8kTz&sub=01H5KG2NGES5RVMA85YB3M6G0G&nickname=Prime%208&profile=https://imgur.com/gallery/y6sSvCr.json&picture=https://i.imgur.com/y6sSvCr.jpeg&scope=sub,nickname,profile,xpub&redirect_uri=https://` -// form validation -const phraseRegex = new RegExp( - /^([a-zA-Z]+\s){11,}([a-zA-Z]+)$/ -) -const aliasRegex = new RegExp( - /^[a-zA-Z0-9]{1,}$/ -) - // app/data state let wallets let wallet +let userInfo let appState = envoy( { phrase: null, encryptionPassword: null, - selected_wallet: '', - selected_alias: '', + selectedWallet: '', + selectedAlias: '', + aliasInfo: {}, contacts: [], }, (state, oldState) => { - if (state.foo !== oldState.bar) { + if (state.contacts !== oldState.contacts) { + console.log( + 'state.contacts !== oldState.contacts on push', + oldState.contacts, + state.contacts, + ) } } ) @@ -97,9 +103,8 @@ let contactsList = await setupContactsList( event.target?.id === 'add_contact' || event.target?.parentNode?.id === 'add_contact' ) { - let aliasWallets = await loadWalletsForAlias(appState.selected_alias) - wallets = aliasWallets?.$wallets - let selectedWallet = wallets?.[appState.selected_wallet] + await getUserInfo() + let selectedWallet = wallets?.[appState.selectedWallet] let accountIndex = selectedWallet ?.accountIndex || 0 @@ -118,13 +123,13 @@ let contactsList = await setupContactsList( if (selectedWallet) { let upWallet = await store.wallets.setItem( - appState.selected_wallet, + appState.selectedWallet, { ...selectedWallet, accountIndex, } ) - wallets[appState.selected_wallet] = upWallet + wallets[appState.selectedWallet] = upWallet } shareAccount = await deriveWalletData( @@ -162,7 +167,10 @@ let contactsList = await setupContactsList( appState.contacts.sort(sortContactsByAlias) ) - // loadContacts(res => contactsList.render(res)) + // await loadStore( + // store.contacts, + // res => contactsList.render(res) + // ) console.log( 'share qr new contact', @@ -174,6 +182,7 @@ let contactsList = await setupContactsList( { wallet: shareAccount, contact: newContact, + userInfo, }, 'afterend', ) @@ -327,7 +336,7 @@ let walletGen = setupDialog( id="${state.slugs.form}_alias" name="alias" placeholder="your_alias" - pattern="${aliasRegex.source}" + pattern="${ALIAS_REGEX.source}" required spellcheck="false" /> @@ -358,11 +367,11 @@ let walletGen = setupDialog( wallet = await deriveWalletData() appState.phrase = wallet.recoveryPhrase - appState.selected_wallet = wallet.id - appState.selected_alias = `${fde.alias}` + appState.selectedWallet = wallet.id + appState.selectedAlias = `${fde.alias}` - localStorage.selected_wallet = appState.selected_wallet - localStorage.selected_alias = appState.selected_alias + localStorage.selectedWallet = appState.selectedWallet + localStorage.selectedAlias = appState.selectedAlias // console.log('GENERATE wallet!', wallet) @@ -419,7 +428,7 @@ let walletImp = setupDialog( id="phrase" name="pass" placeholder="zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo zoo wrong" - pattern="${phraseRegex.source}" + pattern="${PHRASE_REGEX.source}" required spellcheck="false" /> @@ -449,7 +458,7 @@ let walletImp = setupDialog( id="${state.slugs.form}_alias" name="alias" placeholder="your_alias" - pattern="${aliasRegex.source}" + pattern="${ALIAS_REGEX.source}" required spellcheck="false" /> @@ -489,11 +498,11 @@ let walletImp = setupDialog( wallet = await deriveWalletData(appState.phrase) - appState.selected_alias = `${fde.alias}` - appState.selected_wallet = wallet.id + appState.selectedAlias = `${fde.alias}` + appState.selectedWallet = wallet.id - localStorage.selected_wallet = appState.selected_wallet - localStorage.selected_alias = appState.selected_alias + localStorage.selectedWallet = appState.selectedWallet + localStorage.selectedAlias = appState.selectedAlias // console.log('IMPORT wallet!', wallet) @@ -730,31 +739,43 @@ let sendOrRequest = setupDialog( } ) -async function loadContacts(callback) { - let conLen = await store.contacts.length() - return await store.contacts.iterate(function( - v, key, iterationNumber - ) { - appState.contacts.push(v) +async function getUserInfo() { + if (appState.selectedAlias) { + console.log( + 'getUserInfo selectedAlias', + appState.selectedAlias, + // appState + ) + let { $wallets, ...$userInfo } = await loadWalletsForAlias( + appState.selectedAlias + ) + wallets = $wallets - if (iterationNumber === conLen) { - return appState.contacts - } - }) - .then(callback) - // .then(function(result) { - // // console.log( - // // 'Iteration has completed, last iterated pair:' - // // ); - // // console.log(result); - - // contactsList.render(appState) - // }) - .catch(err => { - console.error('loadContacts', err) - return null - }); + userInfo = envoy( + { + ...OIDC_CLAIMS, + ...($userInfo?.info || {}), + }, + async (state, oldState, prop) => { + if (state[prop] !== oldState[prop]) { + let $aliases = await store.aliases.getItem( + appState.selectedAlias, + ) + store.aliases.setItem( + appState.selectedAlias, + { + ...$aliases, + info: { + ...$aliases.info, + [prop]: state[prop], + }, + } + ) + } + } + ) + } } @@ -762,54 +783,50 @@ async function main() { appState.encryptionPassword = window.atob( sessionStorage.encryptionPassword || '' ) - appState.selected_wallet = localStorage?.selected_wallet || '' - appState.selected_alias = localStorage?.selected_alias || '' + appState.selectedWallet = localStorage?.selectedWallet || '' + appState.selectedAlias = localStorage?.selectedAlias || '' - let aliasWallets = await loadWalletsForAlias(appState.selected_alias) - wallets = aliasWallets?.$wallets + await getUserInfo() - let accountIndex = wallets?.[appState.selected_wallet] + let accountIndex = wallets?.[appState.selectedWallet] ?.accountIndex || 0 bodyNav = await setupNav( mainApp, { data: { - alias: appState.selected_alias + alias: appState.selectedAlias }, } ) walletEncrypt = walletEncryptRig({ mainApp, setupDialog, appState, - wallet, wallets, - bodyNav, dashBalance, onboard, - }) - - editProfile = editProfileRig({ - mainApp, setupDialog, appState, - wallet, wallets, store, aliasWallets, bodyNav, dashBalance, onboard, + wallet, wallets, }) scanContact = scanContactRig({ mainApp, setupDialog, appState, - wallet, wallets, - bodyNav, dashBalance, onboard, }) addContact = addContactRig({ mainApp, setupDialog, appState, - wallet, wallets, aliasWallets, - bodyNav, dashBalance, onboard, + wallet, wallets, userInfo, scanContact, contactsList, store, }) + editProfile = editProfileRig({ + mainApp, setupDialog, appState, + wallet, wallets, store, + bodyNav, userInfo, + }) + svgSprite.render() console.log( 'load wallet alias', - aliasWallets + userInfo ) document.addEventListener('submit', async event => { @@ -854,11 +871,11 @@ async function main() { } }) - let ks_phrase = wallets?.[appState.selected_wallet] + let ks_phrase = wallets?.[appState.selectedWallet] ?.keystore?.crypto?.ciphertext || '' - let ks_iv = wallets?.[appState.selected_wallet] + let ks_iv = wallets?.[appState.selectedWallet] ?.keystore?.crypto?.cipherparams?.iv || '' - let ks_salt = wallets?.[appState.selected_wallet] + let ks_salt = wallets?.[appState.selectedWallet] ?.keystore?.crypto?.kdfparams?.salt || '' if (appState.encryptionPassword) { @@ -926,6 +943,8 @@ async function main() { appState.phrase = decryptedRecoveryPhrase appState.encryptionPassword = fde.pass + await getUserInfo() + if (fde.remember) { sessionStorage.encryptionPassword = window.btoa(String(appState.encryptionPassword)) } @@ -986,19 +1005,31 @@ async function main() { bodyNav.render({ data: { - alias: appState.selected_alias + alias: appState.selectedAlias }, }) mainFtr.render() - // await store.contacts.setItem() - await loadContacts( - res => contactsList.render( - res?.sort(sortContactsByAlias) - ) + await loadStore( + store.contacts, + res => { + console.log( + 'loadStore store.contacts', + res, + ) + if (res) { + appState.contacts = res + + return contactsList.render({ + contacts: res?.sort(sortContactsByAlias), + userInfo, + }) + } + } ) await contactsList.render({ + userInfo, contacts: appState.contacts }) sendRequestBtn.render() @@ -1036,6 +1067,7 @@ async function main() { editProfile.render( { wallet: shareAccount, + userInfo, }, 'afterend', ) diff --git a/src/rigs/add-contact.js b/src/rigs/add-contact.js index 23903fa..82c9506 100644 --- a/src/rigs/add-contact.js +++ b/src/rigs/add-contact.js @@ -7,27 +7,84 @@ import { sortContactsByAlias, // sortContactsByName, parseAddressField, + generateShareURI, + loadStore, + debounce, + nobounce, } from '../helpers/utils.js' -const aliasRegex = new RegExp( - /^[a-zA-Z0-9_\-\.]{1,}$/ -) +import { + OIDC_CLAIMS, + ALIAS_REGEX, +} from '../helpers/constants.js' export let addContactRig = (function (globals) { 'use strict'; let { - setupDialog, mainApp, wallet, wallets, - appState, bodyNav, dashBalance, onboard, - scanContact, contactsList, store, aliasWallets, + setupDialog, mainApp, wallet, + appState, userInfo, + scanContact, contactsList, store, } = globals; + let debounceAlias = debounce(async (state, event) => { + let { preferred_username } = state.contact.info + preferred_username = preferred_username || event.target?.value || '' + let alias = event.target?.value || preferred_username || '' + + let newContact = await store.contacts.setItem( + // state.wallet.id, + state.wallet.xkeyId, + { + ...state.contact, + info: { + ...OIDC_CLAIMS, + ...(state.contact.info || {}), + preferred_username, + }, + alias, + } + ) + + state.contact = newContact + + // let contactExists = appState.contacts.findIndex( + // c => c.info?.preferred_username === newContact.info?.preferred_username + // ) + // if (contactExists > -1) { + // appState.contacts[contactExists] = newContact + // } else { + // appState.contacts.push(newContact) + // } + + // contactsList.render( + // appState.contacts.sort(sortContactsByAlias) + // ) + + loadStore( + store.contacts, + res => { + if (res) { + appState.contacts = res + + return contactsList.restate({ + contacts: res?.sort(sortContactsByAlias), + userInfo, + }) + } + } + ) + // console.log( + // '+contact handleChange newContact', + // newContact + // ) + }) + let addContact = setupDialog( mainApp, { name: 'Add a New Contact', - submitTxt: html` - + submitTxt: html` Add Contact`, submitAlt: 'Add Contact', @@ -50,43 +107,39 @@ export let addContactRig = (function (globals) { `, + generateQr: state => { + let shareURI = generateShareURI(state, 'web+dash') + let shareLink = shareURI.toString() + + return { + uri: shareURI, + link: shareLink, + svg: qrSvg( + shareLink, + { + background: '#0000', + color: 'currentColor', + indent: 1, + padding: 1, + size: 'mini', + container: 'svg-viewbox', + join: true, + } + ) + } + }, content: state => { - let shareParams = new URLSearchParams([ - ["xpub", state.wallet?.xpub || ''], - [ - 'name', - aliasWallets?.info?.name || '' - ], - [ - 'preferred_username', - appState.selected_alias || '' - ], - ["sub", state.wallet?.xkeyId || ''], - ['scope', 'sub,name,preferred_username,xpub'] - ]); - let shareURI = new URL(`web+dash://?${shareParams}`) - + let { link, svg } = state.generateQr(state) return html` ${state.header(state)} Copy URI @@ -150,7 +203,7 @@ export let addContactRig = (function (globals) { id="${state.slugs.form}_alias" name="contactAlias" placeholder="your_alias" - pattern="${aliasRegex.source}" + pattern="${ALIAS_REGEX.source}" spellcheck="false" /> @@ -223,6 +276,7 @@ export let addContactRig = (function (globals) { { ...state.contact, info: { + ...OIDC_CLAIMS, ...(state.contact.info || {}), ...info, }, @@ -236,9 +290,26 @@ export let addContactRig = (function (globals) { xpub, }, }, + alias: preferred_username, + } + ) + + loadStore( + store.contacts, + res => { + if (res) { + appState.contacts = res + + return contactsList.restate({ + contacts: res?.sort(sortContactsByAlias), + userInfo, + }) + } } ) + state.contact = newContact + if (xkeyOrAddr) { event.target.form.contactAddr.value = xkeyOrAddr } @@ -250,59 +321,36 @@ export let addContactRig = (function (globals) { } } } - }, - handleChange: state => async event => { - event.preventDefault() - if ( - event?.target?.validity?.patternMismatch && - event?.target?.type !== 'checkbox' - ) { - let label = event.target?.previousElementSibling?.textContent?.trim() - if (label) { - event.target.setCustomValidity(`Invalid ${label}`) - } - } else { - event.target.setCustomValidity('') - } - event.target.reportValidity() - - // console.log( - // '+contact handleChange', - // event, - // event.target?.name, - // event.target?.value - // ) if (event.target?.name === 'contactAlias') { - let newContact = await store.contacts.setItem( - // state.wallet.id, - state.wallet.xkeyId, - { - ...state.contact, - info: { - ...(state.contact.info || {}), - preferred_username: event.target?.value, - }, - } - ) - - let contactExists = appState.contacts.findIndex( - c => c.info?.preferred_username === newContact.info?.preferred_username - ) - if (contactExists > -1) { - appState.contacts[contactExists] = newContact - } else { - appState.contacts.push(newContact) - } - - contactsList.render( - appState.contacts.sort(sortContactsByAlias) + let updatedAlias = debounceAlias(state, event) + console.log( + 'debounced updated alias', + updatedAlias, ) - // console.log( - // '+contact handleChange newContact', - // newContact - // ) } }, + // handleChange: state => async event => { + // event.preventDefault() + // if ( + // event?.target?.validity?.patternMismatch && + // event?.target?.type !== 'checkbox' + // ) { + // let label = event.target?.previousElementSibling?.textContent?.trim() + // if (label) { + // event.target.setCustomValidity(`Invalid ${label}`) + // } + // } else { + // event.target.setCustomValidity('') + // } + // event.target.reportValidity() + + // // console.log( + // // '+contact handleChange', + // // event, + // // event.target?.name, + // // event.target?.value + // // ) + // }, handleClick: state => async event => { if ( event.target?.classList?.contains('copy') || @@ -342,35 +390,37 @@ export let addContactRig = (function (globals) { ) let showScan = await scanContact.showModal() - let scannedUrl = new URL(showScan) - console.log( - 'showScan', - showScan, - scannedUrl, - // scanContact, - // scanContact?.element?.returnValue - ) - let { searchParams, pathname } = scannedUrl - let addr = pathname.replaceAll('//', '') - let { - xpub, name, preferred_username - } = Object.fromEntries( - searchParams?.entries() - ) - let aOrX = addr || xpub + if (showScan !== 'cancel') { + let scannedUrl = new URL(showScan) - if (aOrX) { - // event.target.addr.value = addr - event.target.contactAddr.value = aOrX - } - if (name) { - // event.target.addr.value = addr - event.target.contactName.value = name - } - if (preferred_username) { - // event.target.addr.value = addr - event.target.contactAlias.value = preferred_username + console.log( + 'scannedUrl', + scannedUrl, + // scanContact, + // scanContact?.element?.returnValue + ) + let { searchParams, pathname } = scannedUrl + let addr = pathname.replaceAll('//', '') + let { + xpub, name, preferred_username + } = Object.fromEntries( + searchParams?.entries() + ) + let aOrX = addr || xpub + + if (aOrX) { + // event.target.addr.value = addr + event.target.contactAddr.value = aOrX + } + if (name) { + // event.target.addr.value = addr + event.target.contactName.value = name + } + if (preferred_username) { + // event.target.addr.value = addr + event.target.contactAlias.value = preferred_username + } } return; @@ -427,40 +477,55 @@ export let addContactRig = (function (globals) { { ...storedContact, info: { + // ...OIDC_CLAIMS, ...(storedContact.info || {}), name: event.target.contactName.value, - preferred_username: event.target.contactAlias.value, }, uri: event.target.contactAddr.value, + alias: event.target.contactAlias.value, } ) - let contactExists = appState.contacts.findIndex( - c => c.info?.preferred_username === pairedContact.info?.preferred_username - ) - if (contactExists > -1) { - appState.contacts[contactExists] = pairedContact - } else { - appState.contacts.push(pairedContact) - } + // let contactExists = appState.contacts.findIndex( + // c => c.info?.preferred_username === pairedContact.info?.preferred_username + // ) + // if (contactExists > -1) { + // appState.contacts[contactExists] = pairedContact + // } else { + // appState.contacts.push(pairedContact) + // } + + // appState.contacts.sort(sortContactsByAlias); + + // contactsList.render(appState.contacts) - appState.contacts.sort(sortContactsByAlias); + loadStore( + store.contacts, + res => { + if (res) { + appState.contacts = res - contactsList.render(appState.contacts) + return contactsList.restate({ + contacts: res?.sort(sortContactsByAlias), + userInfo, + }) + } + } + ) console.log('pairedContact', pairedContact) // let initialized // wallet = state.wallet - // if (!wallets?.[appState.selected_alias]) { + // if (!wallets?.[appState.selectedAlias]) { // initialized = await initWallet( // appState.encryptionPassword, // wallet, // 0, // 0, // { - // preferred_username: appState.selected_alias, + // preferred_username: appState.selectedAlias, // } // ) // wallets = initialized.wallets diff --git a/src/rigs/profile.js b/src/rigs/edit-profile.js similarity index 78% rename from src/rigs/profile.js rename to src/rigs/edit-profile.js index 543467c..a237dc7 100644 --- a/src/rigs/profile.js +++ b/src/rigs/edit-profile.js @@ -8,17 +8,17 @@ import { // parseAddressField, } from '../helpers/utils.js' -const aliasRegex = new RegExp( - /^[a-zA-Z0-9]{1,}$/ -) +import { + ALIAS_REGEX, +} from '../helpers/constants.js' export let editProfileRig = (function (globals) { 'use strict'; let { - setupDialog, mainApp, wallet, wallets, - appState, bodyNav, dashBalance, onboard, - store, aliasWallets, + setupDialog, mainApp, + appState, bodyNav, + store, userInfo, //addContact, } = globals; let editProfile = setupDialog( @@ -65,7 +65,7 @@ export let editProfileRig = (function (globals) { name="profileName" placeholder="John Doe" value="${ - aliasWallets?.info?.name || '' + state.userInfo?.name || '' }" /> @@ -85,9 +85,9 @@ export let editProfileRig = (function (globals) { type="text" id="${state.slugs.form}_alias" name="profileAlias" - value="${appState.selected_alias}" + value="${appState.selectedAlias}" placeholder="your_alias" - pattern="${aliasRegex.source}" + pattern="${ALIAS_REGEX.source}" required spellcheck="false" /> @@ -105,7 +105,7 @@ export let editProfileRig = (function (globals) { handleRender: state => { console.log( 'edit profile render', - aliasWallets, + state.userInfo, ) }, handleSubmit: state => async event => { @@ -133,21 +133,21 @@ export let editProfileRig = (function (globals) { } let storedAlias = await store.aliases.getItem( - appState.selected_alias, + appState.selectedAlias, ) let removedAlias - if (appState.selected_alias !== fde.profileAlias) { + if (appState.selectedAlias !== fde.profileAlias) { removedAlias = await store.aliases.removeItem( - appState.selected_alias, + appState.selectedAlias, ) - appState.selected_alias = fde.profileAlias - localStorage.selected_alias = fde.profileAlias + appState.selectedAlias = fde.profileAlias + localStorage.selectedAlias = fde.profileAlias } let updatedAlias = await store.aliases.setItem( // state.wallet.id, - appState.selected_alias, + appState.selectedAlias, { ...storedAlias, info: { @@ -158,13 +158,16 @@ export let editProfileRig = (function (globals) { } ) + userInfo.name = String(fde.profileName) + userInfo.preferred_username = String(fde.profileAlias) + let storedWallet = await store.wallets.getItem( - appState.selected_wallet, + appState.selectedWallet, ) let updatedWallet = await store.wallets.setItem( // state.wallet.id, - appState.selected_wallet, + appState.selectedWallet, { ...storedWallet, alias: String(fde.profileAlias), @@ -172,23 +175,34 @@ export let editProfileRig = (function (globals) { ) bodyNav.render({ data: { - alias: appState.selected_alias + alias: appState.selectedAlias }, }) - console.log('Edit Profile Updated!', removedAlias, updatedAlias, updatedWallet) + // addContact.render( + // { + // wallet: state.wallet, + // // contact: newContact, + // }, + // 'afterend', + // ) + + console.log( + 'Edit Profile Updated!', + removedAlias, updatedAlias, updatedWallet + ) // let initialized // wallet = state.wallet - // if (!wallets?.[appState.selected_alias]) { + // if (!wallets?.[appState.selectedAlias]) { // initialized = await initWallet( // appState.encryptionPassword, // wallet, // 0, // 0, // { - // preferred_username: appState.selected_alias, + // preferred_username: appState.selectedAlias, // } // ) // wallets = initialized.wallets diff --git a/src/rigs/scan.js b/src/rigs/scan.js index 61f3509..83d11a5 100644 --- a/src/rigs/scan.js +++ b/src/rigs/scan.js @@ -3,16 +3,11 @@ import { lit as html } from '../helpers/lit.js' // formDataEntries, // } from '../helpers/utils.js' -const aliasRegex = new RegExp( - /^[a-zA-Z0-9]{1,}$/ -) - export let scanContactRig = (function (globals) { 'use strict'; let { - setupDialog, mainApp, wallet, wallets, - appState, bodyNav, dashBalance, onboard, + setupDialog, mainApp, } = globals; let scanContact = setupDialog( @@ -145,14 +140,14 @@ export let scanContactRig = (function (globals) { // let initialized // wallet = state.wallet - // if (!wallets?.[appState.selected_alias]) { + // if (!wallets?.[appState.selectedAlias]) { // initialized = await initWallet( // appState.encryptionPassword, // wallet, // 0, // 0, // { - // preferred_username: appState.selected_alias, + // preferred_username: appState.selectedAlias, // } // ) // wallets = initialized.wallets diff --git a/src/rigs/wallet-encrypt.js b/src/rigs/wallet-encrypt.js index faf9279..f37c2f3 100644 --- a/src/rigs/wallet-encrypt.js +++ b/src/rigs/wallet-encrypt.js @@ -154,24 +154,24 @@ export let walletEncryptRig = (function (globals) { sessionStorage.encryptionPassword = window.btoa(String(appState.encryptionPassword)) } - if (!wallets?.[appState.selected_alias]) { + if (!wallets?.[appState.selectedAlias]) { initialized = await initWallet( fde.pass, wallet, 0, 0, { - preferred_username: appState.selected_alias, + preferred_username: appState.selectedAlias, } ) wallets = initialized.wallets } - // console.log('ENCRYPT wallet!', wallet, appState.selected_alias) + // console.log('ENCRYPT wallet!', wallet, appState.selectedAlias) bodyNav?.render({ data: { - alias: appState.selected_alias + alias: appState.selectedAlias }, }) dashBalance?.render({