Adding deposit and loan user flows

This commit is contained in:
sairaj mote 2021-09-07 18:09:07 +05:30
parent ac50a0b15c
commit 9bafae9387
5 changed files with 458 additions and 154 deletions

View File

@ -115,7 +115,7 @@ customElements.define('sm-button',
set disabled(value) {
if (value) {
this.setAttribute('disabled', '')
}else {
} else {
this.removeAttribute('disabled')
}
}
@ -164,80 +164,80 @@ smForm.innerHTML = `
width: 100%;
}
</style>
<form onsubmit="return false">
<form part="form" onsubmit="return false">
<slot></slot>
</form>
`
customElements.define('sm-form', class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(smForm.content.cloneNode(true))
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(smForm.content.cloneNode(true))
this.form = this.shadowRoot.querySelector('form')
this.formElements
this.requiredElements
this.submitButton
this.resetButton
this.allRequiredValid = false
this.form = this.shadowRoot.querySelector('form')
this.formElements
this.requiredElements
this.submitButton
this.resetButton
this.allRequiredValid = false
this.debounce = this.debounce.bind(this)
this.handleInput = this.handleInput.bind(this)
this.handleKeydown = this.handleKeydown.bind(this)
this.reset = this.reset.bind(this)
}
debounce(callback, wait) {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback.apply(null, args);
}, wait);
};
}
handleInput(e) {
this.allRequiredValid = this.requiredElements.every(elem => elem.isValid)
if (!this.submitButton) return;
if (this.allRequiredValid) {
this.submitButton.disabled = false;
}
else {
this.submitButton.disabled = true;
}
}
handleKeydown(e) {
if (e.key === 'Enter' && e.target.tagName !== 'SM-TEXTAREA' ) {
if (this.allRequiredValid) {
this.submitButton.click()
}
else {
this.requiredElements.find(elem => !elem.isValid).vibrate()
}
}
}
reset() {
this.formElements.forEach(elem => elem.reset())
}
connectedCallback() {
const slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', e => {
this.formElements = [...this.querySelectorAll('sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio')]
this.requiredElements = this.formElements.filter(elem => elem.hasAttribute('required'))
this.submitButton = e.target.assignedElements().find(elem => elem.getAttribute('variant') === 'primary' || elem.getAttribute('type') === 'submit');
this.resetButton = e.target.assignedElements().find(elem => elem.getAttribute('type') === 'reset');
if (this.resetButton) {
this.resetButton.addEventListener('click', this.reset)
}
})
this.addEventListener('input', this.debounce(this.handleInput, 100))
this.addEventListener('keydown', this.debounce(this.handleKeydown, 100))
}
disconnectedCallback() {
this.removeEventListener('input', this.debounce(this.handleInput, 100))
this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100))
}
this.debounce = this.debounce.bind(this)
this.handleInput = this.handleInput.bind(this)
this.handleKeydown = this.handleKeydown.bind(this)
this.reset = this.reset.bind(this)
}
debounce(callback, wait) {
let timeoutId = null;
return (...args) => {
window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => {
callback.apply(null, args);
}, wait);
};
}
handleInput(e) {
this.allRequiredValid = this.requiredElements.every(elem => elem.isValid)
if (!this.submitButton) return;
if (this.allRequiredValid) {
this.submitButton.disabled = false;
}
else {
this.submitButton.disabled = true;
}
}
handleKeydown(e) {
if (e.key === 'Enter' && e.target.tagName !== 'SM-TEXTAREA') {
if (this.allRequiredValid) {
this.submitButton.click()
}
else {
this.requiredElements.find(elem => !elem.isValid).vibrate()
}
}
}
reset() {
this.formElements.forEach(elem => elem.reset())
}
connectedCallback() {
const slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', e => {
this.formElements = [...this.querySelectorAll('sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio')]
this.requiredElements = this.formElements.filter(elem => elem.hasAttribute('required'))
this.submitButton = e.target.assignedElements().find(elem => elem.getAttribute('variant') === 'primary' || elem.getAttribute('type') === 'submit');
this.resetButton = e.target.assignedElements().find(elem => elem.getAttribute('type') === 'reset');
if (this.resetButton) {
this.resetButton.addEventListener('click', this.reset)
}
})
this.addEventListener('input', this.debounce(this.handleInput, 100))
this.addEventListener('keydown', this.debounce(this.handleKeydown, 100))
}
disconnectedCallback() {
this.removeEventListener('input', this.debounce(this.handleInput, 100))
this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100))
}
})
const smInput = document.createElement('template')
@ -488,7 +488,7 @@ customElements.define('sm-input',
this.isRequired = false
this.validationFunction
this.reflectedAttributes = ['value', 'required', 'disabled', 'type', 'inputmode', 'readonly', 'min', 'max', 'pattern', 'minlength', 'maxlength', 'step']
this.reset = this.reset.bind(this)
this.focusIn = this.focusIn.bind(this)
this.focusOut = this.focusOut.bind(this)
@ -545,7 +545,7 @@ customElements.define('sm-input',
}
}
set customValidation(val) {
this.validationFunction = val
}
set errorText(val) {
@ -578,19 +578,19 @@ customElements.define('sm-input',
return (_isValid && _customValid)
}
}
reset(){
reset() {
this.value = ''
}
focusIn(){
focusIn() {
this.input.focus()
}
focusOut(){
focusOut() {
this.input.blur()
}
fireEvent(){
fireEvent() {
let event = new Event('input', {
bubbles: true,
cancelable: true,
@ -599,7 +599,7 @@ customElements.define('sm-input',
this.dispatchEvent(event);
}
checkInput(e){
checkInput(e) {
if (!this.hasAttribute('readonly')) {
if (this.input.value.trim() !== '') {
this.clearBtn.classList.remove('hide')
@ -643,7 +643,7 @@ customElements.define('sm-input',
this.input.addEventListener('input', this.checkInput)
this.clearBtn.addEventListener('click', this.reset)
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
if (this.reflectedAttributes.includes(name)) {
@ -680,7 +680,7 @@ customElements.define('sm-input',
}
else {
this.feedbackText.textContent = ''
this.setAttribute('aria-required', 'false')
this.setAttribute('aria-required', 'false')
}
}
else if (name === 'readonly') {
@ -1175,7 +1175,7 @@ customElements.define('sm-popup', class extends HTMLElement {
}
show(options = {}) {
const {pinned = false, popupStack = undefined} = options
const { pinned = false, popupStack = undefined } = options
if (popupStack)
this.popupStack = popupStack
if (this.popupStack && !this.hasAttribute('open')) {
@ -1311,8 +1311,8 @@ customElements.define('sm-popup', class extends HTMLElement {
}
});
resizeObserver.observe(this)
this.popupHeader.addEventListener('touchstart', (e) => { this.handleTouchStart(e) }, { passive: true })
this.popupHeader.addEventListener('touchmove', (e) => { this.handleTouchMove(e) }, { passive: true })
this.popupHeader.addEventListener('touchend', (e) => { this.handleTouchEnd(e) }, { passive: true })
@ -1487,7 +1487,7 @@ class ThemeToggle extends HTMLElement {
document.body.dataset.theme = 'light'
this.setAttribute('aria-checked', 'false')
}
nightlight() {
this.hasTheme = 'dark'
document.body.dataset.theme = 'dark'
@ -1509,7 +1509,7 @@ class ThemeToggle extends HTMLElement {
this.setAttribute('checked', '')
}
else {
this.removeAttribute('checked')
this.removeAttribute('checked')
}
}
}
@ -1549,7 +1549,7 @@ class ThemeToggle extends HTMLElement {
this.addEventListener("keydown", this.handleKeyDown);
document.addEventListener('themechange', this.handleThemeChange)
}
disconnectedCallback() {
this.removeEventListener("click", this.toggleState);
this.removeEventListener("keydown", this.handleKeyDown);
@ -1648,7 +1648,7 @@ customElements.define('sm-copy',
this.attachShadow({
mode: 'open'
}).append(smCopy.content.cloneNode(true))
this.copyContent = this.shadowRoot.querySelector('.copy-content')
this.copyButton = this.shadowRoot.querySelector('.copy-button')

View File

@ -579,6 +579,7 @@ details[open] > summary .icon {
}
.quick-action {
color: inherit;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
@ -722,21 +723,34 @@ details[open] > summary .icon {
.status-tag:not(:empty) .icon {
margin-right: 0.3rem;
}
.status-tag:not(:empty).success, .status-tag:not(:empty).active {
.status-tag:not(:empty).active {
color: var(--green);
background-color: rgba(0, 230, 118, 0.1);
}
.status-tag:not(:empty).closed {
color: rgba(var(--text-color), 0.7);
background-color: rgba(var(--text-color), 0.06);
}
.status-tag:not(:empty).success {
color: var(--green);
background-color: rgba(0, 230, 118, 0.1);
}
.status-tag:not(:empty).success .icon {
fill: var(--green);
}
.status-tag:not(:empty).failed {
color: var(--danger-color);
background-color: rgba(255, 75, 75, 0.1);
}
.status-tag:not(:empty).failed .icon {
fill: var(--danger-color);
}
.status-tag:not(:empty).pending {
color: var(--yellow);
background-color: rgba(255, 252, 75, 0.1);
}
.status-tag:not(:empty).closed {
color: rgba(var(--text-color), 0.7);
background-color: rgba(var(--text-color), 0.06);
.status-tag:not(:empty).pending .icon {
fill: var(--yellow);
}
.activity-card--response {
@ -758,14 +772,14 @@ details[open] > summary .icon {
fill: var(--green);
}
.pending .icon {
fill: var(--yellow);
}
.failed .icon {
fill: var(--danger-color);
}
.pending .icon {
fill: var(--yellow);
}
#user_section {
display: grid;
-ms-flex-line-pack: start;
@ -950,7 +964,6 @@ details[open] > summary .icon {
.account-step {
opacity: 0;
grid-template-columns: auto minmax(0, 1fr);
grid-template-areas: "step-icon step-title" ". step-description";
gap: 0.3rem 0.8rem;
-webkit-animation: slide-down 0.3s forwards;
animation: slide-down 0.3s forwards;
@ -971,31 +984,24 @@ details[open] > summary .icon {
--height: 1rem;
--width: 1rem;
}
.account-step:not(:last-of-type)::after {
.account-step:not(:last-of-type) .step__line {
position: relative;
content: "";
height: 3rem;
width: 0.1rem;
margin: 0.5rem 0 1rem 0;
margin-left: 0.7rem;
justify-self: center;
background-color: var(--green);
}
.account-step .step__icon {
grid-area: step-icon;
}
.account-step .icon {
height: 1.5rem;
width: 1.5rem;
}
.account-step:not(.loading) .step__title {
text-transform: capitalize;
grid-area: step-title;
font-weight: 500;
font-size: 0.9rem;
padding: 0.2rem 0;
}
.account-step .step__description {
grid-area: step-description;
font-size: 0.8rem;
}
@ -1024,6 +1030,104 @@ details[open] > summary .icon {
transform: none;
}
}
#deposit,
#loan {
padding: 1.5rem 0;
grid-template-rows: auto 1fr;
}
#deposit sm-form,
#loan sm-form {
justify-self: center;
margin-top: 3rem;
width: min(24rem, 100%);
}
#deposit sm-form::part(form),
#loan sm-form::part(form) {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
}
#deposit__icon .icon,
#loan__icon .icon {
height: 1.8rem;
width: 1.8rem;
fill: var(--accent-color);
}
#get_deposit_amount,
#get_loan_amount {
--font-size: 1.5rem;
margin-top: 1rem;
}
#result {
place-content: center;
}
#result section {
text-align: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
#result__icon {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
border-radius: 50%;
padding: 1rem;
margin: -5rem 0 1.5rem 0;
-webkit-animation: pop-in 1s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275);
animation: pop-in 1s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
#result__icon .icon {
height: 1.8rem;
width: 1.8rem;
}
#result__description {
margin: 0.5rem 0;
}
#result__back_button {
margin-top: 3rem;
}
@-webkit-keyframes pop-in {
0% {
opacity: 0;
-webkit-transform: scale(0.4) translateY(6rem);
transform: scale(0.4) translateY(6rem);
}
40% {
opacity: 1;
-webkit-transform: scale(0.4) translateY(0);
transform: scale(0.4) translateY(0);
}
100% {
-webkit-transform: none;
transform: none;
}
}
@keyframes pop-in {
0% {
opacity: 0;
-webkit-transform: scale(0.4) translateY(6rem);
transform: scale(0.4) translateY(6rem);
}
40% {
opacity: 1;
-webkit-transform: scale(0.4) translateY(0);
transform: scale(0.4) translateY(0);
}
100% {
-webkit-transform: none;
transform: none;
}
}
@media screen and (max-width: 640px) {
sm-button {
--padding: 1rem;
@ -1058,7 +1162,8 @@ details[open] > summary .icon {
}
#transaction_action_button,
#account_action_button {
#account_action_button,
#deposit_button {
margin-top: auto;
}

2
css/main.min.css vendored

File diff suppressed because one or more lines are too long

View File

@ -512,6 +512,7 @@ details {
margin: 2rem 0;
}
.quick-action {
color: inherit;
display: flex;
flex-direction: column;
align-items: center;
@ -629,22 +630,34 @@ details {
.icon {
margin-right: 0.3rem;
}
&.success,
&.active {
color: var(--green);
background-color: rgb(0, 230, 118, 0.1);
}
&.closed {
color: rgba(var(--text-color), 0.7);
background-color: rgba(var(--text-color), 0.06);
}
&.success {
color: var(--green);
background-color: rgb(0, 230, 118, 0.1);
.icon {
fill: var(--green);
}
}
&.failed {
color: var(--danger-color);
background-color: rgb(255, 75, 75, 0.1);
.icon {
fill: var(--danger-color);
}
}
&.pending {
color: var(--yellow);
background-color: rgba(255, 252, 75, 0.1);
}
&.closed {
color: rgba(var(--text-color), 0.7);
background-color: rgba(var(--text-color), 0.06);
.icon {
fill: var(--yellow);
}
}
}
.activity-card--response {
@ -666,16 +679,16 @@ details {
fill: var(--green);
}
}
.pending {
.icon {
fill: var(--yellow);
}
}
.failed {
.icon {
fill: var(--danger-color);
}
}
.pending {
.icon {
fill: var(--yellow);
}
}
#user_section {
display: grid;
align-content: flex-start;
@ -810,7 +823,6 @@ details {
.account-step {
opacity: 0;
grid-template-columns: auto minmax(0, 1fr);
grid-template-areas: "step-icon step-title" ". step-description";
gap: 0.3rem 0.8rem;
animation: slide-down 0.3s forwards;
&:nth-of-type(2) {
@ -826,33 +838,26 @@ details {
--height: 1rem;
--width: 1rem;
}
&:not(:last-of-type)::after {
&:not(:last-of-type) .step__line {
position: relative;
content: "";
height: 3rem;
width: 0.1rem;
margin: 0.5rem 0 1rem 0;
margin-left: 0.7rem;
justify-self: center;
background-color: var(--green);
}
.step__icon {
grid-area: step-icon;
}
.icon {
height: 1.5rem;
width: 1.5rem;
}
&:not(.loading) {
.step__title {
text-transform: capitalize;
grid-area: step-title;
font-weight: 500;
font-size: 0.9rem;
padding: 0.2rem 0;
}
}
.step__description {
grid-area: step-description;
font-size: 0.8rem;
}
}
@ -866,6 +871,71 @@ details {
transform: none;
}
}
#deposit,
#loan {
padding: 1.5rem 0;
grid-template-rows: auto 1fr;
sm-form {
justify-self: center;
margin-top: 3rem;
width: min(24rem, 100%);
&::part(form) {
display: flex;
flex-direction: column;
}
}
}
#deposit__icon,
#loan__icon {
.icon {
height: 1.8rem;
width: 1.8rem;
fill: var(--accent-color);
}
}
#get_deposit_amount,
#get_loan_amount {
--font-size: 1.5rem;
margin-top: 1rem;
}
#result {
place-content: center;
section {
text-align: center;
align-items: center;
}
&__icon {
display: flex;
border-radius: 50%;
padding: 1rem;
margin: -5rem 0 1.5rem 0;
animation: pop-in 1s forwards cubic-bezier(0.175, 0.885, 0.32, 1.275);
.icon {
height: 1.8rem;
width: 1.8rem;
}
}
&__description {
margin: 0.5rem 0;
}
&__back_button {
margin-top: 3rem;
}
}
@keyframes pop-in {
0% {
opacity: 0;
transform: scale(0.4) translateY(6rem);
}
40% {
opacity: 1;
transform: scale(0.4) translateY(0);
}
100% {
transform: none;
}
}
@media screen and (max-width: 640px) {
sm-button {
--padding: 1rem;
@ -889,7 +959,8 @@ details {
}
}
#transaction_action_button,
#account_action_button {
#account_action_button,
#deposit_button {
margin-top: auto;
}
#account_process {

View File

@ -174,7 +174,7 @@
Quick actions
</h4>
<div id="quick_actions_container">
<button class="quick-action">
<a class="quick-action" href="#/deposit">
<div class="quick-action__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">
@ -186,8 +186,8 @@
</svg>
</div>
<span class="quick-action__title">Make deposit</span>
</button>
<button class="quick-action">
</a>
<a class="quick-action" href="#/loan">
<div class="quick-action__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path
@ -197,7 +197,7 @@
</svg>
</div>
<span class="quick-action__title">Get loan</span>
</button>
</a>
</div>
</section>
<section>
@ -309,6 +309,70 @@
</div>
</section>
</article>
<article id="deposit" class="page hide-completely page-layout">
<button class="icon-button justify-self-start" onclick="history.back()">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z"
clip-rule="evenodd" />
</svg>
</button>
<sm-form>
<div id="deposit__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="grid gap-0-5">
<h3 class="h3">Deposit</h3>
<p id="deposit_interest_rate"></p>
</div>
<sm-input id="get_deposit_amount" type="number" min="1" step="0.01"
error-text="Amount should be at least ₹1" placeholder="₹Amount" required>
</sm-input>
<sm-button id="deposit_button" variant="primary" disabled onclick="initDeposit()">Deposit</sm-button>
</sm-form>
</article>
<article id="loan" class="page hide-completely page-layout">
<button class="icon-button justify-self-start" onclick="history.back()">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M9.707 16.707a1 1 0 01-1.414 0l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 1.414L5.414 9H17a1 1 0 110 2H5.414l4.293 4.293a1 1 0 010 1.414z"
clip-rule="evenodd" />
</svg>
</button>
<sm-form>
<div id="deposit__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="grid gap-0-5">
<h3 class="h3">Loan</h3>
<p id="loan_interest_rate"></p>
</div>
<sm-input id="get_loan_amount" type="number" min="1" step="0.01" error-text="Amount should be at least ₹1"
placeholder="₹Amount" required>
</sm-input>
<sm-button id="loan_button" variant="primary" disabled onclick="initLoan()">Request loan</sm-button>
</sm-form>
</article>
<article id="result" class="page hide-completely page-layout">
<section class="flex direction-column">
<div id="result__icon" class="pending"></div>
<h4 id="result__title"></h4>
<p id="result__description"></p>
<a id="result__back_button" href="" class="button">Done</a>
</section>
</article>
<article id="transaction" class="page hide-completely page-layout">
<button class="icon-button justify-self-start" onclick="history.back()">
<svg xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 20 20" fill="currentColor">
@ -328,7 +392,6 @@
<time id="transaction_detail__time"></time>
<div id="transaction_detail__status"></div>
</div>
<sm-button id="transaction_action_button" variant="primary"></sm-button>
</div>
</section>
</article>
@ -391,6 +454,7 @@
<div class="account-step grid">
<div class="step__icon"></div>
<span class="step__title"></span>
<div class="step__line"></div>
<p class="step__description"></p>
</div>
</template>
@ -632,7 +696,7 @@
return `${month} ${year}`;
}
else
return `${finalHours} ${month} ${date} ${year}`;
return `${month} ${date} ${year}, ${finalHours}`;
} catch (e) {
console.error(e);
return time;
@ -707,6 +771,14 @@
getRef('generated_flo_id').value = floID
getRef('generated_private_key').value = privKey
break;
case 'deposit':
const { I_s } = bank_app.getRates()
getRef('deposit_interest_rate').textContent = `Make a deposit at ${I_s * 100}% rate of interest`
break;
case 'loan':
const { I_b } = bank_app.getRates()
getRef('loan_interest_rate').textContent = `Get a loan at ${I_b * 100}% rate of interest`
break;
case 'transaction':
showTransactionDetails(params)
break;
@ -981,7 +1053,7 @@
card.querySelector('.activity-card__icon').innerHTML = icon
card.querySelector('.activity-card__type').textContent = type
card.querySelector('.activity-card__time').textContent = getFormattedTime(parseInt(openTime))
card.querySelector('.activity-card__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
card.querySelector('.activity-card__amount').textContent = netAmt.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
card.querySelector('.activity-card__status').classList.add(status)
card.querySelector('.activity-card__status').textContent = status
return card
@ -1068,7 +1140,6 @@
function showTransactionDetails(params) {
const { requestID } = params
const { amount, rtype, timestamp, status, index } = getRequestDetails(requestID)
const { status: accountStatus } = bank_app.accounts[index]
let type = (rtype === 'openDeposit' || rtype === 'closeDeposit') ? 'deposit' : 'loan'
const icon = utils.getRelatedIcon(rtype)
@ -1079,22 +1150,6 @@
getRef('transaction_detail__type').textContent = type
getRef('transaction_detail__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
getRef('transaction_detail__time').textContent = getFormattedTime(timestamp)
getRef('transaction_action_button').classList.remove('hide-completely')
if (accountStatus === 'active') {
getRef('transaction_action_button').classList.remove('hide-completely')
} else {
getRef('transaction_action_button').classList.add('hide-completely')
}
switch (rtype) {
case 'openDeposit':
getRef('transaction_action_button').textContent = 'Withdraw'
break
case 'openLoan':
getRef('transaction_action_button').textContent = 'Repay'
break
}
}
function getAccountStatus(index) {
@ -1131,19 +1186,19 @@
function renderAccountProgress(index) {
const { type, status, openTime, closeTime = 0, amount, netAmt } = bank_app.accounts[index]
getRef('account_process__steps').innerHTML = ''
getRef('account_process__steps').append(render.accountProgressStep('success', `${type}ed`, getFormattedTime(openTime)))
getRef('account_process__steps').append(render.accountProgressStep('success', type === "deposit" ? 'Deposited' : 'Got loan', getFormattedTime(openTime)))
const { isPending, pendingRequest } = getAccountStatus(index)
if (type === 'deposit') {
if (isPending) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Sent withdrawal request', getFormattedTime(pendingRequest.split('_')[0])))
getRef('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for confirmation', `Once your request is processed, your withdrawn amount will reflect in your balance.<br>meanwhile you can go back and continue using the app.`))
getRef('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for withdrawal confirmation', `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 {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Withdrawal complete', getFormattedTime(closeTime)))
}
} else {
if (isPending) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Sent repay request', getFormattedTime(pendingRequest.split('_')[0])))
getRef('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for confirmation', `Once your request is processed, your loan will be closed,`))
getRef('account_process__steps').append(render.accountProgressStep('pending', 'Waiting for repayment confirmation', `Once your request is processed, your loan will be closed,`))
} else {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Repayment complete', getFormattedTime(closeTime)))
}
@ -1223,8 +1278,8 @@
accountChart.data.datasets[0].data = [depositTotal, loanTotal]
accountChart.update()
}
getRef('total_deposit').textContent = depositTotal
getRef('total_loan').textContent = loanTotal
getRef('total_deposit').textContent = depositTotal.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
getRef('total_loan').textContent = loanTotal.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
}
document.querySelector('theme-toggle').addEventListener('themechange', e => {
@ -1279,6 +1334,79 @@
}
})
})
getRef('get_deposit_amount').addEventListener('input', e => {
if (e.target.value.trim() !== '') {
getRef('deposit_button').textContent = `Deposit ${parseFloat(e.target.value).toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}`
} else {
getRef('deposit_button').textContent = `Deposit`
}
})
getRef('get_loan_amount').addEventListener('input', e => {
if (e.target.value.trim() !== '') {
getRef('loan_button').textContent = `Request loan of ${parseFloat(e.target.value).toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}`
} else {
getRef('loan_button').textContent = `Request loan`
}
})
function showActionResult(details = {}) {
const { type, amount, status, reason = '' } = details
getRef('result__icon').innerHTML = utils.getRelatedIcon(status)
if (type === 'deposit') {
getRef('result__title').textContent = 'Sent deposit request'
getRef('result__description').textContent = 'Waiting for deposit confirmation. Meanwhile you can go back and continue using app.'
} else if (type === 'loan') {
getRef('result__title').textContent = 'Sent loan request'
getRef('result__description').textContent = 'Waiting for loan confirmation. Meanwhile you can go back and continue using app.'
}
showPage('result')
}
async function initDeposit() {
const amount = parseFloat(getRef('get_deposit_amount').value)
const confirm = await getConfirmation(`Confirm deposit of ${amount.toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}?`)
if (confirm) {
bank_app.makeDeposit(amount)
.then(() => {
showActionResult({
type: 'deposit',
amount,
status: 'pending'
})
})
.catch(err => {
showActionResult({
type: 'deposit',
amount,
status: 'failed',
reason: err
})
})
}
}
async function initLoan() {
const amount = parseFloat(getRef('get_loan_amount').value)
const confirm = await getConfirmation(`Confirm loan of ${amount.toLocaleString('en-IN', { currency: 'INR', style: 'currency' })}?`)
if (confirm) {
bank_app.requestLoan(amount)
.then(() => {
showActionResult({
type: 'loan',
amount,
status: 'pending'
})
})
.catch(err => {
showActionResult({
type: 'loan',
amount,
status: 'failed',
reason: err
})
})
}
}
</script>
<script id="onLoadStartUp">
const requestResponsePairs = {}