UI and feature update

-- Merged wallet and payments history into one page
-- added balance refresh button in home page
This commit is contained in:
sairaj mote 2022-05-19 23:18:10 +05:30
parent bd600c0a25
commit ac75074ecd
6 changed files with 192 additions and 115 deletions

View File

@ -45,12 +45,17 @@ body[data-theme=dark] sm-popup::part(popup) {
background-color: rgba(var(--foreground-color), 1);
}
h1,
h1, h1 > *,
h2,
h2 > *,
h3,
h3 > *,
h4,
h4 > *,
h5,
h6 {
h5 > *,
h6,
h6 > * {
font-weight: 400;
font-family: "Calistoga", cursive;
}
@ -1001,16 +1006,18 @@ ul {
}
#history .page__header {
min-height: 4rem;
margin-bottom: 0;
}
#history_applied_filters_wrapper {
padding: 0.2rem 0 0.5rem 0;
background-color: rgba(var(--background-color), 1);
z-index: 1;
position: -webkit-sticky;
position: sticky;
top: 0;
padding: 0.2rem 0 0.5rem 0;
background-color: rgba(var(--foreground-color), 1);
z-index: 1;
transition: background-color 0.3s;
}
.applied-filter {

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -50,8 +50,11 @@ h3,
h4,
h5,
h6 {
font-weight: 400;
font-family: "Calistoga", cursive;
&,
& > * {
font-weight: 400;
font-family: "Calistoga", cursive;
}
}
p,
@ -941,15 +944,17 @@ ul {
#history {
.page__header {
min-height: 4rem;
margin-bottom: 0;
}
}
#history_applied_filters_wrapper {
padding: 0.2rem 0 0.5rem 0;
background-color: rgba(var(--background-color), 1);
z-index: 1;
position: sticky;
top: 0;
padding: 0.2rem 0 0.5rem 0;
background-color: rgba(var(--foreground-color), 1);
z-index: 1;
transition: background-color 0.3s;
}
.applied-filter {
display: flex;

View File

@ -172,14 +172,9 @@
<div id="wallet_section" class="grid gap-1">
<div class="flex align-center space-between">
<h4>My wallet</h4>
<a href="#/wallet" class="flex align-center interact button user-element">
See history
<svg class="icon" 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="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
</svg>
</a>
<div class="multi-state-button">
<button class="button" onclick="refreshBalance(this)">Refresh</button>
</div>
</div>
<div id="wallet_cards_wrapper">
<div class="grid gap-0-5 balance-card">
@ -300,9 +295,15 @@
</section>
</section>
<section id="history" class="inner-page hide grid gap-1-5">
<strip-select id="history_type_selector" class="justify-self-center">
<strip-option value="payment" selected>Payments</strip-option>
<strip-option value="wallet">Wallet</strip-option>
</strip-select>
<div class="page__header">
<div class="grid">
<h4>Payments</h4>
<h4>
<r-s sid="history_type">Payments</r-s>
</h4>
<h1>history</h1>
</div>
<button class="button button--small align-self-end" onclick="showPopup('payments_filters_popup')">
@ -318,9 +319,25 @@
<h5>Applied filters</h5>
<div id="history_applied_filters" class="flex gap-0-5"></div>
</div>
<ul id="payments_history" class="observe-empty-state"></ul>
<div class=" empty-state gap-1 justify-center text-center">
<h4>No transactions</h4>
<div id="history_wrapper">
<div>
<ul id="payments_history" class="observe-empty-state"></ul>
<div class=" empty-state gap-1 justify-center text-center">
<h4>No transactions</h4>
</div>
</div>
<div id="wallet_history_wrapper" class="grid gap-1-5 hide">
<div class="hide grid gap-1">
<h4>Pending transactions</h4>
<ul id="pending_wallet_transactions" class="grid gap-0-5"></ul>
</div>
<div class="grid gap-1">
<ul id="wallet_history" class="observe-empty-state grid gap-0-5"></ul>
<div class=" empty-state gap-1 justify-center text-center">
<h4>No transactions</h4>
</div>
</div>
</div>
</div>
</section>
<section id="contacts" class="inner-page hide flex flex-direction-column">
@ -383,8 +400,7 @@
<h4>No Saved FLO ID</h4>
</div>
</section>
<button id="add_address_button" class="button interact fab user-element"
onclick="showPopup('add_address_popup')">
<button id="add_address_button" class="button interact fab" onclick="showPopup('add_address_popup')">
<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">
<path d="M0 0h24v24H0V0z" fill="none" />
@ -435,36 +451,6 @@
</div>
</div>
</section>
<section id="wallet" class="inner-page hide">
<div class="page__header">
<div class="grid justify-start gap-1">
<a href="#/home" class="button icon-only margin-right-0-5">
<svg class="icon" 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="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" />
</svg>
</a>
<div class="grid">
<h4>Wallet</h4>
<h1>transactions</h1>
</div>
</div>
</div>
<div id="wallet_history_wrapper" class="grid gap-1-5 user-element">
<div class="hide grid gap-1">
<h4>Pending transactions</h4>
<ul id="pending_wallet_transactions" class="grid gap-0-5"></ul>
</div>
<div class="grid gap-1">
<h4>History</h4>
<ul id="wallet_history" class="observe-empty-state grid gap-0-5"></ul>
<div class=" empty-state gap-1 justify-center text-center">
<h4>No transactions</h4>
</div>
</div>
</div>
</section>
<div id="transaction" class="inner-page hide grid gap-2">
<div class="grid gap-1 justify-start">
<button class="button icon-only margin-right-0-5" onclick="history.back()">
@ -557,7 +543,7 @@
<span class="nav-item__title">History</span>
</a>
</li>
<li>
<li class="user-element hide">
<a href="#/contacts" class="nav-item interact" title='View payment requests'>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24"
width="24px" fill="#000000">
@ -1170,14 +1156,7 @@
console.log(`Welcome ${myFloID}`);
document.querySelectorAll('.logged-in-user-id').forEach(elem => elem.value = myFloID);
floGlobals.isSubAdmin = floGlobals.subAdmins.includes(myFloID)
tokenAPI.getBalance(myFloID).then((balance = 0) => {
const [beforeDecimal, afterDecimal] = formatAmount(balance).split('₹')[1].split('.')
getRef('rupee_balance').innerHTML = `<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`
})
floBlockchainAPI.getBalance(myFloID).then(balance => {
const [beforeDecimal, afterDecimal = '00'] = String(balance).split('.')
getRef('flo_balance').innerHTML = `<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`
})
refreshBalance()
if (floGlobals.isSubAdmin) {
cashierUI.renderRequests(Cashier.Requests);
Cashier.init().then(result => {

View File

@ -48,7 +48,7 @@ function continueWalletTopup() {
res.text().then(data => getRef('topup_wallet__qr_code').innerHTML = data)
.catch(err => console.error(err));
}).catch(err => console.error(err));
showProcessStage('topup_wallet_process', 1)
showChildElement('topup_wallet_process', 1)
getRef('topup_wallet__txid').focusIn();
}
function depositMoneyToWallet() {
@ -62,11 +62,12 @@ function depositMoneyToWallet() {
buttonLoader('topup_wallet_button', true);
User.cashToToken(cashier, amount, upiTxID).then(result => {
console.log(result);
showProcessStage('topup_wallet_process', 2);
showChildElement('topup_wallet_process', 2);
refreshBalance()
}).catch(error => {
console.error(error)
getRef('topup_failed_reason').textContent = error;
showProcessStage('topup_wallet_process', 3);
showChildElement('topup_wallet_process', 3);
})
}
@ -82,18 +83,19 @@ function withdrawMoneyFromWallet() {
User.sendToken(cashier, amount, 'for token-to-cash').then(txid => {
console.warn(`Withdraw ${amount} from cashier ${cashier}`, txid);
User.tokenToCash(cashier, amount, txid, upiId).then(result => {
showProcessStage('withdraw_wallet_process', 1);
showChildElement('withdraw_wallet_process', 1);
refreshBalance();
console.log(result);
}).catch(error => {
getRef('withdrawal_failed_reason').textContent = error;
showProcessStage('withdraw_wallet_process', 2);
showChildElement('withdraw_wallet_process', 2);
console.error(error)
}).finally(() => {
buttonLoader('withdraw_rupee_button', false);
});
}).catch(error => {
getRef('withdrawal_failed_reason').textContent = error;
showProcessStage('withdraw_wallet_process', 2);
showChildElement('withdraw_wallet_process', 2);
buttonLoader('withdraw_rupee_button', false);
console.error(error)
})
@ -104,7 +106,7 @@ function transferToExchange() {
buttonLoader('exchange_transfer__button', true);
floExchangeAPI.depositToken('rupee', amount, myFloID, 'FRJkPqdbbsug3TtQRAWviqvTL9Qr2EMnrm', myPrivKey).then(txid => {
console.log(txid);
showProcessStage('exchange_transfer_process', 1);
showChildElement('exchange_transfer_process', 1);
getRef('exchange_transfer__success_message').textContent = `Transferred ${formatAmount(amount)} to exchange`;
}).catch(error => {
console.log(error);
@ -114,7 +116,7 @@ function transferToExchange() {
if (error === 'Insufficient rupee# balance')
error = 'Insufficient rupee token balance in your wallet, please top-up your wallet.';
getRef('exchange_transfer__failed_reason').textContent = error;
showProcessStage('exchange_transfer_process', 2);
showChildElement('exchange_transfer_process', 2);
}).finally(() => {
buttonLoader('exchange_transfer__button', false);
});
@ -182,7 +184,7 @@ userUI.renderCashierRequests = function (requests, error = null) {
return console.error(error);
else if (typeof requests !== "object" || requests === null)
return;
if (pagesData.lastPage === 'wallet') {
if (pagesData.lastPage === 'history') {
for (let transactionID in requests) {
const { note, tag } = requests[transactionID];
let status = tag ? 'done' : (note ? 'failed' : "pending");
@ -349,7 +351,7 @@ function completeCashToTokenRequest(request) {
const { message: { upi_txid, amount }, vectorClock, senderID } = request;
Cashier.checkIfUpiTxIsValid(upi_txid).then(_ => {
getConfirmation('Confirm', {
message: `Check if you have received UPI transfer\ntxid: ${upi_txid}\namount: ${formatAmount(amount)}`,
message: `Check if you have received UPI transfer\nTxID: ${upi_txid}\nAmount: ${formatAmount(amount)}`,
confirmText: 'Confirm'
}).then(confirmed => {
if (confirmed) {
@ -579,14 +581,15 @@ const render = {
};
function buttonLoader(id, show) {
getRef(id).disabled = show;
const button = typeof id === 'string' ? getRef(id) : id;
button.disabled = show;
const animOptions = {
duration: 200,
fill: 'forwards',
easing: 'ease'
}
if (show) {
getRef(id).animate([
button.animate([
{
clipPath: 'circle(100%)',
},
@ -597,13 +600,29 @@ function buttonLoader(id, show) {
e.target.commitStyles()
e.target.cancel()
}
getRef(id).parentNode.append(createElement('sm-spinner'))
button.parentNode.append(createElement('sm-spinner'))
} else {
getRef(id).style = ''
const potentialTarget = getRef(id).parentNode.querySelector('sm-spinner')
button.style = ''
const potentialTarget = button.parentNode.querySelector('sm-spinner')
if (potentialTarget) potentialTarget.remove();
}
}
function refreshBalance(button) {
if (button)
buttonLoader(button, true)
tokenAPI.getBalance(myFloID).then((balance = 0) => {
const [beforeDecimal, afterDecimal] = formatAmount(balance).split('₹')[1].split('.')
getRef('rupee_balance').innerHTML = `<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`
if (button)
buttonLoader(button, false)
})
floBlockchainAPI.getBalance(myFloID).then(balance => {
const [beforeDecimal, afterDecimal = '00'] = String(balance).split('.')
getRef('flo_balance').innerHTML = `<span><b>${beforeDecimal}</b></span>.<span>${afterDecimal}</span>`
if (button)
buttonLoader(button, false)
})
}
function getArrayOfSavedIds() {
const arr = [];
@ -812,6 +831,12 @@ function executeUserAction() {
userUI.requestMoneyFromUser(floID, amount, remark);
}
}
const [historyType, setHistoryType] = createState('Payments', 'history_type', (v) => {
showChildElement('history_wrapper', v === 'Payments' ? 0 : 1)
});
getRef('history_type_selector').addEventListener('change', e => {
setHistoryType(e.target.value === 'payment' ? 'Payments' : 'Wallet')
})
function toggleFilters() {
const animOptions = {

View File

@ -114,7 +114,7 @@ document.addEventListener('popupopened', async e => {
getRef('select_upi_id').parentNode.classList.remove('hide')
getRef('select_upi_id').append(frag)
}
showProcessStage('withdraw_wallet_process', 0)
showChildElement('withdraw_wallet_process', 0)
break;
}
})
@ -126,14 +126,14 @@ document.addEventListener('popupclosed', e => {
getRef('search_saved_ids_picker').value = ''
break;
case 'topup_wallet_popup':
showProcessStage('topup_wallet_process', 0)
showChildElement('topup_wallet_process', 0)
break;
case 'withdraw_wallet_popup':
getRef('select_upi_id').parentNode.classList.add('hide')
getRef('select_upi_id').innerHTML = ''
break;
case 'transfer_to_exchange_popup':
showProcessStage('exchange_transfer_process', 0);
showChildElement('exchange_transfer_process', 0);
break;
}
})
@ -372,6 +372,31 @@ async function showPage(targetPage, options = {}) {
break;
case 'history':
render.paymentsHistory()
const walletTransactions = []
if (walletHistoryLoader)
walletHistoryLoader.clear()
const pendingWalletTransactions = document.createDocumentFragment()
let areTransactionsPending = false
for (const transactionId in User.cashierRequests) {
if (!User.cashierRequests[transactionId].note) {
areTransactionsPending = true
pendingWalletTransactions.prepend(render.walletRequestCard(User.cashierRequests[transactionId]))
} else {
walletTransactions.unshift(User.cashierRequests[transactionId])
}
}
if (walletHistoryLoader) {
walletHistoryLoader.update(walletTransactions)
} else {
walletHistoryLoader = new LazyLoader('#wallet_history', walletTransactions, render.walletRequestCard);
pendingTransactionsObserver.observe(getRef('pending_wallet_transactions'), { childList: true });
}
if (areTransactionsPending) {
getRef('pending_wallet_transactions').innerHTML = ''
getRef('pending_wallet_transactions').append(pendingWalletTransactions)
}
walletHistoryLoader.init()
break;
case 'requests':
const paymentRequests = [];
@ -400,33 +425,6 @@ async function showPage(targetPage, options = {}) {
}
paymentRequestsLoader.init()
break;
case 'wallet':
const walletTransactions = []
if (walletHistoryLoader)
walletHistoryLoader.clear()
const pendingWalletTransactions = document.createDocumentFragment()
let areTransactionsPending = false
for (const transactionId in User.cashierRequests) {
if (!User.cashierRequests[transactionId].note) {
areTransactionsPending = true
pendingWalletTransactions.prepend(render.walletRequestCard(User.cashierRequests[transactionId]))
} else {
walletTransactions.unshift(User.cashierRequests[transactionId])
}
}
if (walletHistoryLoader) {
walletHistoryLoader.update(walletTransactions)
} else {
walletHistoryLoader = new LazyLoader('#wallet_history', walletTransactions, render.walletRequestCard);
pendingTransactionsObserver.observe(getRef('pending_wallet_transactions'), { childList: true });
}
if (areTransactionsPending) {
getRef('pending_wallet_transactions').innerHTML = ''
getRef('pending_wallet_transactions').append(pendingWalletTransactions)
}
walletHistoryLoader.init()
break;
case 'transaction':
let transactionDetails
let status
@ -485,15 +483,13 @@ async function showPage(targetPage, options = {}) {
if (pageId !== 'history') {
if (paymentsHistoryLoader)
paymentsHistoryLoader.clear()
if (walletHistoryLoader)
walletHistoryLoader.clear()
}
if (pageId !== 'contact') {
if (contactHistoryLoader)
contactHistoryLoader.clear()
}
if (pageId !== 'wallet') {
if (walletHistoryLoader)
walletHistoryLoader.clear()
}
if (pageId !== 'settings') {
getRef('saved_upi_ids_list').innerHTML = '';
}
@ -746,11 +742,76 @@ function handleMobileChange(e) {
mobileQuery.addEventListener('change', handleMobileChange)
handleMobileChange(mobileQuery)
function showProcessStage(id, index) {
function showChildElement(id, index) {
[...getRef(id).children].forEach((child, i) => {
if (i === index)
child.classList.remove('hide')
else
child.classList.add('hide')
})
}
}
// Reactivity system
class ReactiveState {
constructor() {
this.state = {}
}
setState(key, value, callback) {
if (this.state[key].value === value) return
this.state[key].value = value
this.state[key].refs.forEach(ref => {
ref.textContent = value
})
if (callback)
callback(value)
}
getState(key) {
return this.state[key].value
}
subscribe(key, dom) {
if (!this.state.hasOwnProperty(key)) {
this.state[key] = {
refs: new Set(),
value: '',
}
}
this.state[key].refs.add(dom)
dom.textContent = this.state[key].value
}
unsubscribe(key, dom) {
this.state[key].refs.delete(dom)
}
createState(defaultValue, key, callback) {
if (!key)
key = Math.random().toString(36).substr(2, 9);
if (!this.state.hasOwnProperty(key)) {
this.state[key] = {
refs: new Set()
}
}
this.setState(key, defaultValue, callback)
return [
() => this.getState(key),
value => this.setState(key, value, callback)
]
}
}
const reactiveState = new ReactiveState()
function createState(defaultValue, key, callback) {
return reactiveState.createState(defaultValue, key, callback)
}
const smState = document.createElement('template')
smState.innerHTML = ``
class SmState extends HTMLElement {
constructor() {
super();
this.appendChild(smState.content.cloneNode(true));
}
connectedCallback() {
reactiveState.subscribe(this.getAttribute('sid'), this)
}
disconnectedCallback() {
reactiveState.unsubscribe(this.getAttribute('sid'), this)
}
}
window.customElements.define('r-s', SmState);