Added better token transfer

This commit is contained in:
sairaj mote 2023-03-19 17:29:03 +05:30
parent d0ec0ee79c
commit 831b129cf8
5 changed files with 235 additions and 100 deletions

View File

@ -481,6 +481,10 @@ h3 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
.margin-left-auto {
margin-left: auto;
}
.icon-button { .icon-button {
padding: 0.6rem; padding: 0.6rem;
border-radius: 0.8rem; border-radius: 0.8rem;
@ -863,13 +867,35 @@ h3 {
#balance_card { #balance_card {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 2rem;
padding: max(1rem, 2vw); padding: max(1rem, 2vw);
background-color: rgba(var(--text-color), 0.06); background-color: rgba(var(--text-color), 0.06);
aspect-ratio: 4/2; aspect-ratio: 4/2;
justify-content: flex-end; justify-content: flex-end;
border-radius: 0.5rem; border-radius: 0.5rem;
} }
#balance_card form {
margin-top: 1rem;
}
.token-balance {
display: flex;
align-items: center;
cursor: pointer;
gap: 0.5rem;
background-color: rgba(var(--text-color), 0.06);
padding: 0.8rem;
border-radius: 0.3rem;
font-size: 0.9rem;
}
.token-balance span:first-of-type {
text-transform: capitalize;
}
.token-balance input {
height: 1rem;
width: 1rem;
accent-color: var(--accent-color);
}
#transaction_result { #transaction_result {
display: grid; display: grid;
@ -880,6 +906,9 @@ h3 {
text-align: center; text-align: center;
align-content: center; align-content: center;
} }
#transaction_result:empty {
display: none;
}
#transaction_result h3 { #transaction_result h3 {
text-align: center; text-align: center;
width: 100%; width: 100%;
@ -1062,6 +1091,6 @@ h3 {
overflow: overlay; overflow: overlay;
} }
} }
.hide { .hidden {
display: none !important; display: none !important;
} }

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -460,6 +460,9 @@ h3 {
.margin-left-0-5 { .margin-left-0-5 {
margin-left: 0.5rem; margin-left: 0.5rem;
} }
.margin-left-auto {
margin-left: auto;
}
.icon-button { .icon-button {
padding: 0.6rem; padding: 0.6rem;
@ -822,12 +825,33 @@ h3 {
#balance_card { #balance_card {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1rem; gap: 2rem;
padding: max(1rem, 2vw); padding: max(1rem, 2vw);
background-color: rgba(var(--text-color), 0.06); background-color: rgba(var(--text-color), 0.06);
aspect-ratio: 4/2; aspect-ratio: 4/2;
justify-content: flex-end; justify-content: flex-end;
border-radius: 0.5rem; border-radius: 0.5rem;
form {
margin-top: 1rem;
}
}
.token-balance {
display: flex;
align-items: center;
cursor: pointer;
gap: 0.5rem;
background-color: rgba(var(--text-color), 0.06);
padding: 0.8rem;
border-radius: 0.3rem;
font-size: 0.9rem;
span:first-of-type {
text-transform: capitalize;
}
input {
height: 1rem;
width: 1rem;
accent-color: var(--accent-color);
}
} }
#transaction_result { #transaction_result {
display: grid; display: grid;
@ -837,6 +861,9 @@ h3 {
justify-content: center; justify-content: center;
text-align: center; text-align: center;
align-content: center; align-content: center;
&:empty {
display: none;
}
h3 { h3 {
text-align: center; text-align: center;
width: 100%; width: 100%;
@ -1017,6 +1044,6 @@ h3 {
} }
} }
.hide { .hidden {
display: none !important; display: none !important;
} }

View File

@ -42,7 +42,7 @@
</script> </script>
</head> </head>
<body onload="onLoadStartUp()" class="hide"> <body onload="onLoadStartUp()" class="hidden">
<sm-notifications id="notification_drawer"></sm-notifications> <sm-notifications id="notification_drawer"></sm-notifications>
<sm-popup id="confirmation_popup"> <sm-popup id="confirmation_popup">
<h4 id="confirm_title"></h4> <h4 id="confirm_title"></h4>
@ -198,7 +198,7 @@
Add FLO address Add FLO address
</button> </button>
</div> </div>
<div id="transactions" class="hide page"> <div id="transactions" class="hidden page">
<header class="grid"> <header class="grid">
<div class="grid align-center w-100"> <div class="grid align-center w-100">
<a href="#/home" class="flex interact icon-only"> <a href="#/home" class="flex interact icon-only">
@ -246,7 +246,7 @@
<span id="flo_balance"></span> <span id="flo_balance"></span>
</div> </div>
</div> </div>
<div id="tokens" class="grid gap-0-5 hide"> <div id="tokens" class="grid gap-0-5 hidden">
<div class="flex align-center"> <div class="flex align-center">
<svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px" <svg class="icon margin-right-0-5" xmlns="http://www.w3.org/2000/svg" height="24px"
viewBox="0 0 24 24" width="24px" fill="#000000"> viewBox="0 0 24 24" width="24px" fill="#000000">
@ -287,7 +287,7 @@
<span>Loading transactions</span> <span>Loading transactions</span>
</div> </div>
</div> </div>
<button id="scroll_to_top" class="fab hide" onclick="backToTop()"> <button id="scroll_to_top" class="fab hidden" onclick="backToTop()">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px"
fill="#000000"> fill="#000000">
<path d="M0 0h24v24H0z" fill="none" /> <path d="M0 0h24v24H0z" fill="none" />
@ -295,7 +295,7 @@
</svg> </svg>
</button> </button>
</div> </div>
<div id="send" class="page hide gap-1"> <div id="send" class="page hidden gap-1">
<div class="grid full-bleed"> <div class="grid full-bleed">
<h3>Send</h3> <h3>Send</h3>
<p>Perform FLO blockchain transactions</p> <p>Perform FLO blockchain transactions</p>
@ -310,7 +310,7 @@
Sender balance will be shown once you enter a valid address Sender balance will be shown once you enter a valid address
</p> </p>
</div> </div>
<sm-input id="getBal_addr" class="w-100" placeholder="Sender FLO address" <sm-input id="sender_flo_addr" class="w-100" placeholder="Sender FLO address"
error-text="Invalid FLO address" data-flo-id="" animate required> error-text="Invalid FLO address" data-flo-id="" animate required>
<button slot="right" class="icon-only" onclick="showFloIdPicker('sender')" <button slot="right" class="icon-only" onclick="showFloIdPicker('sender')"
title="Select from saved IDs"> title="Select from saved IDs">
@ -336,21 +336,27 @@
</sm-input> </sm-input>
</div> </div>
<div class="grid gap-1"> <div class="grid gap-1">
<sm-input id="amount" type="number" placeholder="Amount" step="0.00001" min="0.00001" <sm-input id="tx_flo_amount" type="number" placeholder="FLO amount" step="0.00000001"
error-text="Invalid amount" animate required> min="0.00000001" error-text="Invalid amount" animate required>
</sm-input> </sm-input>
<sm-textarea id="flo_data_textarea" placeholder="FLO data" rows="8" maxlength="1040" animate> <sm-input id="tx_token_amount" type="number" class="hidden" placeholder="Token amount"
</sm-textarea> step="0.00000001" min="0.00000001" error-text="Invalid amount" animate required disabled>
<div id="show_character_count">1040/1040</div> </sm-input>
<p id="flo_data_status"></p> <div id="flo_data_wrapper" class="grid gap-0-5">
<button class="button button--primary hide" id="fix_invalid_button" <sm-textarea id="flo_data_textarea" placeholder="FLO data" rows="8" maxlength="1040"
animate>
</sm-textarea>
<div id="show_character_count">1040/1040</div>
<p id="flo_data_status"></p>
</div>
<button class="button button--primary hidden" id="fix_invalid_button"
onclick="removeInvalid()">Fix</button> onclick="removeInvalid()">Fix</button>
<button class="button button--primary cta" id="sendBtn" type="submit" <button class="button button--primary cta" id="send_button" type="submit"
onclick="openPopup('get_private_key_popup')" disabled>Send</button> onclick="openPopup('get_private_key_popup')" disabled>Send</button>
</div> </div>
</sm-form> </sm-form>
</div> </div>
<div id="settings" class="page hide gap-2"> <div id="settings" class="page hidden gap-2">
<h3>Settings</h3> <h3>Settings</h3>
<section class="grid gap-1"> <section class="grid gap-1">
<h4>Accent color</h4> <h4>Accent color</h4>
@ -425,10 +431,10 @@
<h3>Add address</h3> <h3>Add address</h3>
</header> </header>
<sm-form> <sm-form>
<sm-input id="floAddr" placeholder="FLO address" error-text="Invalid FLO address" autofocus data-flo-id <sm-input id="flo_addr_to_save" placeholder="FLO address" error-text="Invalid FLO address" autofocus
animate required> data-flo-id animate required>
</sm-input> </sm-input>
<sm-input id="addrLabel" placeholder="Name" animate></sm-input> <sm-input id="label_to_save" placeholder="Name" animate></sm-input>
<button class="button button--primary cta" type="submit" onclick="saveFloId()" disabled>Add</button> <button class="button button--primary cta" type="submit" onclick="saveFloId()" disabled>Add</button>
</sm-form> </sm-form>
</sm-popup> </sm-popup>
@ -450,7 +456,7 @@
<sm-copy id="edit_saved_id"></sm-copy> <sm-copy id="edit_saved_id"></sm-copy>
</div> </div>
<sm-form> <sm-form>
<sm-input id="newAddrLabel" placeholder="Name" autofocus animate required></sm-input> <sm-input id="new_addr_label" placeholder="Name" autofocus animate required></sm-input>
<div class="flex align-center space-between"> <div class="flex align-center space-between">
<button class="button icon-only" title="Delete this FLO address?" onclick="deleteSaved()"> <button class="button icon-only" title="Delete this FLO address?" onclick="deleteSaved()">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
@ -507,14 +513,14 @@
it.</p> it.</p>
</div> </div>
<sm-form> <sm-form>
<div id="recovered_flo_id_wrapper" class="hide"> <div id="recovered_flo_id_wrapper" class="hidden">
<h5>Recovered FLO address</h5> <h5>Recovered FLO address</h5>
<sm-copy id="recovered_flo_id"></sm-copy> <sm-copy id="recovered_flo_id"></sm-copy>
</div> </div>
<sm-input id="retrieve_flo_id_field" type="password" error-text="Invalid private key" <sm-input id="retrieve_flo_id_field" type="password" error-text="Invalid private key"
placeholder="Private key" class="password-field" required autofocus> placeholder="Private key" class="password-field" required autofocus>
<label slot="right" class="interact"> <label slot="right" class="interact">
<input type="checkbox" class="hide" readonly onchange="togglePrivateKeyVisibility(this)"> <input type="checkbox" class="hidden" readonly onchange="togglePrivateKeyVisibility(this)">
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000"> width="24px" fill="#000000">
<title>Hide password</title> <title>Hide password</title>
@ -582,7 +588,7 @@
<sm-form> <sm-form>
<sm-input id="get_private_key_field" class="password-field " type="password" required autofocus> <sm-input id="get_private_key_field" class="password-field " type="password" required autofocus>
<label slot="right" class="interact"> <label slot="right" class="interact">
<input type="checkbox" class="hide" readonly onchange="togglePrivateKeyVisibility(this)"> <input type="checkbox" class="hidden" readonly onchange="togglePrivateKeyVisibility(this)">
<svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" <svg class="icon invisible" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000"> width="24px" fill="#000000">
<title>Hide password</title> <title>Hide password</title>
@ -767,11 +773,11 @@
getRef('search_saved_ids_picker').value = '' getRef('search_saved_ids_picker').value = ''
break; break;
case 'get_private_key_popup': case 'get_private_key_popup':
getRef('get_private_key').classList.remove('hide') getRef('get_private_key').classList.remove('hidden')
renderElem(getRef('transaction_result'), html``) renderElem(getRef('transaction_result'), html``)
break; break;
case 'retrieve_flo_id_popup': case 'retrieve_flo_id_popup':
getRef('recovered_flo_id_wrapper').classList.add('hide') getRef('recovered_flo_id_wrapper').classList.add('hidden')
break; break;
} }
}) })
@ -923,7 +929,7 @@
} else { } else {
notify('Browser is not fully compatible, some features may not work. for best experience please use Chrome, Edge, Firefox or Safari', 'error') notify('Browser is not fully compatible, some features may not work. for best experience please use Chrome, Edge, Firefox or Safari', 'error')
} }
document.body.classList.remove('hide') document.body.classList.remove('hidden')
document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateFloID) document.querySelectorAll('sm-input[data-flo-id]').forEach(input => input.customValidation = floCrypto.validateFloID)
document.querySelectorAll('sm-input[data-private-key]').forEach(input => input.customValidation = floCrypto.getPubKeyHex) document.querySelectorAll('sm-input[data-private-key]').forEach(input => input.customValidation = floCrypto.getPubKeyHex)
document.addEventListener('keyup', (e) => { document.addEventListener('keyup', (e) => {
@ -1037,9 +1043,9 @@
let previousActiveElement = getRef('main_navbar').querySelector('.nav-item--active') let previousActiveElement = getRef('main_navbar').querySelector('.nav-item--active')
const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`) const currentActiveElement = document.querySelector(`.nav-item[href="#/${pageId}"]`)
if (currentActiveElement) { if (currentActiveElement) {
if (getRef('main_navbar').classList.contains('hide')) { if (getRef('main_navbar').classList.contains('hidden')) {
getRef('main_navbar').classList.remove('hide-away') getRef('main_navbar').classList.remove('hide-away')
getRef('main_navbar').classList.remove('hide') getRef('main_navbar').classList.remove('hidden')
getRef('main_navbar').animate([ getRef('main_navbar').animate([
{ {
transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`, transform: isMobileView ? `translateY(100%)` : `translateX(-100%)`,
@ -1055,7 +1061,7 @@
easing: 'ease' easing: 'ease'
}) })
} }
getRef('main_header').classList.remove('hide') getRef('main_header').classList.remove('hidden')
const previousActiveElementIndex = [...getRef('main_navbar').querySelectorAll('.nav-item')].indexOf(previousActiveElement) const previousActiveElementIndex = [...getRef('main_navbar').querySelectorAll('.nav-item')].indexOf(previousActiveElement)
const currentActiveElementIndex = [...getRef('main_navbar').querySelectorAll('.nav-item')].indexOf(currentActiveElement) const currentActiveElementIndex = [...getRef('main_navbar').querySelectorAll('.nav-item')].indexOf(currentActiveElement)
const isOnTop = previousActiveElementIndex < currentActiveElementIndex const isOnTop = previousActiveElementIndex < currentActiveElementIndex
@ -1098,7 +1104,7 @@
previousActiveElement.classList.remove('nav-item--active'); previousActiveElement.classList.remove('nav-item--active');
currentActiveElement.classList.add('nav-item--active') currentActiveElement.classList.add('nav-item--active')
} else { } else {
if (!getRef('main_navbar').classList.contains('hide')) { if (!getRef('main_navbar').classList.contains('hidden')) {
getRef('main_navbar').classList.add('hide-away') getRef('main_navbar').classList.add('hide-away')
getRef('main_navbar').animate([ getRef('main_navbar').animate([
{ {
@ -1114,13 +1120,13 @@
fill: 'forwards', fill: 'forwards',
easing: 'ease' easing: 'ease'
}).onfinish = () => { }).onfinish = () => {
getRef('main_navbar').classList.add('hide') getRef('main_navbar').classList.add('hidden')
} }
getRef('main_header').classList.add('hide') getRef('main_header').classList.add('hidden')
} }
} }
document.querySelectorAll('.page').forEach(page => page.classList.add('hide')) document.querySelectorAll('.page').forEach(page => page.classList.add('hidden'))
getRef(pageId).classList.remove('hide') getRef(pageId).classList.remove('hidden')
getRef(pageId).animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300, fill: 'forwards', easing: 'ease' }) getRef(pageId).animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300, fill: 'forwards', easing: 'ease' })
} }
@ -1240,6 +1246,16 @@
mobileQuery.addEventListener('change', handleMobileChange) mobileQuery.addEventListener('change', handleMobileChange)
handleMobileChange(mobileQuery) handleMobileChange(mobileQuery)
// fetch with json response
async function fetchJSON(url, options) {
const response = await fetch(url, options)
if (response.ok) {
return await response.json()
} else {
throw new Error(response.statusText)
}
}
</script> </script>
<script> <script>
//UI for webWallet //UI for webWallet
@ -1300,21 +1316,19 @@
try { try {
scrollToTopObserver.disconnect() scrollToTopObserver.disconnect()
// retrieve tokens and render them // retrieve tokens and render them
getRef('tokens').classList.add('hide') getRef('tokens').classList.add('hidden')
fetch(`https://ranchimallflo.duckdns.org/api/v1.0/getFloAddressBalance?floAddress=${queriedFloId}`).then(res => res.json()).then(({ floAddressBalances }) => { fetchJSON(`https://ranchimallflo.duckdns.org/api/v1.0/getFloAddressBalance?floAddress=${queriedFloId}`).then(({ floAddressBalances }) => {
const frag = document.createDocumentFragment() let ownedTokens = []
getRef('token_list').innerHTML = ''
let hasTokens = false
for (const token in floAddressBalances) { for (const token in floAddressBalances) {
hasTokens = true ownedTokens.push(html`
frag.append(createElement('li', { <li class="token-item">
className: 'token-item', <span>${token}: </span><span>${parseFloat(floAddressBalances[token].balance.toFixed(8))}</span>
innerHTML: `<span>${token}: </span><span>${parseFloat(floAddressBalances[token].balance.toFixed(8))}</span>` </li>
})) `)
} }
if (hasTokens) { if (ownedTokens.length) {
getRef('token_list').append(frag) renderElem(getRef('token_list'), html`${ownedTokens}`)
getRef('tokens').classList.remove('hide') getRef('tokens').classList.remove('hidden')
} }
}).catch(e => { }).catch(e => {
console.error(e) console.error(e)
@ -1334,8 +1348,8 @@
} }
}) })
// show spinner // show spinner
getRef('transactions_scroller').nextElementSibling.classList.remove('hide') getRef('transactions_scroller').nextElementSibling.classList.remove('hidden')
getRef('transactions_scroller').classList.add('hide') getRef('transactions_scroller').classList.add('hidden')
getRef('transactions_list').innerHTML = ''; getRef('transactions_list').innerHTML = '';
await floWebWallet.syncTransactions(queriedFloId); await floWebWallet.syncTransactions(queriedFloId);
let allTransactions = (await floWebWallet.readTransactions(queriedFloId)).reverse(); let allTransactions = (await floWebWallet.readTransactions(queriedFloId)).reverse();
@ -1350,8 +1364,8 @@
transactionsLazyLoader = new LazyLoader('#transactions_list', allTransactions, render.transactionCard) transactionsLazyLoader = new LazyLoader('#transactions_list', allTransactions, render.transactionCard)
transactionsLazyLoader.init() transactionsLazyLoader.init()
} }
getRef('transactions_scroller').classList.remove('hide') getRef('transactions_scroller').classList.remove('hidden')
getRef('transactions_scroller').nextElementSibling.classList.add('hide') getRef('transactions_scroller').nextElementSibling.classList.add('hidden')
getRef('transactions_scroller').scroll({ getRef('transactions_scroller').scroll({
top: 0 top: 0
}) })
@ -1372,7 +1386,7 @@
if (e.target.closest('.edit-saved')) { if (e.target.closest('.edit-saved')) {
const target = e.target.closest('.saved-id'); const target = e.target.closest('.saved-id');
getRef('edit_saved_id').setAttribute('value', target.dataset.floId) getRef('edit_saved_id').setAttribute('value', target.dataset.floId)
getRef('newAddrLabel').value = target.dataset.name getRef('new_addr_label').value = target.dataset.name
openPopup('edit_saved_popup') openPopup('edit_saved_popup')
} else if (e.target.closest('.copy-saved-id')) { } else if (e.target.closest('.copy-saved-id')) {
const target = e.target.closest('.saved-id'); const target = e.target.closest('.saved-id');
@ -1390,11 +1404,11 @@
}) })
delegate(getRef('saved_ids_picker_list'), 'click', '.saved-id', e => { delegate(getRef('saved_ids_picker_list'), 'click', '.saved-id', e => {
const target = e.target.closest('.saved-id'); const target = e.target.closest('.saved-id');
getRef(`${openSavedIdPopupFor === 'sender' ? 'getBal_addr' : 'receiver'}`).value = target.dataset.floId getRef(`${openSavedIdPopupFor === 'sender' ? 'sender_flo_addr' : 'receiver'}`).value = target.dataset.floId
getRef(`${openSavedIdPopupFor === 'sender' ? 'getBal_addr' : 'receiver'}`).focusIn() getRef(`${openSavedIdPopupFor === 'sender' ? 'sender_flo_addr' : 'receiver'}`).focusIn()
if (openSavedIdPopupFor === 'sender') { if (openSavedIdPopupFor === 'sender') {
checkSenderBalance() checkSenderBalance()
$('#refresh_balance_button').classList.remove('hide') $('#refresh_balance_button').classList.remove('hidden')
} }
closePopup() closePopup()
}) })
@ -1422,10 +1436,10 @@
duration: 150, duration: 150,
easing: 'ease', easing: 'ease',
}).onfinish = () => { }).onfinish = () => {
getRef('scroll_to_top').classList.add('hide') getRef('scroll_to_top').classList.add('hidden')
} }
} else { } else {
getRef('scroll_to_top').classList.remove('hide') getRef('scroll_to_top').classList.remove('hidden')
getRef('scroll_to_top').animate([ getRef('scroll_to_top').animate([
{ {
transform: 'scale(0)', transform: 'scale(0)',
@ -1521,8 +1535,8 @@
function saveFloId() { function saveFloId() {
const floID = getRef('floAddr').value.trim() const floID = getRef('flo_addr_to_save').value.trim()
let name = getRef('addrLabel').value.trim(); let name = getRef('label_to_save').value.trim();
if (name == '') if (name == '')
name = 'Unknown' name = 'Unknown'
compactIDB.addData('labels', name, floID).then((resolve) => { compactIDB.addData('labels', name, floID).then((resolve) => {
@ -1545,7 +1559,7 @@
} }
} }
getRef('getBal_addr').addEventListener('input', debounce(e => { getRef('sender_flo_addr').addEventListener('input', debounce(e => {
if (e.target.isValid) { if (e.target.isValid) {
checkSenderBalance() checkSenderBalance()
} else { } else {
@ -1555,29 +1569,105 @@
function checkSenderBalance() { function checkSenderBalance() {
renderBalance(0, true) renderBalance(0, true)
floWebWallet.getBalance(getRef('getBal_addr').value.trim()).then((retrievedBal) => { const senderFloAddr = getRef('sender_flo_addr').value.trim()
Promise.all([
floWebWallet.getBalance(senderFloAddr),
fetchJSON(`https://ranchimallflo.duckdns.org/api/v1.0/getFloAddressBalance?floAddress=${senderFloAddr}`)
]).then(([retrievedBal, { floAddressBalances }]) => {
renderBalance(parseFloat(retrievedBal)) renderBalance(parseFloat(retrievedBal))
let ownedTokens = []
for (const token in floAddressBalances) {
ownedTokens.push(html`
<label class="token-balance">
<input type="radio" name="sender-token" data-balance=${floAddressBalances[token].balance.toFixed(8)} value=${token}/>
<span>${token} </span><b class="margin-left-auto">${parseFloat(floAddressBalances[token].balance.toFixed(8))}</b>
</label>
`)
}
if (ownedTokens.length) {
ownedTokens.push(html`
<label class="token-balance">
<input type="radio" name="sender-token" value="none" checked/>
<span>Don't send a token</span>
</label>
`)
renderElem(document.getElementById('sender_tokens_wrapper'), html.for(document.getElementById('sender_tokens_wrapper'), senderFloAddr)`
<h5>Tokens</h5>
<p>Select a token, if you want to send a token.</p>
<form onsubmit="event.preventDefault()" onchange=${handleTokenSelection} class="grid gap-1">
<div class="grid gap-0-5">
${ownedTokens}
</div>
</form>
`)
document.getElementById('sender_tokens_wrapper').classList.remove('hidden')
handleTokenSelection()
}
}).catch((error) => { }).catch((error) => {
notify(error, 'error'); notify(error, 'error');
resetBalance() resetBalance()
}) })
} }
function clearSelection() {
getRef('tx_token_amount').disabled = true
getRef('tx_token_amount').classList.add('hidden')
getRef('tx_token_amount').value = ''
getRef('flo_data_wrapper').classList.remove('hidden')
getRef('flo_data_textarea').value = ''
}
function handleTokenSelection() {
const selectedToken = document.getElementById('sender_tokens_wrapper').querySelector('input[type="radio"]:checked')
if (selectedToken.value === 'none')
return clearSelection(e)
const tokenName = selectedToken.value
const tokenBalance = parseFloat(selectedToken.dataset.balance)
getRef('flo_data_wrapper').classList.add('hidden')
getRef('tx_token_amount').disabled = false
getRef('tx_token_amount').classList.remove('hidden')
getRef('tx_token_amount').placeholder = `${tokenName.charAt(0).toUpperCase() + tokenName.slice(1)} amount`
getRef('tx_token_amount').setAttribute('max', tokenBalance)
}
getRef('tx_token_amount').addEventListener('input', e => {
const tokenAmount = parseFloat(e.target.value.trim())
const selectedToken = document.getElementById('sender_tokens_wrapper').querySelector('input[type="radio"]:checked')
const tokenName = selectedToken.value
const tokenBalance = parseFloat(selectedToken.dataset.balance)
const { rangeOverflow, rangeUnderflow } = e.target.validity;
if (rangeUnderflow)
e.target.setAttribute('error-text', `Minimum 0.00000001 ${tokenName} allowed`)
if (rangeOverflow)
e.target.setAttribute('error-text', `You can send ${tokenName} upto ${tokenBalance} only`)
getRef('flo_data_textarea').value = `send ${tokenAmount} ${tokenName}#`
})
getRef('tx_flo_amount').addEventListener('input', e => {
const floAmount = parseFloat(e.target.value.trim())
const { rangeOverflow, rangeUnderflow } = e.target.validity;
if (rangeUnderflow)
e.target.setAttribute('error-text', `Minimum 0.00000001 FLO allowed`)
if (rangeOverflow)
e.target.setAttribute('error-text', `You can send FLO upto ${getRef('sender_balance').textContent} only`)
})
function renderBalance(balance = 0, loading = false) { function renderBalance(balance = 0, loading = false) {
getRef('tx_flo_amount').setAttribute('max', balance)
renderElem(getRef('balance_card'), html` renderElem(getRef('balance_card'), html`
<div class="flex align-center space-between"> <div class="grid">
<h5>Balance</h5> <div class="flex align-center space-between">
<button id="refresh_balance_button" class="button button--small button--colored hide" <h5>Balance</h5>
onclick="checkSenderBalance()">Refresh</button> <button id="refresh_balance_button" class="button button--small button--colored hidden"
</div> onclick="checkSenderBalance()">Refresh</button>
<div class="flex align-end gap-0-3"> </div>
<b id="sender_balance" style="font-size: 2.5rem;line-height: 1;">${loading ? html`<sm-spinner></sm-spinner>` : balance}</b> <div class="flex align-end gap-0-3">
<span>FLO</span> <b id="sender_balance" style="font-size: 2.5rem;line-height: 1;">${loading ? html`<sm-spinner></sm-spinner>` : balance}</b>
<span>FLO</span>
</div>
</div> </div>
<div id="sender_tokens_wrapper" class="grid hidden"></div>
`) `)
} }
function resetBalance() { function resetBalance() {
clearSelection()
renderElem(getRef('balance_card'), html` renderElem(getRef('balance_card'), html`
<div class="flex align-center space-between"> <div class="flex align-center space-between">
<h5>Balance</h5> <h5>Balance</h5>
@ -1590,7 +1680,7 @@
function saveChanges() { function saveChanges() {
let name = getRef('newAddrLabel').value.trim(); let name = getRef('new_addr_label').value.trim();
if (name == '') if (name == '')
name = 'Unknown'; name = 'Unknown';
compactIDB.writeData('labels', name, getRef('edit_saved_id').value).then((resolve) => { compactIDB.writeData('labels', name, getRef('edit_saved_id').value).then((resolve) => {
@ -1633,22 +1723,22 @@
function retrieveFloId() { function retrieveFloId() {
const privKey = getRef('retrieve_flo_id_field').value.trim() const privKey = getRef('retrieve_flo_id_field').value.trim()
floWebWallet.recoverAddr(privKey).then(({ floID }) => { floWebWallet.recoverAddr(privKey).then(({ floID }) => {
getRef('recovered_flo_id_wrapper').classList.remove('hide') getRef('recovered_flo_id_wrapper').classList.remove('hidden')
getRef('recovered_flo_id').value = floID getRef('recovered_flo_id').value = floID
}) })
} }
function sendMessage() { function sendMessage() {
const sender = getRef('getBal_addr').value.trim(); const sender = getRef('sender_flo_addr').value.trim();
const amount = parseFloat(getRef('amount').value.trim()); const floAmount = parseFloat(getRef('tx_flo_amount').value.trim());
const receiver = getRef('receiver').value.trim(); const receiver = getRef('receiver').value.trim();
const floData = getRef('flo_data_textarea').value.trim(); const floData = getRef('flo_data_textarea').value.trim();
const privKey = getRef('get_private_key_field').value.trim(); const privKey = getRef('get_private_key_field').value.trim();
buttonLoader('confirm_transaction_button', true) buttonLoader('confirm_transaction_button', true)
floWebWallet.sendTransaction(sender, receiver, amount, floData, privKey).then((transactionId) => { floWebWallet.sendTransaction(sender, receiver, floAmount, floData, privKey).then((transactionId) => {
showTransactionResult(true, transactionId); showTransactionResult(true, transactionId);
getRef('send_form').reset(); getRef('send_form').reset();
getRef('sendBtn').disabled = true; getRef('send_button').disabled = true;
resetBalance() resetBalance()
}).catch((error) => { }).catch((error) => {
showTransactionResult(false, error); showTransactionResult(false, error);
@ -1658,7 +1748,7 @@
} }
function showTransactionResult(success, result) { function showTransactionResult(success, result) {
getRef('get_private_key').classList.add('hide') getRef('get_private_key').classList.add('hidden')
renderElem(getRef('transaction_result'), html` renderElem(getRef('transaction_result'), html`
${success ? html` ${success ? html`
<svg class="icon icon--success" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <path d="M0 0h24v24H0z" fill="none" /> <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" /> </svg> <svg class="icon icon--success" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <path d="M0 0h24v24H0z" fill="none" /> <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" /> </svg>
@ -1700,12 +1790,12 @@
getRef('flo_data_textarea').addEventListener('input', function (e) { getRef('flo_data_textarea').addEventListener('input', function (e) {
if (this.value.trim() !== '') { if (this.value.trim() !== '') {
getRef('sendBtn').classList.add('hide') getRef('send_button').classList.add('hidden')
getRef('fix_invalid_button').classList.remove('hide') getRef('fix_invalid_button').classList.remove('hidden')
} }
else { else {
getRef('sendBtn').classList.remove('hide') getRef('send_button').classList.remove('hidden')
getRef('fix_invalid_button').classList.add('hide') getRef('fix_invalid_button').classList.add('hidden')
} }
if (1040 - this.value.length) { if (1040 - this.value.length) {
getRef('show_character_count').textContent = `${1040 - this.value.length} /1040` getRef('show_character_count').textContent = `${1040 - this.value.length} /1040`
@ -1717,8 +1807,8 @@
function checkFloData() { function checkFloData() {
const floDataText = getRef('flo_data_textarea').value; const floDataText = getRef('flo_data_textarea').value;
if (/^[\x20-\x7E]*$/.test(floDataText)) { if (/^[\x20-\x7E]*$/.test(floDataText)) {
getRef('sendBtn').classList.remove('hide') getRef('send_button').classList.remove('hidden')
getRef('fix_invalid_button').classList.add('hide') getRef('fix_invalid_button').classList.add('hidden')
getRef('flo_data_status').textContent = '' getRef('flo_data_status').textContent = ''
} }
else { else {
@ -1731,17 +1821,6 @@
checkFloData() checkFloData()
} }
// let preventUnconfirmedUTXO = true
// getRef('allow_utxo_switch').addEventListener('change', e => {
// preventUnconfirmedUTXO = !e.target.checked
// localStorage.preventUnconfirmedUTXO = preventUnconfirmedUTXO
// })
// if (localStorage.getItem('preventUnconfirmedUTXO') !== 'null') {
// const getBoolean = (localStorage.preventUnconfirmedUTXO === 'false')
// preventUnconfirmedUTXO = getBoolean
// getRef('allow_utxo_switch').checked = getBoolean
// }
const selectedColors = [ const selectedColors = [
'--dark-red', '--dark-red',
'--red', '--red',

File diff suppressed because one or more lines are too long