code refactoring

This commit is contained in:
sairaj mote 2022-12-23 21:28:35 +05:30
parent 2cf02a5793
commit 110140219f
4 changed files with 263 additions and 368 deletions

View File

@ -365,6 +365,10 @@ ul {
fill: var(--accent-color); fill: var(--accent-color);
} }
sm-spinner {
--size: 1.2rem;
}
#confirmation_popup, #confirmation_popup,
#prompt_popup { #prompt_popup {
flex-direction: column; flex-direction: column;
@ -534,6 +538,7 @@ details[open] > summary .icon {
#loading sm-spinner { #loading sm-spinner {
justify-self: center; justify-self: center;
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
--size: 1.2rem;
} }
#home { #home {
@ -778,11 +783,6 @@ sm-chip:last-of-type {
grid-area: amount; grid-area: amount;
text-align: end; text-align: end;
} }
.activity-card--request sm-spinner,
.activity-card--pending sm-spinner {
--height: 1rem;
--width: 1rem;
}
.activity-card--admin { .activity-card--admin {
align-items: center; align-items: center;
@ -804,10 +804,6 @@ sm-chip:last-of-type {
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
} }
.activity-card--admin sm-spinner {
--height: 1rem;
--width: 1rem;
}
#pending_transaction:not(:empty) { #pending_transaction:not(:empty) {
margin-bottom: 2rem; margin-bottom: 2rem;
@ -920,10 +916,6 @@ sm-chip:last-of-type {
pointer-events: none; pointer-events: none;
background-color: transparent; background-color: transparent;
} }
#refresh_balance_button sm-spinner {
--height: 1rem;
--width: 1rem;
}
#account_chart_container { #account_chart_container {
display: flex; display: flex;
@ -964,9 +956,7 @@ sm-chip:last-of-type {
} }
.balance-card { .balance-card {
display: grid; display: flex;
grid-template-columns: auto 1fr;
grid-template-areas: "icon ." "icon .";
padding: 1rem 0; padding: 1rem 0;
align-items: center; align-items: center;
gap: 0.3rem 1rem; gap: 0.3rem 1rem;
@ -992,6 +982,7 @@ sm-chip:last-of-type {
.balance-card__amount { .balance-card__amount {
font-size: 1rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
margin-left: auto;
} }
.page__header button { .page__header button {
@ -1100,10 +1091,6 @@ sm-chip:last-of-type {
-webkit-animation-delay: 0.3s; -webkit-animation-delay: 0.3s;
animation-delay: 0.3s; animation-delay: 0.3s;
} }
.account-step sm-spinner {
--height: 1rem;
--width: 1rem;
}
.account-step:not(:last-of-type) .step__line { .account-step:not(:last-of-type) .step__line {
position: relative; position: relative;
height: 100%; height: 100%;
@ -1282,13 +1269,9 @@ sm-chip:last-of-type {
transform: none; transform: none;
} }
} }
#settings { #account_summary {
padding: 0 1.5rem; padding: 0 1.5rem;
} }
#settings sm-copy {
font-size: 0.9rem;
margin: 0.3rem 0 1.5rem 0;
}
#sign_out_button { #sign_out_button {
color: rgba(var(--background-color), 1); color: rgba(var(--background-color), 1);
@ -1363,8 +1346,8 @@ sm-chip:last-of-type {
.activity-card--account .grid { .activity-card--account .grid {
text-align: right; text-align: right;
} }
.hide-on-mobile { .hide-on-small {
display: none; display: none !important;
} }
} }
@media screen and (min-width: 640px) { @media screen and (min-width: 640px) {
@ -1473,24 +1456,6 @@ sm-chip:last-of-type {
justify-content: flex-start; justify-content: flex-start;
} }
} }
@media screen and (max-width: 1024px) {
#user_section {
position: fixed;
background-color: rgba(var(--background-color), 1);
transition: transform 0.3s;
z-index: 2;
right: 0;
top: 0;
bottom: 0;
padding-top: 0;
}
#user_section.reveal {
box-shadow: -0.5rem 0 1.5rem rgba(0, 0, 0, 0.1);
}
#user_section:not(.reveal) {
transform: translateX(100%);
}
}
@media screen and (min-width: 1024px) { @media screen and (min-width: 1024px) {
.page-layout { .page-layout {
grid-template-columns: 1fr 80vw 1fr; grid-template-columns: 1fr 80vw 1fr;

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -360,6 +360,10 @@ ul {
fill: var(--accent-color); fill: var(--accent-color);
} }
} }
sm-spinner {
--size: 1.2rem;
}
#confirmation_popup, #confirmation_popup,
#prompt_popup { #prompt_popup {
flex-direction: column; flex-direction: column;
@ -521,6 +525,7 @@ details {
sm-spinner { sm-spinner {
justify-self: center; justify-self: center;
margin-bottom: 1.5rem; margin-bottom: 1.5rem;
--size: 1.2rem;
} }
} }
#home { #home {
@ -745,10 +750,6 @@ sm-chip {
grid-area: amount; grid-area: amount;
text-align: end; text-align: end;
} }
sm-spinner {
--height: 1rem;
--width: 1rem;
}
} }
.activity-card--admin { .activity-card--admin {
align-items: center; align-items: center;
@ -769,10 +770,6 @@ sm-chip {
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
} }
sm-spinner {
--height: 1rem;
--width: 1rem;
}
} }
#pending_transaction:not(:empty) { #pending_transaction:not(:empty) {
margin-bottom: 2rem; margin-bottom: 2rem;
@ -882,10 +879,6 @@ sm-chip {
pointer-events: none; pointer-events: none;
background-color: transparent; background-color: transparent;
} }
sm-spinner {
--height: 1rem;
--width: 1rem;
}
} }
#account_chart_container { #account_chart_container {
@ -929,9 +922,7 @@ sm-chip {
} }
} }
.balance-card { .balance-card {
display: grid; display: flex;
grid-template-columns: auto 1fr;
grid-template-areas: "icon ." "icon .";
padding: 1rem 0; padding: 1rem 0;
align-items: center; align-items: center;
gap: 0.3rem 1rem; gap: 0.3rem 1rem;
@ -956,6 +947,7 @@ sm-chip {
&__amount { &__amount {
font-size: 1rem; font-size: 1rem;
font-weight: 700; font-weight: 700;
margin-left: auto;
} }
} }
@ -1050,10 +1042,6 @@ sm-chip {
&:nth-of-type(4) { &:nth-of-type(4) {
animation-delay: 0.3s; animation-delay: 0.3s;
} }
sm-spinner {
--height: 1rem;
--width: 1rem;
}
&:not(:last-of-type) .step__line { &:not(:last-of-type) .step__line {
position: relative; position: relative;
height: 100%; height: 100%;
@ -1202,12 +1190,8 @@ sm-chip {
transform: none; transform: none;
} }
} }
#settings { #account_summary {
padding: 0 1.5rem; padding: 0 1.5rem;
sm-copy {
font-size: 0.9rem;
margin: 0.3rem 0 1.5rem 0;
}
} }
#sign_out_button { #sign_out_button {
color: rgba(var(--background-color), 1); color: rgba(var(--background-color), 1);
@ -1283,8 +1267,8 @@ sm-chip {
text-align: right; text-align: right;
} }
} }
.hide-on-mobile { .hide-on-small {
display: none; display: none !important;
} }
} }
@media screen and (min-width: 640px) { @media screen and (min-width: 640px) {
@ -1401,24 +1385,6 @@ sm-chip {
} }
} }
} }
@media screen and (max-width: 1024px) {
#user_section {
position: fixed;
background-color: rgba(var(--background-color), 1);
transition: transform 0.3s;
z-index: 2;
right: 0;
top: 0;
bottom: 0;
padding-top: 0;
&.reveal {
box-shadow: -0.5rem 0 1.5rem rgba(0, 0, 0, 0.1);
}
&:not(.reveal) {
transform: translateX(100%);
}
}
}
@media screen and (min-width: 1024px) { @media screen and (min-width: 1024px) {
.page-layout { .page-layout {
grid-template-columns: 1fr 80vw 1fr; grid-template-columns: 1fr 80vw 1fr;

View File

@ -143,7 +143,7 @@
</article> </article>
<article id="home" class="page hidden"> <article id="home" class="page hidden">
<header id="main_header"> <header id="main_header">
<div class="logo hide-on-mobile"> <div class="logo hide-on-small">
<svg class="main-logo" viewBox="0 0 27.25 32"> <svg class="main-logo" viewBox="0 0 27.25 32">
<title>RanchiMall</title> <title>RanchiMall</title>
<path <path
@ -215,7 +215,7 @@
History History
</span> </span>
</a> </a>
<a href="#/home/settings" class="nav-item hide-on-desktop"> <a href="#/home/account_summary" class="nav-item hide-on-desktop">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" <svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px"
viewBox="0 0 24 24" width="24px" fill="#000000"> viewBox="0 0 24 24" width="24px" fill="#000000">
<g> <g>
@ -418,6 +418,7 @@
<p>You transaction activities will appear here.</h4> <p>You transaction activities will appear here.</h4>
</div> </div>
</div> </div>
<div id="account_summary" class="sub-page hidden"></div>
<div id="admin" class="sub-page hidden"> <div id="admin" class="sub-page hidden">
<div id="admin__header"> <div id="admin__header">
<h3 class="h3">Requests</h3> <h3 class="h3">Requests</h3>
@ -475,104 +476,7 @@
</div> </div>
</div> </div>
</section> </section>
<section id="user_section"> <section id="user_section" class="hide-on-small"></section>
<div id="user_section__header" class=" hide-on-desktop">
<button class="icon-button justify-self-start" onclick="toggleUserSection()">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd" />
</svg>
</button>
</div>
<div class="user-option">
<h4 class="flex align-center">
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg"
enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<g>
<rect fill="none" height="24" width="24" />
</g>
<g>
<g>
<g>
<path
d="M11,5.08V2C6,2.5,2,6.81,2,12s4,9.5,9,10v-3.08c-3-0.48-6-3.4-6-6.92S8,5.56,11,5.08z M18.97,11H22c-0.47-5-4-8.53-9-9 v3.08C16,5.51,18.54,8,18.97,11z M13,18.92V22c5-0.47,8.53-4,9-9h-3.03C18.54,16,16,18.49,13,18.92z" />
</g>
</g>
</g>
</svg>
Account summary
</h4>
<div id="account_chart_container">
<div id="chart_legend">
<div class="legend">Deposit</div>
<div class="legend">Loan</div>
</div>
<canvas id="account_summary_chart"></canvas>
</div>
<div class="balance-card">
<div class="balance-card__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24"
height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
<rect fill="none" height="24" width="24" />
<g>
<path
d="M19.83,7.5l-2.27-2.27c0.07-0.42,0.18-0.81,0.32-1.15C17.96,3.9,18,3.71,18,3.5C18,2.67,17.33,2,16.5,2 c-1.64,0-3.09,0.79-4,2l-5,0C4.46,4,2,6.46,2,9.5S4.5,21,4.5,21l5.5,0v-2h2v2l5.5,0l1.68-5.59L22,14.47V7.5H19.83z M13,9H8V7h5V9z M16,11c-0.55,0-1-0.45-1-1c0-0.55,0.45-1,1-1s1,0.45,1,1C17,10.55,16.55,11,16,11z" />
</g>
</svg>
</div>
<div class="balance-card__token">Total deposit</div>
<div id="total_deposit" class="balance-card__amount"></div>
</div>
<div class="balance-card">
<div class="balance-card__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<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" />
<path
d="M9.71,6.59h3.94A2.94,2.94,0,0,0,16,5.39h0a1.13,1.13,0,0,0-.23-1.57,1.11,1.11,0,0,0-.95-.18h0a1.2,1.2,0,0,1-.92-.18l-.28-.21a3.64,3.64,0,0,0-4.22,0h0a1.18,1.18,0,0,1-1,.16L8.2,3.35a1.13,1.13,0,0,0-1.36.84A1.17,1.17,0,0,0,7,5H7A3.18,3.18,0,0,0,9.71,6.59Z" />
</svg>
</div>
<div class="balance-card__token">Total loan</div>
<div id="total_loan" class="balance-card__amount"></div>
</div>
</div>
<div>
<h4 class="flex align-center space-between">
<svg class="icon button__icon--left" 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="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" />
</svg>
My balance
<button id="refresh_balance_button" class="button justify-right" onclick="refreshBalance(this)">
Refresh
</button>
</h4>
<div class="balance-card">
<div class="balance-card__icon">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM7 5a1 1 0 100 2h1a2 2 0 011.732 1H7a1 1 0 100 2h2.732A2 2 0 018 11H7a1 1 0 00-.707 1.707l3 3a1 1 0 001.414-1.414l-1.483-1.484A4.008 4.008 0 0011.874 10H13a1 1 0 100-2h-1.126a3.976 3.976 0 00-.41-1H13a1 1 0 100-2H7z"
clip-rule="evenodd" />
</svg>
</div>
<div class="balance-card__token">Rupee</div>
<div id="rupee_balance" class="balance-card__amount"></div>
</div>
<div class="balance-card">
<div class="balance-card__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
d="M16.36,15.39c1.83,0,4.26-2.49,4.36-4.74-5.65-.19-4.91.47-7.28,2.39,2.19-2.4,1.42-7.79-1.43-10V6.17c2.33,1.49,2.21,5.14,0,7.15-2.23-2-2.27-5.69,0-7.15V3c-2.83,2.26-3.62,7.66-1.44,10-2.36-1.93-1.63-2.58-7.28-2.39.1,2.26,2.55,4.73,4.36,4.74,0,0-1.93.22-2.74-2.62,2.38-.37,4.29-.14,6.28,2-.79-.11-4.89,1.13-4.38,3.26.53.06,3,.3,3.58-.83-.17.18-1.25.5-1.53.05.38-1.39,2.32-2,2.32-2-1,1.82-.48,4.63.82,5.72,1.31-1.08,1.8-3.95.82-5.72,0,0,1.95.6,2.32,2-.29.46-1.36.12-1.53-.05.58,1.14,3.06.88,3.58.83.49-2.17-3.58-3.36-4.38-3.26,2-2.17,3.92-2.39,6.28-2C18.3,15.62,16.36,15.39,16.36,15.39ZM12,19.46c-.91-.79-.5-3,0-3.59C12.5,16.45,12.91,18.66,12,19.46Z" />
</svg>
</div>
<div class="balance-card__token">FLO</div>
<div id="flo_balance" class="balance-card__amount"></div>
</div>
</div>
</section>
</article> </article>
<article id="deposit" class="page hidden page-layout"> <article id="deposit" class="page hidden page-layout">
<a class="button icon-button justify-self-start" href="#/home/dashboard"> <a class="button icon-button justify-self-start" href="#/home/dashboard">
@ -799,28 +703,13 @@
floGlobals.connectionErrorNotification = notify('There seems to be a problem connecting to the internet, Please check you internet connection.', 'error') floGlobals.connectionErrorNotification = notify('There seems to be a problem connecting to the internet, Please check you internet connection.', 'error')
}) })
window.addEventListener('online', () => { window.addEventListener('online', () => {
getRef('notification_drawer').remove(floGlobals.connectionErrorNotification) getById('notification_drawer').remove(floGlobals.connectionErrorNotification)
notify('We are back online.', 'success') notify('We are back online.', 'success')
}) })
// Use instead of document.getElementById // Use instead of document.getElementById
function getRef(elementId) { function getById(elementId) {
if (!domRefs.hasOwnProperty(elementId)) { return document.getElementById(elementId)
domRefs[elementId] = {
count: 1,
ref: null,
};
return document.getElementById(elementId);
} else {
if (domRefs[elementId].count < 3) {
domRefs[elementId].count = domRefs[elementId].count + 1;
return document.getElementById(elementId);
} else {
if (!domRefs[elementId].ref)
domRefs[elementId].ref = document.getElementById(elementId);
return domRefs[elementId].ref;
}
}
} }
// returns dom with specified element // returns dom with specified element
@ -843,8 +732,8 @@
// function required for popups or modals to appear // function required for popups or modals to appear
function openPopup(popupId, pinned) { function openPopup(popupId, pinned) {
zIndex++ zIndex++
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`) getById(popupId).setAttribute('style', `z-index: ${zIndex}`)
return getRef(popupId).show({ pinned }) return getById(popupId).show({ pinned })
} }
// hides the popup or modal // hides the popup or modal
@ -856,14 +745,14 @@
document.addEventListener('popupopened', e => { document.addEventListener('popupopened', e => {
switch (e.target.id) { switch (e.target.id) {
case 'profile_popup': case 'profile_popup':
renderElem(getRef('profile_popup__content'), render.profile()) renderElem(getById('profile_popup__content'), render.profile())
break; break;
} }
}) })
document.addEventListener('popupclosed', e => { document.addEventListener('popupclosed', e => {
switch (e.target.id) { switch (e.target.id) {
case 'profile_popup': case 'profile_popup':
renderElem(getRef('profile_popup__content'), html``) renderElem(getById('profile_popup__content'), html``)
break; break;
} }
zIndex--; zIndex--;
@ -872,10 +761,10 @@
const getConfirmation = (title, options = {}) => { const getConfirmation = (title, options = {}) => {
return new Promise(resolve => { return new Promise(resolve => {
const { message = '', cancelText = 'Cancel', confirmText = 'OK', danger = false } = options const { message = '', cancelText = 'Cancel', confirmText = 'OK', danger = false } = options
getRef('confirm_title').innerText = title; getById('confirm_title').innerText = title;
getRef('confirm_message').innerText = message; getById('confirm_message').innerText = message;
const cancelButton = getRef('confirmation_popup').querySelector('.cancel-button'); const cancelButton = getById('confirmation_popup').querySelector('.cancel-button');
const confirmButton = getRef('confirmation_popup').querySelector('.confirm-button') const confirmButton = getById('confirmation_popup').querySelector('.confirm-button')
confirmButton.textContent = confirmText confirmButton.textContent = confirmText
cancelButton.textContent = cancelText cancelButton.textContent = cancelText
if (danger) if (danger)
@ -915,7 +804,7 @@
if (mode === 'error') { if (mode === 'error') {
console.error(message) console.error(message)
} }
return getRef("notification_drawer").push(message, { icon, ...options }); return getById("notification_drawer").push(message, { icon, ...options });
} }
function getFormattedTime(timestamp, format) { function getFormattedTime(timestamp, format) {
@ -955,7 +844,7 @@
} }
} }
window.addEventListener('hashchange', e => showPage(window.location.hash)) window.addEventListener('hashchange', e => routeTo(window.location.hash))
window.addEventListener("load", () => { window.addEventListener("load", () => {
document.body.classList.remove('hidden') document.body.classList.remove('hidden')
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)
@ -980,7 +869,7 @@
let accountLoader let accountLoader
let accountChart let accountChart
let adminRequestsLoader let adminRequestsLoader
async function showPage(targetPage, options = {}) { async function routeTo(targetPage, options = {}) {
const { firstLoad, hashChange } = options const { firstLoad, hashChange } = options
let pageId let pageId
let subPageId let subPageId
@ -1020,24 +909,24 @@
switch (pageId) { switch (pageId) {
case 'sign_in': case 'sign_in':
setTimeout(() => { setTimeout(() => {
getRef('private_key_field').focusIn() getById('private_key_field').focusIn()
}, 0); }, 0);
break; break;
case 'sign_up': case 'sign_up':
const { floID, privKey } = floCrypto.generateNewID() const { floID, privKey } = floCrypto.generateNewID()
getRef('generated_flo_id').value = floID getById('generated_flo_id').value = floID
getRef('generated_private_key').value = privKey getById('generated_private_key').value = privKey
break; break;
case 'deposit': case 'deposit':
const { I_s } = bank_app.getRates() const { I_s } = bank_app.getRates()
getRef('deposit_interest_rate').textContent = (I_s * 100).toFixed(2) getById('deposit_interest_rate').textContent = (I_s * 100).toFixed(2)
// checks if there is transaction pending, if so then shows warning // checks if there is transaction pending, if so then shows warning
checkIfAllowed('deposit') checkIfAllowed('deposit')
checkTouchSupport(window.matchMedia("(any-hover: hover)")) checkTouchSupport(window.matchMedia("(any-hover: hover)"))
break; break;
case 'loan': case 'loan':
const { I_b } = bank_app.getRates() const { I_b } = bank_app.getRates()
getRef('loan_interest_rate').textContent = (I_b * 100).toFixed(2) getById('loan_interest_rate').textContent = (I_b * 100).toFixed(2)
checkIfAllowed('loan') checkIfAllowed('loan')
checkTouchSupport(window.matchMedia("(any-hover: hover)")) checkTouchSupport(window.matchMedia("(any-hover: hover)"))
break; break;
@ -1052,8 +941,8 @@
break; break;
} }
document.querySelector('.page:not(.hidden)')?.classList.add('hidden') document.querySelector('.page:not(.hidden)')?.classList.add('hidden')
getRef(pageId)?.classList.remove('hidden') getById(pageId)?.classList.remove('hidden')
getRef(pageId)?.animate([ getById(pageId)?.animate([
{ {
opacity: 0, opacity: 0,
}, },
@ -1067,9 +956,19 @@
}) })
} }
if (subPageId) { if (subPageId) {
getRef('all_responses_list').innerHTML = '' getById('all_responses_list').innerHTML = ''
getRef('all_requests_list').innerHTML = '' getById('all_requests_list').innerHTML = ''
getRef('user_accounts').innerHTML = '' getById('user_accounts').innerHTML = ''
if (floGlobals.isMobileView) {
if (accountChart)
accountChart.destroy()
renderElem(getById('user_section'), html``)
} else {
renderElem(getById('user_section'), render.accountSummary())
chartObserver.disconnect()
chartObserver.observe(getById('account_chart_container'))
refreshBalance()
}
switch (subPageId) { switch (subPageId) {
case 'dashboard': case 'dashboard':
if (pagesData.openedSubPages.includes(subPageId)) { if (pagesData.openedSubPages.includes(subPageId)) {
@ -1081,8 +980,8 @@
checkPendingTransaction() checkPendingTransaction()
hideProcess('deposit') hideProcess('deposit')
hideProcess('loan') hideProcess('loan')
getRef('get_deposit_amount').value = '' getById('get_deposit_amount').value = ''
getRef('get_loan_amount').value = '' getById('get_loan_amount').value = ''
break; break;
case 'admin': case 'admin':
if (pagesData.openedSubPages.includes(subPageId)) { if (pagesData.openedSubPages.includes(subPageId)) {
@ -1099,7 +998,7 @@
responseLoader = new LazyLoader('#all_responses_list', getResponses, render.responseCard, { batchSize: 10 }) responseLoader = new LazyLoader('#all_responses_list', getResponses, render.responseCard, { batchSize: 10 })
responseLoader.init() responseLoader.init()
} }
getRef('notifications_page_button').classList.remove('has-notification') getById('notifications_page_button').classList.remove('has-notification')
break; break;
case 'history': case 'history':
if (pagesData.openedSubPages.includes(subPageId)) { if (pagesData.openedSubPages.includes(subPageId)) {
@ -1109,12 +1008,18 @@
requestLoader.init() requestLoader.init()
} }
break; break;
case 'account_summary':
renderElem(getById('account_summary'), render.accountSummary())
refreshBalance()
chartObserver.disconnect()
chartObserver.observe(getById('account_chart_container'))
break;
} }
document.querySelector('.sub-page:not(.hidden)')?.classList.add('hidden') document.querySelector('.sub-page:not(.hidden)')?.classList.add('hidden')
getRef(subPageId)?.classList.remove('hidden') getById(subPageId)?.classList.remove('hidden')
getRef('main_nav').querySelectorAll('.nav-item--active').forEach(item => item.classList.remove('nav-item--active')) getById('main_nav').querySelectorAll('.nav-item--active').forEach(item => item.classList.remove('nav-item--active'))
getRef('main_nav').querySelector(`.nav-item[href="#/${pageId}/${subPageId ? subPageId : ''}"]`).classList.add('nav-item--active') getById('main_nav').querySelector(`.nav-item[href="#/${pageId}/${subPageId ? subPageId : ''}"]`).classList.add('nav-item--active')
getRef(subPageId)?.animate([ getById(subPageId)?.animate([
{ {
opacity: 0, opacity: 0,
transform: 'translateY(1rem)' transform: 'translateY(1rem)'
@ -1212,6 +1117,21 @@
this.render() this.render()
} }
} }
const mobileQuery = window.matchMedia('(max-width: 40rem)')
function handleMobileChange(e) {
floGlobals.isMobileView = e.matches
routeTo(window.location.hash)
if (floGlobals.isMobileView) {
} else {
}
}
mobileQuery.addEventListener('change', handleMobileChange)
handleMobileChange(mobileQuery)
const reduceMotionQuery = window.matchMedia('(prefers-reduced-motion: reduce)');
reduceMotionQuery.addEventListener('change', () => {
floGlobals.prefersReducedMotion = reduceMotionQuery.matches
});
floGlobals.prefersReducedMotion = reduceMotionQuery.matches
</script> </script>
<script id="ui_functions"> <script id="ui_functions">
const utils = { const utils = {
@ -1291,9 +1211,9 @@
const render = { const render = {
adminRequestCard(activityDetails = {}) { adminRequestCard(activityDetails = {}) {
const { rtype, id, status } = activityDetails const { rtype, id, status } = activityDetails
const card = getRef('admin_request_template').content.cloneNode(true).firstElementChild const card = getById('admin_request_template').content.cloneNode(true).firstElementChild
const icon = utils.getRelatedIcon(rtype) const icon = utils.getRelatedIcon(rtype)
const selectedStatus = getRef('admin_request_selector').value const selectedStatus = getById('admin_request_selector').value
let action = '' let action = ''
switch (rtype) { switch (rtype) {
case 'openDeposit': case 'openDeposit':
@ -1320,7 +1240,7 @@
}, },
requestCard(activityDetails = {}) { requestCard(activityDetails = {}) {
const { requestID, amount, rtype, timestamp, status } = activityDetails const { requestID, amount, rtype, timestamp, status } = activityDetails
const card = getRef('request_template').content.cloneNode(true).firstElementChild const card = getById('request_template').content.cloneNode(true).firstElementChild
const icon = utils.getRelatedIcon(rtype) const icon = utils.getRelatedIcon(rtype)
let action = '' let action = ''
switch (rtype) { switch (rtype) {
@ -1353,7 +1273,7 @@
amount = bank_app.getUserDetails(myFloID).accounts[index].amount amount = bank_app.getUserDetails(myFloID).accounts[index].amount
} }
const timestamp = id.split('_')[0] const timestamp = id.split('_')[0]
const card = getRef('response_template').content.cloneNode(true).firstElementChild const card = getById('response_template').content.cloneNode(true).firstElementChild
const icon = utils.getRelatedIcon(status) const icon = utils.getRelatedIcon(status)
let action = '' let action = ''
switch (rtype) { switch (rtype) {
@ -1384,7 +1304,7 @@
accountCard(accountDetails = {}) { accountCard(accountDetails = {}) {
const { type, status, openTime, closeTime = 0, amount, netAmt } = accountDetails const { type, status, openTime, closeTime = 0, amount, netAmt } = accountDetails
let index = bank_app.getUserDetails(myFloID).accounts.findIndex(({ openTime: ot }) => ot == openTime) let index = bank_app.getUserDetails(myFloID).accounts.findIndex(({ openTime: ot }) => ot == openTime)
const card = getRef('account_template').content.cloneNode(true).firstElementChild const card = getById('account_template').content.cloneNode(true).firstElementChild
const icon = utils.getRelatedIcon(type) const icon = utils.getRelatedIcon(type)
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
@ -1395,7 +1315,7 @@
}, },
accountProgressStep(type, title, description = '', options = {}) { accountProgressStep(type, title, description = '', options = {}) {
const { openTx, closeTx } = options const { openTx, closeTx } = options
const elem = getRef('account_step_template').content.cloneNode(true).firstElementChild const elem = getById('account_step_template').content.cloneNode(true).firstElementChild
elem.classList.add(type) elem.classList.add(type)
elem.querySelector('.step__icon').innerHTML = type === 'loading' ? '<sm-spinner></sm-spinner>' : utils.getRelatedIcon(type) elem.querySelector('.step__icon').innerHTML = type === 'loading' ? '<sm-spinner></sm-spinner>' : utils.getRelatedIcon(type)
elem.querySelector('.step__title').textContent = title elem.querySelector('.step__title').textContent = title
@ -1410,6 +1330,60 @@
} }
return elem return elem
}, },
accountSummary() {
return html`
<div class="user-option">
<h4 class="flex align-center">
<svg class="icon button__icon--left" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <g> <rect fill="none" height="24" width="24" /> </g> <g> <g> <g> <path d="M11,5.08V2C6,2.5,2,6.81,2,12s4,9.5,9,10v-3.08c-3-0.48-6-3.4-6-6.92S8,5.56,11,5.08z M18.97,11H22c-0.47-5-4-8.53-9-9 v3.08C16,5.51,18.54,8,18.97,11z M13,18.92V22c5-0.47,8.53-4,9-9h-3.03C18.54,16,16,18.49,13,18.92z" /> </g> </g> </g> </svg>
Account summary
</h4>
<div id="account_chart_container">
<div id="chart_legend">
<div class="legend">Deposit</div>
<div class="legend">Loan</div>
</div>
<canvas id="account_summary_chart"></canvas>
</div>
<div class="balance-card">
<div class="balance-card__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"> <rect fill="none" height="24" width="24" /> <g> <path d="M19.83,7.5l-2.27-2.27c0.07-0.42,0.18-0.81,0.32-1.15C17.96,3.9,18,3.71,18,3.5C18,2.67,17.33,2,16.5,2 c-1.64,0-3.09,0.79-4,2l-5,0C4.46,4,2,6.46,2,9.5S4.5,21,4.5,21l5.5,0v-2h2v2l5.5,0l1.68-5.59L22,14.47V7.5H19.83z M13,9H8V7h5V9z M16,11c-0.55,0-1-0.45-1-1c0-0.55,0.45-1,1-1s1,0.45,1,1C17,10.55,16.55,11,16,11z" /> </g> </svg>
</div>
<div class="balance-card__token">Total deposit</div>
<div id="total_deposit" class="balance-card__amount"></div>
</div>
<div class="balance-card">
<div class="balance-card__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <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" /> <path d="M9.71,6.59h3.94A2.94,2.94,0,0,0,16,5.39h0a1.13,1.13,0,0,0-.23-1.57,1.11,1.11,0,0,0-.95-.18h0a1.2,1.2,0,0,1-.92-.18l-.28-.21a3.64,3.64,0,0,0-4.22,0h0a1.18,1.18,0,0,1-1,.16L8.2,3.35a1.13,1.13,0,0,0-1.36.84A1.17,1.17,0,0,0,7,5H7A3.18,3.18,0,0,0,9.71,6.59Z" /> </svg>
</div>
<div class="balance-card__token">Total loan</div>
<div id="total_loan" class="balance-card__amount"></div>
</div>
</div>
<div>
<h4 class="flex align-center space-between">
<svg class="icon button__icon--left" 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="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" /> </svg>
My balance
<button id="refresh_balance_button" class="button justify-right" onclick="refreshBalance(this)">
Refresh
</button>
</h4>
<div class="balance-card">
<div class="balance-card__icon">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor"> <path fill-rule="evenodd" d="M10 18a8 8 0 100-16 8 8 0 000 16zM7 5a1 1 0 100 2h1a2 2 0 011.732 1H7a1 1 0 100 2h2.732A2 2 0 018 11H7a1 1 0 00-.707 1.707l3 3a1 1 0 001.414-1.414l-1.483-1.484A4.008 4.008 0 0011.874 10H13a1 1 0 100-2h-1.126a3.976 3.976 0 00-.41-1H13a1 1 0 100-2H7z" clip-rule="evenodd" /> </svg>
</div>
<div class="balance-card__token">Rupee</div>
<div id="rupee_balance" class="balance-card__amount"></div>
</div>
<div class="balance-card">
<div class="balance-card__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M16.36,15.39c1.83,0,4.26-2.49,4.36-4.74-5.65-.19-4.91.47-7.28,2.39,2.19-2.4,1.42-7.79-1.43-10V6.17c2.33,1.49,2.21,5.14,0,7.15-2.23-2-2.27-5.69,0-7.15V3c-2.83,2.26-3.62,7.66-1.44,10-2.36-1.93-1.63-2.58-7.28-2.39.1,2.26,2.55,4.73,4.36,4.74,0,0-1.93.22-2.74-2.62,2.38-.37,4.29-.14,6.28,2-.79-.11-4.89,1.13-4.38,3.26.53.06,3,.3,3.58-.83-.17.18-1.25.5-1.53.05.38-1.39,2.32-2,2.32-2-1,1.82-.48,4.63.82,5.72,1.31-1.08,1.8-3.95.82-5.72,0,0,1.95.6,2.32,2-.29.46-1.36.12-1.53-.05.58,1.14,3.06.88,3.58.83.49-2.17-3.58-3.36-4.38-3.26,2-2.17,3.92-2.39,6.28-2C18.3,15.62,16.36,15.39,16.36,15.39ZM12,19.46c-.91-.79-.5-3,0-3.59C12.5,16.45,12.91,18.66,12,19.46Z" /> </svg>
</div>
<div class="balance-card__token">FLO</div>
<div id="flo_balance" class="balance-card__amount"></div>
</div>
</div>
`
},
profile() { profile() {
return html` return html`
<div class="grid gap-1-5"> <div class="grid gap-1-5">
@ -1425,19 +1399,19 @@
function getSignedIn() { function getSignedIn() {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) { if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) {
showPage(window.location.hash) routeTo(window.location.hash)
} else { } else {
showPage('landing') routeTo('landing')
} }
getRef('sign_in_button').onclick = () => { getById('sign_in_button').onclick = () => {
resolve(getRef('private_key_field').value.trim()) resolve(getById('private_key_field').value.trim())
getRef('private_key_field').value = '' getById('private_key_field').value = ''
showPage('loading') routeTo('loading')
} }
getRef('sign_up_button').onclick = () => { getById('sign_up_button').onclick = () => {
resolve(getRef('generated_private_key').value.trim()) resolve(getById('generated_private_key').value.trim())
getRef('generated_private_key').value = '' getById('generated_private_key').value = ''
showPage('loading') routeTo('loading')
} }
}) })
} }
@ -1459,10 +1433,12 @@
button.classList.add('loading') button.classList.add('loading')
button.innerHTML = `<sm-spinner></sm-spinner>` button.innerHTML = `<sm-spinner></sm-spinner>`
} }
getById('rupee_balance').innerHTML = `<sm-spinner></sm-spinner>`
getById('flo_balance').innerHTML = `<sm-spinner></sm-spinner>`
Promise.all([bank_app.tokenAPI.getBalance(myFloID), floBlockchainAPI.getBalance(myFloID)]) Promise.all([bank_app.tokenAPI.getBalance(myFloID), floBlockchainAPI.getBalance(myFloID)])
.then(([rupeeBalance, floBalance]) => { .then(([rupeeBalance, floBalance]) => {
getRef('rupee_balance').textContent = utils.formatAmount(rupeeBalance) getById('rupee_balance').textContent = utils.formatAmount(rupeeBalance)
getRef('flo_balance').textContent = floBalance getById('flo_balance').textContent = floBalance
if (button) { if (button) {
button.classList.remove('loading') button.classList.remove('loading')
button.textContent = `Refresh` button.textContent = `Refresh`
@ -1536,12 +1512,12 @@
} }
const icon = utils.getRelatedIcon(rtype) const icon = utils.getRelatedIcon(rtype)
const statusIcon = utils.getRelatedIcon(status) const statusIcon = utils.getRelatedIcon(status)
getRef('transaction_detail__icon').innerHTML = icon getById('transaction_detail__icon').innerHTML = icon
getRef('transaction_detail__type').textContent = type getById('transaction_detail__type').textContent = type
getRef('transaction_detail__amount').textContent = utils.formatAmount(amount) getById('transaction_detail__amount').textContent = utils.formatAmount(amount)
getRef('transaction__steps').innerHTML = '' getById('transaction__steps').innerHTML = ''
getRef('transaction__steps').append(render.accountProgressStep('success', `Sent ${type} request`, getFormattedTime(timestamp))) getById('transaction__steps').append(render.accountProgressStep('success', `Sent ${type} request`, getFormattedTime(timestamp)))
if (requestResponsePairs.hasOwnProperty(requestID)) { if (requestResponsePairs.hasOwnProperty(requestID)) {
const { status, reason } = bank_app.viewAllResponses()[requestResponsePairs[requestID]] const { status, reason } = bank_app.viewAllResponses()[requestResponsePairs[requestID]]
@ -1562,8 +1538,8 @@
type = 'loan repayment complete' type = 'loan repayment complete'
break; break;
} }
getRef('transaction__steps').append(render.accountProgressStep(status, action, getFormattedTime(timestamp))) getById('transaction__steps').append(render.accountProgressStep(status, action, getFormattedTime(timestamp)))
getRef('transaction__steps').append(createElement('a', { getById('transaction__steps').append(createElement('a', {
textContent: `View ${type} account`, textContent: `View ${type} account`,
attributes: { id: 'transaction__cta', href: `#/account?index=${index}` }, attributes: { id: 'transaction__cta', href: `#/account?index=${index}` },
className: 'button' className: 'button'
@ -1584,10 +1560,10 @@
type = 'repay loan' type = 'repay loan'
break; break;
} }
getRef('transaction__steps').append(render.accountProgressStep(status, `Failed to ${action}`, reason)) getById('transaction__steps').append(render.accountProgressStep(status, `Failed to ${action}`, reason))
} }
} else { } else {
getRef('transaction__steps').append(render.accountProgressStep('pending', `Waiting for ${type} request confirmation`, `You can continue using the app, you will get in-app notification once your request is processed.`)) getById('transaction__steps').append(render.accountProgressStep('pending', `Waiting for ${type} request confirmation`, `You can continue using the app, you will get in-app notification once your request is processed.`))
} }
} }
@ -1624,33 +1600,33 @@
function renderAccountProgress(index) { function renderAccountProgress(index) {
const { type, status, openTime, closeTime = undefined, amount, netAmt, openTx = undefined, closeTx = undefined } = bank_app.getUserDetails(myFloID).accounts[index] const { type, status, openTime, closeTime = undefined, amount, netAmt, openTx = undefined, closeTx = undefined } = bank_app.getUserDetails(myFloID).accounts[index]
getRef('account_process__steps').innerHTML = '' getById('account_process__steps').innerHTML = ''
getRef('account_process__steps').append(render.accountProgressStep('success', type === "deposit" ? 'Deposited' : 'Got loan', getFormattedTime(openTime), { openTx })) getById('account_process__steps').append(render.accountProgressStep('success', type === "deposit" ? 'Deposited' : 'Got loan', getFormattedTime(openTime), { openTx }))
const { isPending, pendingRequest } = getAccountStatus(index) const { isPending, pendingRequest } = getAccountStatus(index)
if (type === 'deposit') { if (type === 'deposit') {
if (isPending) { if (isPending) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Sent withdrawal request', getFormattedTime(pendingRequest.split('_')[0]))) getById('account_process__steps').append(render.accountProgressStep('success', 'Sent withdrawal request', getFormattedTime(pendingRequest.split('_')[0])))
getRef('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for withdrawal confirmation', `This may take upto 4hrs to be processed. Once your request is processed, your withdrawn amount will reflect in your balance.<br>meanwhile you can go back and continue using the app.`)) getById('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for withdrawal confirmation', `This may take upto 4hrs to be processed. Once your request is processed, your withdrawn amount will reflect in your balance.<br>meanwhile you can go back and continue using the app.`))
} else if (closeTime) { } else if (closeTime) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Withdrawal complete', getFormattedTime(closeTime), { closeTx })) getById('account_process__steps').append(render.accountProgressStep('success', 'Withdrawal complete', getFormattedTime(closeTime), { closeTx }))
} }
} else { } else {
if (isPending) { if (isPending) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Sent repay request', getFormattedTime(pendingRequest.split('_')[0]))) getById('account_process__steps').append(render.accountProgressStep('success', 'Sent repay request', getFormattedTime(pendingRequest.split('_')[0])))
getRef('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for repayment confirmation', `This may take upto 4hrs to be processed. Once your request is processed, your loan will be closed,`)) getById('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for repayment confirmation', `This may take upto 4hrs to be processed. Once your request is processed, your loan will be closed,`))
} else if (closeTime) { } else if (closeTime) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Repayment complete', getFormattedTime(closeTime), { closeTx })) getById('account_process__steps').append(render.accountProgressStep('success', 'Repayment complete', getFormattedTime(closeTime), { closeTx }))
} }
} }
} }
getRef('accounts_status_selector').addEventListener('change', e => { getById('accounts_status_selector').addEventListener('change', e => {
accountLoader.update(getAccounts()) accountLoader.update(getAccounts())
}) })
function getAccounts() { function getAccounts() {
bank_app.refreshData() bank_app.refreshData()
const statusFilter = getRef('accounts_status_selector').value const statusFilter = getById('accounts_status_selector').value
return bank_app.getUserDetails(myFloID).accounts.filter(({ status }) => status === statusFilter).reverse() return bank_app.getUserDetails(myFloID).accounts.filter(({ status }) => status === statusFilter).reverse()
} }
@ -1659,22 +1635,22 @@
const { type, status, openTime, closeTime = 0, amount, netAmt } = bank_app.getUserDetails(myFloID).accounts[index] const { type, status, openTime, closeTime = 0, amount, netAmt } = bank_app.getUserDetails(myFloID).accounts[index]
const icon = utils.getRelatedIcon(type) const icon = utils.getRelatedIcon(type)
const interest = netAmt - amount const interest = netAmt - amount
getRef('account_detail__icon').innerHTML = icon getById('account_detail__icon').innerHTML = icon
getRef('account_detail__status').textContent = status getById('account_detail__status').textContent = status
getRef('account_detail__status').className = `status-tag flex align-center ${status}` getById('account_detail__status').className = `status-tag flex align-center ${status}`
getRef('account_detail__type').textContent = type getById('account_detail__type').textContent = type
getRef('account_detail__amount').textContent = utils.formatAmount(amount) getById('account_detail__amount').textContent = utils.formatAmount(amount)
getRef('account_detail__interest_type').textContent = `Interest ${type === 'deposit' ? 'earned' : 'accrued'}` getById('account_detail__interest_type').textContent = `Interest ${type === 'deposit' ? 'earned' : 'accrued'}`
getRef('account_detail__interest').textContent = utils.formatAmount(interest) getById('account_detail__interest').textContent = utils.formatAmount(interest)
getRef('account_detail__interest').className = type === 'deposit' ? 'positive' : 'negative' getById('account_detail__interest').className = type === 'deposit' ? 'positive' : 'negative'
renderAccountProgress(index) renderAccountProgress(index)
if (status === 'active' && !getAccountStatus(index).isPending) { if (status === 'active' && !getAccountStatus(index).isPending) {
getRef('account_action_button').classList.remove('hidden') getById('account_action_button').classList.remove('hidden')
} else { } else {
getRef('account_action_button').classList.add('hidden') getById('account_action_button').classList.add('hidden')
} }
getRef('account_action_button').textContent = (type === 'deposit') ? 'Withdraw' : 'Repay' getById('account_action_button').textContent = (type === 'deposit') ? 'Withdraw' : 'Repay'
} }
async function processAccount() { async function processAccount() {
@ -1687,17 +1663,17 @@
ans = await getConfirmation('Repay loan?', { message: 'Make sure you have required amount to repay the loan!', cancelText: 'No', confirmText: 'Yes' }) ans = await getConfirmation('Repay loan?', { message: 'Make sure you have required amount to repay the loan!', cancelText: 'No', confirmText: 'Yes' })
} }
if (ans) { if (ans) {
getRef('account_action_button').classList.add('hidden') getById('account_action_button').classList.add('hidden')
const actionToDo = type === 'deposit' ? 'withdraw' : 'Repay' const actionToDo = type === 'deposit' ? 'withdraw' : 'Repay'
getRef('account_process__steps').append(render.accountProgressStep('loading', `Sending ${actionToDo} request`)) getById('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 => {
renderAccountProgress(index) renderAccountProgress(index)
}) })
.catch(err => { .catch(err => {
getRef('account_process__steps').lastElementChild.remove() getById('account_process__steps').lastElementChild.remove()
getRef('account_process__steps') getById('account_process__steps')
.append( .append(
render.accountProgressStep('failed', 'Failed withdrawal', `Can't withdraw deposit as loan amount exceeds total deposit amount.`) render.accountProgressStep('failed', 'Failed withdrawal', `Can't withdraw deposit as loan amount exceeds total deposit amount.`)
) )
@ -1708,8 +1684,8 @@
renderAccountProgress(index) renderAccountProgress(index)
}) })
.catch(err => { .catch(err => {
getRef('account_process__steps').lastElementChild.remove() getById('account_process__steps').lastElementChild.remove()
getRef('account_process__steps') getById('account_process__steps')
.append( .append(
render.accountProgressStep('failed', 'Failed repayment', err) render.accountProgressStep('failed', 'Failed repayment', err)
) )
@ -1728,16 +1704,16 @@
function updateChart() { function updateChart() {
const { depositTotal, loanTotal } = bank_app.getUserDetails(myFloID) const { depositTotal, loanTotal } = bank_app.getUserDetails(myFloID)
if (!depositTotal && !loanTotal) { if (!depositTotal && !loanTotal) {
getRef('account_chart_container').classList.add('hidden') getById('account_chart_container').classList.add('hidden')
} else { } else {
getRef('account_chart_container').classList.remove('hidden') getById('account_chart_container').classList.remove('hidden')
} }
if (accountChart && isChartVisible) { if (accountChart && isChartVisible) {
accountChart.data.datasets[0].data = [depositTotal, loanTotal] accountChart.data.datasets[0].data = [depositTotal, loanTotal]
accountChart.update() accountChart.update()
} }
getRef('total_deposit').textContent = utils.formatAmount(depositTotal) getById('total_deposit').textContent = utils.formatAmount(depositTotal)
getRef('total_loan').textContent = utils.formatAmount(loanTotal) getById('total_loan').textContent = utils.formatAmount(loanTotal)
} }
document.querySelector('theme-toggle').addEventListener('themechange', e => { document.querySelector('theme-toggle').addEventListener('themechange', e => {
@ -1748,7 +1724,7 @@
}) })
function renderChart(params) { function renderChart(params) {
const ctx = getRef('account_summary_chart').getContext('2d'); const ctx = getById('account_summary_chart').getContext('2d');
const { depositTotal, loanTotal } = bank_app.getUserDetails(myFloID) const { depositTotal, loanTotal } = bank_app.getUserDetails(myFloID)
return new Chart(ctx, { return new Chart(ctx, {
type: 'doughnut', type: 'doughnut',
@ -1788,112 +1764,106 @@
if (entry.isIntersecting) { if (entry.isIntersecting) {
const { depositTotal, loanTotal } = bank_app.getUserDetails(myFloID) const { depositTotal, loanTotal } = bank_app.getUserDetails(myFloID)
if (!depositTotal && !loanTotal) { if (!depositTotal && !loanTotal) {
getRef('account_chart_container').classList.add('hidden') getById('account_chart_container').classList.add('hidden')
} else { } else {
accountChart = renderChart() accountChart = renderChart()
isChartVisible = true isChartVisible = true
getRef('account_chart_container').classList.remove('hidden') getById('account_chart_container').classList.remove('hidden')
} }
} else if (!entry.isIntersecting && accountChart) { } else if (!entry.isIntersecting && accountChart) {
accountChart.destroy() accountChart.destroy()
isChartVisible = false isChartVisible = false
} getById('account_chart_container').classList.add('hidden')
})
})
const userSectionObserver = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
refreshBalance()
} }
}) })
}) })
getRef('get_deposit_amount').addEventListener('input', handleDepositAmountInput) getById('get_deposit_amount').addEventListener('input', handleDepositAmountInput)
function handleDepositAmountInput(e) { function handleDepositAmountInput(e) {
let message = '' let message = ''
if (getRef(`deposit_button_wrapper`).children[0]?.tagName === 'SM-BUTTON') { if (getById(`deposit_button_wrapper`).children[0]?.tagName === 'SM-BUTTON') {
message = `Deposit` message = `Deposit`
} else { } else {
message = `Slide to deposit` message = `Slide to deposit`
} }
if (e.target.value.trim() !== '') { if (e.target.value.trim() !== '') {
getRef(`deposit_button_wrapper`).children[0].textContent = `${message} ${utils.formatAmount(parseFloat(e.target.value))}` getById(`deposit_button_wrapper`).children[0].textContent = `${message} ${utils.formatAmount(parseFloat(e.target.value))}`
} else { } else {
if (getRef(`deposit_button_wrapper`).firstElementChild) if (getById(`deposit_button_wrapper`).firstElementChild)
getRef(`deposit_button_wrapper`).firstElementChild.textContent = message getById(`deposit_button_wrapper`).firstElementChild.textContent = message
} }
} }
getRef('get_loan_amount').addEventListener('input', handleDepositAmountInput) getById('get_loan_amount').addEventListener('input', handleDepositAmountInput)
function handleLoanAmountInput(e) { function handleLoanAmountInput(e) {
let message = '' let message = ''
if (e.target.value.trim() !== '') { if (e.target.value.trim() !== '') {
if (getRef(`loan_button_wrapper`).children[0].tagName === 'SM-BUTTON') { if (getById(`loan_button_wrapper`).children[0].tagName === 'SM-BUTTON') {
message = `Request loan of` message = `Request loan of`
} else { } else {
message = `Slide to request loan of` message = `Slide to request loan of`
} }
getRef(`loan_button_wrapper`).children[0].textContent = `${message} ${utils.formatAmount(parseFloat(e.target.value))}` getById(`loan_button_wrapper`).children[0].textContent = `${message} ${utils.formatAmount(parseFloat(e.target.value))}`
} else { } else {
if (getRef(`loan_button_wrapper`).children[0]?.tagName === 'SM-BUTTON') { if (getById(`loan_button_wrapper`).children[0]?.tagName === 'SM-BUTTON') {
message = `Request loan` message = `Request loan`
} else { } else {
message = `Slide to request loan` message = `Slide to request loan`
} }
getRef(`loan_button_wrapper`).children[0].textContent = message getById(`loan_button_wrapper`).children[0].textContent = message
} }
} }
function showActionResult(details = {}) { function showActionResult(details = {}) {
const { type, amount, status, reason = '' } = details const { type, amount, status, reason = '' } = details
getRef('result__icon').innerHTML = utils.getRelatedIcon(status) getById('result__icon').innerHTML = utils.getRelatedIcon(status)
getRef('result__icon').className = status getById('result__icon').className = status
switch (status) { switch (status) {
case 'pending': case 'pending':
getRef('result__title').textContent = `Sent ${type} request` getById('result__title').textContent = `Sent ${type} request`
getRef('result__description').textContent = `Waiting for ${type} confirmation. This may take upto 4hrs to be processed, Meanwhile you can go back and continue using app.` getById('result__description').textContent = `Waiting for ${type} confirmation. This may take upto 4hrs to be processed, Meanwhile you can go back and continue using app.`
break break
case 'failed': case 'failed':
getRef('result__title').textContent = `Failed to send ${type} request` getById('result__title').textContent = `Failed to send ${type} request`
getRef('result__description').textContent = reason getById('result__description').textContent = reason
break break
case 'loading': case 'loading':
getRef('result__icon').innerHTML = '<sm-spinner></sm-spinner>' getById('result__icon').innerHTML = '<sm-spinner></sm-spinner>'
getRef('result__title').textContent = `Sending ${type} request` getById('result__title').textContent = `Sending ${type} request`
getRef('result__description').textContent = '' getById('result__description').textContent = ''
break break
} }
getRef(`get_${type}_amount`).value = '' getById(`get_${type}_amount`).value = ''
} }
// Sets UX according to supported pointing device // Sets UX according to supported pointing device
const checkTouchSupport = (mql) => { const checkTouchSupport = (mql) => {
if (mql.matches) { if (mql.matches) {
getRef('deposit_button_wrapper').innerHTML = `<button id="deposit_button" class="button button--primary" onclick="confirmDeposit()" disabled>Deposit</button>` getById('deposit_button_wrapper').innerHTML = `<button id="deposit_button" class="button button--primary" onclick="confirmDeposit()" disabled>Deposit</button>`
getRef('loan_button_wrapper').innerHTML = `<button id="loan_button" class="button button--primary" onclick="confirmLoan()" disabled>Request loan</button>` getById('loan_button_wrapper').innerHTML = `<button id="loan_button" class="button button--primary" onclick="confirmLoan()" disabled>Request loan</button>`
getRef('deposit_form').addEventListener('submit', confirmDeposit) getById('deposit_form').addEventListener('submit', confirmDeposit)
getRef('loan_form').addEventListener('submit', confirmLoan) getById('loan_form').addEventListener('submit', confirmLoan)
getRef('deposit_button_wrapper').removeEventListener('confirmed', initDeposit) getById('deposit_button_wrapper').removeEventListener('confirmed', initDeposit)
getRef('loan_button_wrapper').removeEventListener('confirmed', initLoan) getById('loan_button_wrapper').removeEventListener('confirmed', initLoan)
} else { } else {
// touch supported // touch supported
getRef('deposit_button_wrapper').innerHTML = `<slide-button id="deposit_slide" type="submit" disabled>Slide to deposit</slide-button>` getById('deposit_button_wrapper').innerHTML = `<slide-button id="deposit_slide" type="submit" disabled>Slide to deposit</slide-button>`
getRef('loan_button_wrapper').innerHTML = `<slide-button id="loan_slide" type="submit" disabled>Slide to request loan</slide-button>` getById('loan_button_wrapper').innerHTML = `<slide-button id="loan_slide" type="submit" disabled>Slide to request loan</slide-button>`
getRef('deposit_button_wrapper').addEventListener('confirmed', initDeposit) getById('deposit_button_wrapper').addEventListener('confirmed', initDeposit)
getRef('loan_button_wrapper').addEventListener('confirmed', initLoan) getById('loan_button_wrapper').addEventListener('confirmed', initLoan)
getRef('deposit_form').removeEventListener('submit', confirmDeposit) getById('deposit_form').removeEventListener('submit', confirmDeposit)
getRef('loan_form').removeEventListener('submit', confirmLoan) getById('loan_form').removeEventListener('submit', confirmLoan)
} }
getRef('deposit_form')?.elementsChanged() getById('deposit_form')?.elementsChanged()
getRef('loan_form')?.elementsChanged() getById('loan_form')?.elementsChanged()
} }
window.matchMedia("(any-hover: hover)").addEventListener('change', checkTouchSupport); window.matchMedia("(any-hover: hover)").addEventListener('change', checkTouchSupport);
async function confirmDeposit() { async function confirmDeposit() {
const amount = parseFloat(getRef('get_deposit_amount').value) const amount = parseFloat(getById('get_deposit_amount').value)
const confirm = await getConfirmation('Continue?', { message: `Confirm deposit of ${utils.formatAmount(amount)}?`, cancelText: 'Cancel', confirmText: 'Confirm' }) const confirm = await getConfirmation('Continue?', { message: `Confirm deposit of ${utils.formatAmount(amount)}?`, cancelText: 'Cancel', confirmText: 'Confirm' })
if (confirm) { if (confirm) {
initDeposit() initDeposit()
@ -1901,7 +1871,7 @@
} }
function initDeposit() { function initDeposit() {
const amount = parseFloat(getRef('get_deposit_amount').value) const amount = parseFloat(getById('get_deposit_amount').value)
showProcess('deposit') showProcess('deposit')
bank_app.makeDeposit(amount) bank_app.makeDeposit(amount)
.then(() => { .then(() => {
@ -1916,14 +1886,14 @@
} }
async function confirmLoan(params) { async function confirmLoan(params) {
const amount = parseFloat(getRef('get_loan_amount').value) const amount = parseFloat(getById('get_loan_amount').value)
const confirm = await getConfirmation('Continue?', { message: `Confirm loan of ${utils.formatAmount(amount)}?`, cancelText: 'Cancel', confirmText: 'Confirm' }) const confirm = await getConfirmation('Continue?', { message: `Confirm loan of ${utils.formatAmount(amount)}?`, cancelText: 'Cancel', confirmText: 'Confirm' })
if (confirm) { if (confirm) {
initLoan() initLoan()
} }
} }
function initLoan() { function initLoan() {
const amount = parseFloat(getRef('get_loan_amount').value) const amount = parseFloat(getById('get_loan_amount').value)
showProcess('loan') showProcess('loan')
bank_app.requestLoan(amount) bank_app.requestLoan(amount)
.then(() => { .then(() => {
@ -1938,32 +1908,28 @@
} }
function showProcess(type) { function showProcess(type) {
getRef(`${type}_button_wrapper`).children[0].classList.add('clip') getById(`${type}_button_wrapper`).children[0].classList.add('clip')
getRef(`${type}_button_wrapper`).append(document.createElement('sm-spinner')) getById(`${type}_button_wrapper`).append(document.createElement('sm-spinner'))
} }
function hideProcess(type) { function hideProcess(type) {
getRef(`${type}_button_wrapper`).children[0]?.classList.remove('clip') getById(`${type}_button_wrapper`).children[0]?.classList.remove('clip')
getRef(`${type}_button_wrapper`).querySelector('sm-spinner')?.remove() getById(`${type}_button_wrapper`).querySelector('sm-spinner')?.remove()
}
function toggleUserSection() {
getRef('user_section').classList.toggle('reveal')
} }
function getAdminRequests() { function getAdminRequests() {
const allRequests = utils.getArrayOfObj(bank_app.viewAllRequests()).reverse() const allRequests = utils.getArrayOfObj(bank_app.viewAllRequests()).reverse()
const selectedStatus = getRef('admin_request_selector').value const selectedStatus = getById('admin_request_selector').value
if (selectedStatus === 'failed') { if (selectedStatus === 'failed') {
return allRequests.filter(({ status }) => status.includes(' ')) return allRequests.filter(({ status }) => status.includes(' '))
} else { } else {
return allRequests.filter(({ status }) => status === selectedStatus) return allRequests.filter(({ status }) => status === selectedStatus)
} }
} }
getRef('admin_request_selector').addEventListener('change', e => { getById('admin_request_selector').addEventListener('change', e => {
adminRequestsLoader.update(getAdminRequests) adminRequestsLoader.update(getAdminRequests)
}) })
getRef('admin_requests_container').addEventListener('click', async e => { getById('admin_requests_container').addEventListener('click', async e => {
if (e.target.closest('button')) { if (e.target.closest('button')) {
const target = e.target.closest('button') const target = e.target.closest('button')
const request = e.target.closest('.activity-card') const request = e.target.closest('.activity-card')
@ -2002,20 +1968,20 @@
const { isPending, uid } = utils.getLastTransaction() const { isPending, uid } = utils.getLastTransaction()
if (uid) { if (uid) {
const { amount, rtype } = getRequestDetails(uid) const { amount, rtype } = getRequestDetails(uid)
getRef('pending_transaction').innerHTML = '' getById('pending_transaction').innerHTML = ''
if (isPending && (rtype === 'openDeposit' || rtype === 'openLoan')) { if (isPending && (rtype === 'openDeposit' || rtype === 'openLoan')) {
const card = getRef('pending_transaction_template').content.cloneNode(true) const card = getById('pending_transaction_template').content.cloneNode(true)
const action = rtype === 'openDeposit' ? 'Deposit' : 'Loan' const action = rtype === 'openDeposit' ? 'Deposit' : 'Loan'
card.querySelector('.activity-card').setAttribute('href', `#/transaction?requestID=${uid}`) card.querySelector('.activity-card').setAttribute('href', `#/transaction?requestID=${uid}`)
card.querySelector('.activity-card__icon').innerHTML = utils.getRelatedIcon('pending') card.querySelector('.activity-card__icon').innerHTML = utils.getRelatedIcon('pending')
card.querySelector('.activity-card__title').textContent = `${action} in process` card.querySelector('.activity-card__title').textContent = `${action} in process`
card.querySelector('.activity-card__amount').textContent = utils.formatAmount(amount) card.querySelector('.activity-card__amount').textContent = utils.formatAmount(amount)
getRef('pending_transaction').append(card) getById('pending_transaction').append(card)
getRef('quick_actions_container').querySelectorAll('a').forEach(elem => { getById('quick_actions_container').querySelectorAll('a').forEach(elem => {
elem.classList.add('disabled') elem.classList.add('disabled')
}) })
} else { } else {
getRef('quick_actions_container').querySelectorAll('a').forEach(elem => { getById('quick_actions_container').querySelectorAll('a').forEach(elem => {
elem.classList.remove('disabled') elem.classList.remove('disabled')
}) })
} }
@ -2024,20 +1990,20 @@
function checkIfAllowed(type) { function checkIfAllowed(type) {
const { isPending, uid } = utils.getLastTransaction() const { isPending, uid } = utils.getLastTransaction()
getRef(`${type}_button_wrapper`).querySelector('strong')?.remove() getById(`${type}_button_wrapper`).querySelector('strong')?.remove()
// check if there is a last transaction // check if there is a last transaction
if (uid) { if (uid) {
const { amount, rtype } = getRequestDetails(uid) const { amount, rtype } = getRequestDetails(uid)
if (isPending && (rtype === 'openDeposit' || rtype === 'openLoan')) { if (isPending && (rtype === 'openDeposit' || rtype === 'openLoan')) {
const action = rtype === 'openDeposit' ? 'Deposit' : 'Loan' const action = rtype === 'openDeposit' ? 'Deposit' : 'Loan'
getRef(`${type}_button_wrapper`).firstElementChild.classList.add('hidden') getById(`${type}_button_wrapper`).firstElementChild.classList.add('hidden')
getRef(`${type}_button`).after(createElement('strong', { getById(`${type}_button`).after(createElement('strong', {
className: 'warning', className: 'warning',
textContent: `${action} in process. You can't ${type === 'deposit' ? 'deposit' : 'request loan'} until that's completed.`, textContent: `${action} in process. You can't ${type === 'deposit' ? 'deposit' : 'request loan'} until that's completed.`,
})) }))
} }
} else { } else {
getRef(`${type}_button_wrapper`).firstElementChild?.classList.remove('hidden') getById(`${type}_button_wrapper`).firstElementChild?.classList.remove('hidden')
} }
} }
let requestResponsePairs let requestResponsePairs
@ -2077,7 +2043,7 @@
floDapps.launchStartUp().then(result => { floDapps.launchStartUp().then(result => {
console.log(result); console.log(result);
// alert(`Welcome FLO_ID: ${myFloID}`); // alert(`Welcome FLO_ID: ${myFloID}`);
getRef('user_profile_id').textContent = myFloID getById('user_profile_id').textContent = myFloID
//App functions.... //App functions....
bank_app.launchApp(reqCallback, responseCallback) bank_app.launchApp(reqCallback, responseCallback)
.then(result => { .then(result => {
@ -2091,16 +2057,14 @@
document.querySelectorAll('.admin-option').forEach(option => option.classList.remove('hidden')) document.querySelectorAll('.admin-option').forEach(option => option.classList.remove('hidden'))
document.querySelectorAll('.user-option').forEach(option => option.classList.add('hidden')) document.querySelectorAll('.user-option').forEach(option => option.classList.add('hidden'))
} else { } else {
chartObserver.observe(getRef('account_chart_container'))
document.querySelectorAll('.admin-option').forEach(option => option.classList.add('hidden')) document.querySelectorAll('.admin-option').forEach(option => option.classList.add('hidden'))
document.querySelectorAll('.user-option').forEach(option => option.classList.remove('hidden')) document.querySelectorAll('.user-option').forEach(option => option.classList.remove('hidden'))
} }
if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) { if (window.location.hash.includes('sign_in') || window.location.hash.includes('sign_up')) {
window.location.hash = '' window.location.hash = ''
} else { } else {
showPage(window.location.hash) routeTo(window.location.hash)
} }
userSectionObserver.observe(getRef('user_section'))
}) })
.catch(error => console.error(error)) .catch(error => console.error(error))
}).catch(error => console.error(error)); }).catch(error => console.error(error));
@ -2136,9 +2100,9 @@
await bank_app.refreshData() await bank_app.refreshData()
checkPendingTransaction() checkPendingTransaction()
if (pagesData.lastSubPage !== 'notifications') { if (pagesData.lastSubPage !== 'notifications') {
getRef('notifications_page_button').classList.add('has-notification') getById('notifications_page_button').classList.add('has-notification')
} else { } else {
getRef('notifications_page_button').classList.remove('has-notification') getById('notifications_page_button').classList.remove('has-notification')
} }
refreshBalance() refreshBalance()
} }