UX improvements and bug fixes

This commit is contained in:
sairaj mote 2021-09-17 23:18:44 +05:30
parent 60220d9ad4
commit 3a5e5ad7f6
5 changed files with 642 additions and 387 deletions

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
} }
:root { :root {
font-size: clamp(1rem, 1.2vmax, 3rem); font-size: clamp(1rem, 1.2vmax, 1.2rem);
} }
html, html,
@ -46,13 +46,15 @@ body[data-theme=dark] * {
--yellow: #ffd13a; --yellow: #ffd13a;
} }
p { p,
strong {
font-size: 0.9rem; font-size: 0.9rem;
max-width: 70ch; max-width: 70ch;
line-height: 1.7; line-height: 1.7;
color: rgba(var(--text-color), 0.8); color: rgba(var(--text-color), 0.8);
} }
p:not(:last-of-type) { p:not(:last-of-type),
strong:not(:last-of-type) {
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
} }
@ -409,7 +411,7 @@ button:active,
} }
#logo h4 { #logo h4 {
text-transform: capitalize; text-transform: capitalize;
font-size: 1rem; font-size: 0.9rem;
font-weight: 600; font-weight: 600;
} }
#logo #main_logo { #logo #main_logo {
@ -420,6 +422,12 @@ button:active,
} }
details summary { details summary {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: justify;
-ms-flex-pack: justify;
justify-content: space-between;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
@ -576,6 +584,10 @@ details[open] > summary .icon {
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;
} }
.quick-action.disabled {
pointer-events: none;
opacity: 0.6;
}
.quick-action__icon { .quick-action__icon {
padding: 1rem; padding: 1rem;
border-radius: 1rem; border-radius: 1rem;
@ -716,23 +728,41 @@ strip-option:last-of-type {
} }
.activity-card--request, .activity-card--request,
.activity-card--pending,
.activity-card--admin { .activity-card--admin {
grid-template-areas: "icon . amount" "icon time ."; grid-template-areas: "icon . amount" "icon time .";
} }
.activity-card--request .activity-card__icon, .activity-card--request .activity-card__icon,
.activity-card--pending .activity-card__icon,
.activity-card--admin .activity-card__icon { .activity-card--admin .activity-card__icon {
grid-area: icon; grid-area: icon;
} }
.activity-card--request .activity-card__time, .activity-card--request .activity-card__time,
.activity-card--pending .activity-card__time,
.activity-card--admin .activity-card__time { .activity-card--admin .activity-card__time {
grid-area: time; grid-area: time;
} }
.activity-card--request .activity-card__amount, .activity-card--request .activity-card__amount,
.activity-card--pending .activity-card__amount,
.activity-card--admin .activity-card__amount { .activity-card--admin .activity-card__amount {
grid-area: amount; grid-area: amount;
text-align: end; text-align: end;
} }
#pending_transaction:not(:empty) {
margin-bottom: 2rem;
}
.activity-card--pending:not(:empty) {
padding: 1rem;
margin-top: 0.8rem;
border: solid 0.1rem var(--accent-color);
}
.activity-card--pending:not(:empty) .activity-card__description {
font-size: 0.8rem;
color: rgba(var(--text-color), 0.8);
}
.status-tag:not(:empty) { .status-tag:not(:empty) {
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@ -1104,6 +1134,37 @@ strip-option:last-of-type {
margin-top: 1rem; margin-top: 1rem;
} }
.loader-button-wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
position: relative;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.loader-button-wrapper sm-button {
width: 100%;
z-index: 1;
-webkit-transition: -webkit-clip-path 0.3s;
transition: -webkit-clip-path 0.3s;
transition: clip-path 0.3s;
transition: clip-path 0.3s, -webkit-clip-path 0.3s;
-webkit-clip-path: circle(100%);
clip-path: circle(100%);
}
.loader-button-wrapper sm-button.clip {
pointer-events: none;
-webkit-clip-path: circle(0);
clip-path: circle(0);
}
.loader-button-wrapper sm-spinner {
position: absolute;
}
#result { #result {
place-content: center; place-content: center;
} }
@ -1238,7 +1299,7 @@ strip-option:last-of-type {
#transaction_action_button, #transaction_action_button,
#account_action_button, #account_action_button,
#deposit_button { .loader-button-wrapper {
margin-top: auto; margin-top: auto;
} }
@ -1300,6 +1361,7 @@ strip-option:last-of-type {
#user_section { #user_section {
grid-area: user-section; grid-area: user-section;
background-color: rgba(var(--background-color), 1); background-color: rgba(var(--background-color), 1);
width: min(24rem, 100%);
} }
#transaction_top, #transaction_top,
@ -1372,6 +1434,10 @@ strip-option:last-of-type {
.hide-on-desktop { .hide-on-desktop {
display: none; display: none;
} }
.activity-card--pending:not(:empty) {
padding: 1.5rem;
}
} }
@media screen and (min-width: 1920px) { @media screen and (min-width: 1920px) {
.page-layout { .page-layout {

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
} }
:root { :root {
font-size: clamp(1rem, 1.2vmax, 3rem); font-size: clamp(1rem, 1.2vmax, 1.2rem);
} }
html, html,
@ -48,7 +48,8 @@ body[data-theme="dark"] {
} }
} }
p { p,
strong {
font-size: 0.9rem; font-size: 0.9rem;
max-width: 70ch; max-width: 70ch;
line-height: 1.7; line-height: 1.7;
@ -375,7 +376,7 @@ button:active,
h4 { h4 {
text-transform: capitalize; text-transform: capitalize;
font-size: 1rem; font-size: 0.9rem;
font-weight: 600; font-weight: 600;
} }
@ -388,6 +389,8 @@ button:active,
} }
details { details {
summary { summary {
display: flex;
justify-content: space-between;
user-select: none; user-select: none;
cursor: pointer; cursor: pointer;
} }
@ -506,6 +509,10 @@ details {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
&.disabled {
pointer-events: none;
opacity: 0.6;
}
&__icon { &__icon {
padding: 1rem; padding: 1rem;
border-radius: 1rem; border-radius: 1rem;
@ -625,6 +632,7 @@ strip-option {
} }
} }
.activity-card--request, .activity-card--request,
.activity-card--pending,
.activity-card--admin { .activity-card--admin {
grid-template-areas: "icon . amount" "icon time ."; grid-template-areas: "icon . amount" "icon time .";
.activity-card__icon { .activity-card__icon {
@ -638,6 +646,18 @@ strip-option {
text-align: end; text-align: end;
} }
} }
#pending_transaction:not(:empty) {
margin-bottom: 2rem;
}
.activity-card--pending:not(:empty) {
padding: 1rem;
margin-top: 0.8rem;
border: solid 0.1rem var(--accent-color);
.activity-card__description {
font-size: 0.8rem;
color: rgba(var(--text-color), 0.8);
}
}
.status-tag:not(:empty) { .status-tag:not(:empty) {
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.05em; letter-spacing: 0.05em;
@ -944,6 +964,25 @@ strip-option {
--font-size: 1.5rem; --font-size: 1.5rem;
margin-top: 1rem; margin-top: 1rem;
} }
.loader-button-wrapper {
display: flex;
position: relative;
justify-content: center;
align-items: center;
sm-button {
width: 100%;
z-index: 1;
transition: clip-path 0.3s;
clip-path: circle(100%);
&.clip {
pointer-events: none;
clip-path: circle(0);
}
}
sm-spinner {
position: absolute;
}
}
#result { #result {
place-content: center; place-content: center;
section { section {
@ -1036,7 +1075,7 @@ strip-option {
} }
#transaction_action_button, #transaction_action_button,
#account_action_button, #account_action_button,
#deposit_button { .loader-button-wrapper {
margin-top: auto; margin-top: auto;
} }
#transaction_top, #transaction_top,
@ -1091,6 +1130,7 @@ strip-option {
#user_section { #user_section {
grid-area: user-section; grid-area: user-section;
background-color: rgba(var(--background-color), 1); background-color: rgba(var(--background-color), 1);
width: min(24rem, 100%);
} }
#transaction_top, #transaction_top,
#account_top, #account_top,
@ -1150,6 +1190,9 @@ strip-option {
.hide-on-desktop { .hide-on-desktop {
display: none; display: none;
} }
.activity-card--pending:not(:empty) {
padding: 1.5rem;
}
} }
@media screen and (min-width: 1920px) { @media screen and (min-width: 1920px) {
.page-layout { .page-layout {

View File

@ -6,6 +6,11 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RanchiMall Bank</title> <title>RanchiMall Bank</title>
<script src="components.js" defer></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"
integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="css/main.min.css"> <link rel="stylesheet" href="css/main.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
@ -36,10 +41,6 @@
application: "test_bank", application: "test_bank",
} }
</script> </script>
<script src="components.js" defer></script>
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"
integrity="sha512-Wt1bJGtlnMtGP0dqNFH1xlkLBNpEodaiQ8ZN5JLA5wpc1sUlk/O5uuOMNgvzddzkpvZ9GLyYNa8w2s7rqiTk5Q=="
crossorigin="anonymous" referrerpolicy="no-referrer"></script>
</head> </head>
<body onload="onLoadStartUp()" class="hide-completely"> <body onload="onLoadStartUp()" class="hide-completely">
@ -163,6 +164,7 @@
<section id="subpage_container"> <section id="subpage_container">
<div id="dashboard" class="sub-page"> <div id="dashboard" class="sub-page">
<section> <section>
<section id="pending_transaction"></section>
<h4 class="flex align-center"> <h4 class="flex align-center">
<svg xmlns="http://www.w3.org/2000/svg" class="icon button__icon--left" viewBox="0 0 20 20" <svg xmlns="http://www.w3.org/2000/svg" class="icon button__icon--left" viewBox="0 0 20 20"
fill="currentColor"> fill="currentColor">
@ -475,7 +477,9 @@
<sm-input id="get_deposit_amount" type="number" min="1" step="0.01" <sm-input id="get_deposit_amount" type="number" min="1" step="0.01"
error-text="Amount should be at least ₹1" placeholder="₹Amount" required> error-text="Amount should be at least ₹1" placeholder="₹Amount" required>
</sm-input> </sm-input>
<sm-button id="deposit_button" variant="primary" disabled onclick="initDeposit()">Deposit</sm-button> <div id="deposit_button_wrapper" class="loader-button-wrapper">
<sm-button id="deposit_button" variant="primary" disabled onclick="initDeposit()">Deposit</sm-button>
</div>
</sm-form> </sm-form>
</article> </article>
<article id="loan" class="page hide-completely page-layout"> <article id="loan" class="page hide-completely page-layout">
@ -487,7 +491,7 @@
</svg> </svg>
</a> </a>
<sm-form> <sm-form>
<div id="deposit__icon"> <div id="loan__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path <path
d="M12.65,8.5H10.42a5.18,5.18,0,0,0-4,1.95L3.75,13.74a5,5,0,0,0-.68,5.31l0,0h0a5.07,5.07,0,0,0,4.5,2.73h7.88A5.08,5.08,0,0,0,20,19.05h0a5.39,5.39,0,0,0,.43-1.2,4.91,4.91,0,0,0-1-4.06l-2.66-3.34A5.17,5.17,0,0,0,12.65,8.5Z" /> d="M12.65,8.5H10.42a5.18,5.18,0,0,0-4,1.95L3.75,13.74a5,5,0,0,0-.68,5.31l0,0h0a5.07,5.07,0,0,0,4.5,2.73h7.88A5.08,5.08,0,0,0,20,19.05h0a5.39,5.39,0,0,0,.43-1.2,4.91,4.91,0,0,0-1-4.06l-2.66-3.34A5.17,5.17,0,0,0,12.65,8.5Z" />
@ -502,7 +506,9 @@
<sm-input id="get_loan_amount" type="number" min="1" step="0.01" error-text="Amount should be at least ₹1" <sm-input id="get_loan_amount" type="number" min="1" step="0.01" error-text="Amount should be at least ₹1"
placeholder="₹Amount" required> placeholder="₹Amount" required>
</sm-input> </sm-input>
<sm-button id="loan_button" variant="primary" disabled onclick="initLoan()">Request loan</sm-button> <div id="loan_button_wrapper" class="loader-button-wrapper">
<sm-button id="loan_button" variant="primary" disabled onclick="initLoan()">Request loan</sm-button>
</div>
</sm-form> </sm-form>
</article> </article>
<article id="result" class="page hide-completely page-layout"> <article id="result" class="page hide-completely page-layout">
@ -607,6 +613,25 @@
<p class="step__description"></p> <p class="step__description"></p>
</div> </div>
</template> </template>
<template id="pending_transaction_template">
<details open>
<summary>
<h4>Pending transaction</h4>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z" />
</svg>
</summary>
<a id="pending_request" class="activity-card activity-card--pending interact">
<div class="activity-card__icon pending"></div>
<div class="activity-card__title"></div>
<p class="activity-card__description">
You won't be able to do deposit or get a loan till process is completed.
</p>
<h4 class="activity-card__amount"></h4>
</a>
</details>
</template>
<script id="ui_utils"> <script id="ui_utils">
// Global variables // Global variables
const domRefs = {}; const domRefs = {};
@ -896,11 +921,14 @@
break; break;
case 'deposit': case 'deposit':
const { I_s } = bank_app.getRates() const { I_s } = bank_app.getRates()
getRef('deposit_interest_rate').textContent = `Make a deposit at ${I_s * 100}% rate of interest` getRef('deposit_interest_rate').textContent = `Make a deposit at ${I_s * 100}%.p.a`
// checks if there is transaction pending, if so then shows warning
checkIfAllowed('deposit')
break; break;
case 'loan': case 'loan':
const { I_b } = bank_app.getRates() const { I_b } = bank_app.getRates()
getRef('loan_interest_rate').textContent = `Get a loan at ${I_b * 100}% rate of interest` getRef('loan_interest_rate').textContent = `Get a loan at ${I_b * 100}%.p.a`
checkIfAllowed('loan')
break; break;
case 'transaction': case 'transaction':
showTransactionDetails(params) showTransactionDetails(params)
@ -939,6 +967,7 @@
accountLoader = new LazyLoader('#user_accounts', getAccounts, render.accountCard, { batchSize: 10 }) accountLoader = new LazyLoader('#user_accounts', getAccounts, render.accountCard, { batchSize: 10 })
accountLoader.init() accountLoader.init()
} }
checkPendingTransaction()
break; break;
case 'admin': case 'admin':
if (pagesData.openedSubPages.includes(subPageId)) { if (pagesData.openedSubPages.includes(subPageId)) {
@ -1125,6 +1154,15 @@
break; break;
} }
return icon return icon
},
getLastTransaction() {
const allRequests = bank_app.viewAllRequests()
let key
for (key in allRequests);
return {
uid: key,
isPending: !requestResponsePairs.has(key)
}
} }
} }
const render = { const render = {
@ -1226,7 +1264,7 @@
card.setAttribute('href', `#/account?index=${index}`) card.setAttribute('href', `#/account?index=${index}`)
card.querySelector('.activity-card__icon').innerHTML = icon card.querySelector('.activity-card__icon').innerHTML = icon
card.querySelector('.activity-card__type').textContent = type card.querySelector('.activity-card__type').textContent = type
card.querySelector('.activity-card__time').textContent = getFormattedTime(parseInt(status === 'active' ? openTime : closeTime)) card.querySelector('.activity-card__time').textContent = getFormattedTime(parseInt(status === 'active' ? openTime : closeTime), true)
card.querySelector('.activity-card__amount').textContent = netAmt.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' }) card.querySelector('.activity-card__amount').textContent = netAmt.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
return card return card
}, },
@ -1259,7 +1297,7 @@
}) })
} }
function signOut() { function signOut() {
getConfirmation('Sign out?', 'You are about to sign out of the app, continue?') getConfirmation('Sign out?', 'You are about to sign out of the app, continue?', 'Stay', 'Leave')
.then(async (res) => { .then(async (res) => {
if (res) { if (res) {
await floDapps.clearCredentials() await floDapps.clearCredentials()
@ -1304,13 +1342,17 @@
index, index,
amount, amount,
rtype, rtype,
requestID: requestID, requestID,
timestamp: requestID.split('_')[0], timestamp: requestID.split('_')[0],
} }
if (reqStatus === 'completed') { if (reqStatus === 'completed') {
transactionDetails.status = 'completed' transactionDetails.status = 'completed'
} else { } else {
transactionDetails.status = requestResponsePairs[requestID] ? bank_app.viewAllResponses()[requestResponsePairs[requestID]].status : 'pending' if (requestResponsePairs.has(requestID)) {
transactionDetails.status = bank_app.viewAllResponses()[requestResponsePairs.get(requestID)].status
} else {
transactionDetails.status = 'pending'
}
} }
return transactionDetails return transactionDetails
} }
@ -1321,9 +1363,9 @@
for (const key in transactions) { for (const key in transactions) {
const details = getRequestDetails(key) const details = getRequestDetails(key)
if (details) if (details)
requests.push(details) requests.unshift(details)
} }
return requests.reverse() return requests
} }
function getResponses() { function getResponses() {
return utils.getArrayOfObj(bank_app.viewAllResponses()).reverse() return utils.getArrayOfObj(bank_app.viewAllResponses()).reverse()
@ -1356,8 +1398,8 @@
getRef('transaction__steps').innerHTML = '' getRef('transaction__steps').innerHTML = ''
getRef('transaction__steps').append(render.accountProgressStep('success', `Sent ${type} request`, getFormattedTime(timestamp))) getRef('transaction__steps').append(render.accountProgressStep('success', `Sent ${type} request`, getFormattedTime(timestamp)))
if (requestResponsePairs[requestID]) { if (requestResponsePairs.has(requestID)) {
const { status, reason } = bank_app.viewAllResponses()[requestResponsePairs[requestID]] const { status, reason } = bank_app.viewAllResponses()[requestResponsePairs.get(requestID)]
// Check if response is positive or not // Check if response is positive or not
if (status === 'success') { if (status === 'success') {
let action let action
@ -1491,17 +1533,17 @@
const { type, netAmt } = bank_app.getUserDetails(myFloID).accounts[index] const { type, netAmt } = bank_app.getUserDetails(myFloID).accounts[index]
let ans let ans
if (type === 'deposit') { if (type === 'deposit') {
ans = await getConfirmation('Withdraw deposit?', 'Are you sure to withdraw this deposit now?') ans = await getConfirmation('Withdraw deposit?', 'Are you sure to withdraw this deposit now?', 'No', 'Yes')
} else { } else {
ans = await getConfirmation('Repay loan?', 'Make sure you have required amount to repay the loan!') ans = await getConfirmation('Repay loan?', 'Make sure you have required amount to repay the loan!', 'No', 'Yes')
} }
if (ans) { if (ans) {
getRef('account_action_button').classList.add('hide-completely')
const actionToDo = type === 'deposit' ? 'withdraw' : 'Repay' const actionToDo = type === 'deposit' ? 'withdraw' : 'Repay'
getRef('account_process__steps').append(render.accountProgressStep('loading', `Sending ${actionToDo} request`)) getRef('account_process__steps').append(render.accountProgressStep('loading', `Sending ${actionToDo} request`))
if (type === 'deposit') { if (type === 'deposit') {
bank_app.withdrawDeposit(parseInt(index)) bank_app.withdrawDeposit(parseInt(index))
.then(res => { .then(res => {
getRef('account_process__steps').lastElementChild.remove()
renderAccountProgress(index) renderAccountProgress(index)
}) })
.catch(err => { .catch(err => {
@ -1513,7 +1555,6 @@
} else { } else {
bank_app.repayLoan(parseInt(index)) bank_app.repayLoan(parseInt(index))
.then(res => { .then(res => {
getRef('account_process__steps').lastElementChild.remove()
renderAccountProgress(index) renderAccountProgress(index)
}) })
.catch(err => { .catch(err => {
@ -1625,20 +1666,30 @@
getRef('result__icon').innerHTML = utils.getRelatedIcon(status) getRef('result__icon').innerHTML = utils.getRelatedIcon(status)
getRef('result__icon').className = status getRef('result__icon').className = status
getRef('result__back_button').href = `#/${type}` getRef('result__back_button').href = `#/${type}`
if (status === 'pending') { debugger
getRef('result__title').textContent = `Sent ${type} request` switch (status) {
getRef('result__description').textContent = `Waiting for ${type} confirmation. Meanwhile you can go back and continue using app.` case 'pending':
} else if (status === 'failed') { getRef('result__title').textContent = `Sent ${type} request`
getRef('result__title').textContent = `Failed to send ${type} request` getRef('result__description').textContent = `Waiting for ${type} confirmation. Meanwhile you can go back and continue using app.`
getRef('result__description').textContent = reason break
case 'failed':
getRef('result__title').textContent = `Failed to send ${type} request`
getRef('result__description').textContent = reason
break
case 'loading':
getRef('result__icon').innerHTML = '<sm-spinner></sm-spinner>'
getRef('result__title').textContent = `Sending ${type} request`
getRef('result__description').textContent = ''
break
} }
getRef(`get_${type}_amount`).value = '' getRef(`get_${type}_amount`).value = ''
} }
async function initDeposit() { async function initDeposit() {
const amount = parseFloat(getRef('get_deposit_amount').value) const amount = parseFloat(getRef('get_deposit_amount').value)
const confirm = await getConfirmation(`Confirm deposit of ${amount.toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}?`) const confirm = await getConfirmation(`Confirm deposit of ${amount.toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}?`, 'Cancel', 'Confirm')
if (confirm) { if (confirm) {
showProcess('deposit')
bank_app.makeDeposit(amount) bank_app.makeDeposit(amount)
.then(() => { .then(() => {
window.location.hash = `#/result?type=deposit&amount=${amount}&status=pending` window.location.hash = `#/result?type=deposit&amount=${amount}&status=pending`
@ -1646,12 +1697,16 @@
.catch(err => { .catch(err => {
window.location.hash = `#/result?type=deposit&amount=${amount}&status=failed&reason=${err}` window.location.hash = `#/result?type=deposit&amount=${amount}&status=failed&reason=${err}`
}) })
.finally(() => {
hideProcess('deposit')
})
} }
} }
async function initLoan() { async function initLoan() {
const amount = parseFloat(getRef('get_loan_amount').value) const amount = parseFloat(getRef('get_loan_amount').value)
const confirm = await getConfirmation(`Confirm loan of ${amount.toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}?`) const confirm = await getConfirmation(`Confirm loan of ${amount.toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}?`, 'Cancel', 'Confirm')
if (confirm) { if (confirm) {
showInitProcess('loan')
bank_app.requestLoan(amount) bank_app.requestLoan(amount)
.then(() => { .then(() => {
window.location.hash = `#/result?type=loan&amount=${amount}&status=pending` window.location.hash = `#/result?type=loan&amount=${amount}&status=pending`
@ -1659,9 +1714,21 @@
.catch(err => { .catch(err => {
window.location.hash = `#/result?type=loan&amount=${amount}&status=failed&reason=${err}` window.location.hash = `#/result?type=loan&amount=${amount}&status=failed&reason=${err}`
}) })
.finally(() => {
hideProcess('loan')
})
} }
} }
function showProcess(type) {
getRef(`${type}_button_wrapper`).children[0].classList.add('clip')
getRef(`${type}_button_wrapper`).append(document.createElement('sm-spinner'))
}
function hideProcess(type) {
getRef(`${type}_button_wrapper`).children[0].classList.remove('clip')
getRef(`${type}_button_wrapper`).children[1].remove()
}
function toggleUserSection() { function toggleUserSection() {
getRef('user_section').classList.toggle('reveal') getRef('user_section').classList.toggle('reveal')
} }
@ -1711,11 +1778,71 @@
} }
} }
}) })
function checkPendingTransaction() {
const { isPending, uid } = utils.getLastTransaction()
if (uid) {
const { amount, rtype } = getRequestDetails(uid)
getRef('pending_transaction').innerHTML = ''
if (isPending && (rtype === 'openDeposit' || rtype === 'openLoan')) {
const card = getRef('pending_transaction_template').content.cloneNode(true)
const action = rtype === 'openDeposit' ? 'Deposit' : 'Loan'
card.querySelector('.activity-card').setAttribute('href', `#/transaction?requestID=${uid}`)
card.querySelector('.activity-card__icon').innerHTML = utils.getRelatedIcon('pending')
card.querySelector('.activity-card__title').textContent = `${action} in process`
card.querySelector('.activity-card__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
getRef('pending_transaction').append(card)
getRef('quick_actions_container').querySelectorAll('a').forEach(elem => {
elem.classList.add('disabled')
})
} else {
getRef('quick_actions_container').querySelectorAll('a').forEach(elem => {
elem.classList.remove('disabled')
})
}
}
}
function checkIfAllowed(type) {
const { isPending, uid } = utils.getLastTransaction()
getRef(`${type}_button`).nextElementSibling?.remove()
// check if there is a last transaction
if (uid) {
const { amount, rtype } = getRequestDetails(uid)
if (isPending && (rtype === 'openDeposit' || rtype === 'openLoan')) {
const action = rtype === 'openDeposit' ? 'Deposit' : 'Loan'
getRef(`${type}_button`).classList.add('hide-completely')
getRef(`${type}_button`).after(createElement('strong', {
textContent: `${action} in process. You can't ${type === 'deposit' ? 'deposit' : 'request loan'} until that's completed.`,
attributes: { 'style': 'background-color: khaki; color: rgba(0,0,0,0.7); padding: 1rem; border-radius: 0.5rem' }
}))
}
} else {
getRef(`${type}_button`).classList.remove('hide-completely')
}
}
let requestResponsePairs
class ReqResp {
constructor() {
this._mappedRequests = new Map()
}
get mappedRequests() {
return this._mappedRequests
}
updateMap() {
const allResponses = bank_app.viewAllResponses()
for (const key in allResponses) {
// stores requests as requests => response relation
this._mappedRequests.set(allResponses[key].requestID, key)
}
}
}
const requestResponse = new ReqResp()
</script> </script>
<script id="onLoadStartUp"> <script id="onLoadStartUp">
const requestResponsePairs = {} let isStartUpComplete
function onLoadStartUp() { function onLoadStartUp() {
isStartUpComplete = false
//floDapps.addStartUpFunction('Sample', Promised Function) //floDapps.addStartUpFunction('Sample', Promised Function)
//floDapps.setAppObjectStores({sampleObs1:{}, sampleObs2:{options{autoIncrement:true, keyPath:'SampleKey'}, Indexes:{sampleIndex:{}}}}) //floDapps.setAppObjectStores({sampleObs1:{}, sampleObs2:{options{autoIncrement:true, keyPath:'SampleKey'}, Indexes:{sampleIndex:{}}}})
floDapps.setCustomPrivKeyInput(getSignedIn) floDapps.setCustomPrivKeyInput(getSignedIn)
@ -1732,20 +1859,18 @@
getRef('user_flo_id').value = myFloID getRef('user_flo_id').value = myFloID
// alert(`Welcome FLO_ID: ${myFloID}`); // alert(`Welcome FLO_ID: ${myFloID}`);
//App functions.... //App functions....
bank_app.launchApp(reqCallback, DummyCallBack) bank_app.launchApp(reqCallback, responseCallback)
.then(result => { .then(result => {
isStartUpComplete = true
console.log(result) console.log(result)
// create pairs of requestIDs and their respective responses for efficient lookup
requestResponse.updateMap()
requestResponsePairs = requestResponse.mappedRequests
if (floGlobals.adminID === myFloID) { if (floGlobals.adminID === myFloID) {
console.log('Logged in as admin') console.log('Logged in as admin')
document.querySelectorAll('.admin-option').forEach(option => option.classList.remove('hide-completely')) document.querySelectorAll('.admin-option').forEach(option => option.classList.remove('hide-completely'))
document.querySelectorAll('.user-option').forEach(option => option.classList.add('hide-completely')) document.querySelectorAll('.user-option').forEach(option => option.classList.add('hide-completely'))
} else { } else {
// create pairs of requestIDs and their respective responses for efficient lookup
const allResponses = bank_app.viewAllResponses()
for (const key in allResponses) {
const { requestID } = allResponses[key]
requestResponsePairs[requestID] = key
}
chartObserver.observe(getRef('account_chart_container')) chartObserver.observe(getRef('account_chart_container'))
document.querySelectorAll('.admin-option').forEach(option => option.classList.add('hide-completely')) document.querySelectorAll('.admin-option').forEach(option => option.classList.add('hide-completely'))
document.querySelectorAll('.user-option').forEach(option => option.classList.remove('hide-completely')) document.querySelectorAll('.user-option').forEach(option => option.classList.remove('hide-completely'))
@ -1763,17 +1888,29 @@
const reqCallback = (d, e) => { const reqCallback = (d, e) => {
console.log(d) console.log(d)
if (isStartUpComplete) {
requestResponse.updateMap()
}
if (floGlobals.adminID === myFloID) { if (floGlobals.adminID === myFloID) {
if (adminRequestsLoader) { if (adminRequestsLoader) {
adminRequestsLoader.reset() adminRequestsLoader.reset()
notify('New request arrived') notify('New request arrived')
} }
} else {
// checkPendingTransaction()
} }
} }
const DummyCallBack = (d, e) => { const responseCallback = (d, e) => {
if (e) console.error("DummyCallback", e); if (e) console.error("DummyCallback", e);
console.log("DummyCallback", d); console.log("response", d);
if (floGlobals.adminID === myFloID) {
} else {
checkPendingTransaction()
}
if (isStartUpComplete) {
requestResponse.updateMap()
}
} }
</script> </script>
<script id="init_lib" version="1.0.1"> <script id="init_lib" version="1.0.1">
@ -11397,7 +11534,8 @@
acc[d[0]] = d[1]; acc[d[0]] = d[1];
break; break;
default: default:
console.warn("Unknown parse data", d); // console.warn("Unknown parse data", d);
console.warn("Unknown parse data");
} }
}); });
console.debug(time, txid, acc); console.debug(time, txid, acc);