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) { set disabled(value) {
if (value) { if (value) {
this.setAttribute('disabled', '') this.setAttribute('disabled', '')
}else { } else {
this.removeAttribute('disabled') this.removeAttribute('disabled')
} }
} }
@ -164,80 +164,80 @@ smForm.innerHTML = `
width: 100%; width: 100%;
} }
</style> </style>
<form onsubmit="return false"> <form part="form" onsubmit="return false">
<slot></slot> <slot></slot>
</form> </form>
` `
customElements.define('sm-form', class extends HTMLElement { customElements.define('sm-form', class extends HTMLElement {
constructor() { constructor() {
super() super()
this.attachShadow({ this.attachShadow({
mode: 'open' mode: 'open'
}).append(smForm.content.cloneNode(true)) }).append(smForm.content.cloneNode(true))
this.form = this.shadowRoot.querySelector('form') this.form = this.shadowRoot.querySelector('form')
this.formElements this.formElements
this.requiredElements this.requiredElements
this.submitButton this.submitButton
this.resetButton this.resetButton
this.allRequiredValid = false this.allRequiredValid = false
this.debounce = this.debounce.bind(this) this.debounce = this.debounce.bind(this)
this.handleInput = this.handleInput.bind(this) this.handleInput = this.handleInput.bind(this)
this.handleKeydown = this.handleKeydown.bind(this) this.handleKeydown = this.handleKeydown.bind(this)
this.reset = this.reset.bind(this) this.reset = this.reset.bind(this)
} }
debounce(callback, wait) { debounce(callback, wait) {
let timeoutId = null; let timeoutId = null;
return (...args) => { return (...args) => {
window.clearTimeout(timeoutId); window.clearTimeout(timeoutId);
timeoutId = window.setTimeout(() => { timeoutId = window.setTimeout(() => {
callback.apply(null, args); callback.apply(null, args);
}, wait); }, wait);
}; };
} }
handleInput(e) { handleInput(e) {
this.allRequiredValid = this.requiredElements.every(elem => elem.isValid) this.allRequiredValid = this.requiredElements.every(elem => elem.isValid)
if (!this.submitButton) return; if (!this.submitButton) return;
if (this.allRequiredValid) { if (this.allRequiredValid) {
this.submitButton.disabled = false; this.submitButton.disabled = false;
} }
else { else {
this.submitButton.disabled = true; this.submitButton.disabled = true;
} }
} }
handleKeydown(e) { handleKeydown(e) {
if (e.key === 'Enter' && e.target.tagName !== 'SM-TEXTAREA' ) { if (e.key === 'Enter' && e.target.tagName !== 'SM-TEXTAREA') {
if (this.allRequiredValid) { if (this.allRequiredValid) {
this.submitButton.click() this.submitButton.click()
} }
else { else {
this.requiredElements.find(elem => !elem.isValid).vibrate() this.requiredElements.find(elem => !elem.isValid).vibrate()
} }
} }
} }
reset() { reset() {
this.formElements.forEach(elem => elem.reset()) this.formElements.forEach(elem => elem.reset())
} }
connectedCallback() { connectedCallback() {
const slot = this.shadowRoot.querySelector('slot') const slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', e => { slot.addEventListener('slotchange', e => {
this.formElements = [...this.querySelectorAll('sm-input, sm-textarea, sm-checkbox, tags-input, file-input, sm-switch, sm-radio')] 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.requiredElements = this.formElements.filter(elem => elem.hasAttribute('required'))
this.submitButton = e.target.assignedElements().find(elem => elem.getAttribute('variant') === 'primary' || elem.getAttribute('type') === 'submit'); 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'); this.resetButton = e.target.assignedElements().find(elem => elem.getAttribute('type') === 'reset');
if (this.resetButton) { if (this.resetButton) {
this.resetButton.addEventListener('click', this.reset) this.resetButton.addEventListener('click', this.reset)
} }
}) })
this.addEventListener('input', this.debounce(this.handleInput, 100)) this.addEventListener('input', this.debounce(this.handleInput, 100))
this.addEventListener('keydown', this.debounce(this.handleKeydown, 100)) this.addEventListener('keydown', this.debounce(this.handleKeydown, 100))
} }
disconnectedCallback() { disconnectedCallback() {
this.removeEventListener('input', this.debounce(this.handleInput, 100)) this.removeEventListener('input', this.debounce(this.handleInput, 100))
this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100)) this.removeEventListener('keydown', this.debounce(this.handleKeydown, 100))
} }
}) })
const smInput = document.createElement('template') const smInput = document.createElement('template')
@ -578,19 +578,19 @@ customElements.define('sm-input',
return (_isValid && _customValid) return (_isValid && _customValid)
} }
} }
reset(){ reset() {
this.value = '' this.value = ''
} }
focusIn(){ focusIn() {
this.input.focus() this.input.focus()
} }
focusOut(){ focusOut() {
this.input.blur() this.input.blur()
} }
fireEvent(){ fireEvent() {
let event = new Event('input', { let event = new Event('input', {
bubbles: true, bubbles: true,
cancelable: true, cancelable: true,
@ -599,7 +599,7 @@ customElements.define('sm-input',
this.dispatchEvent(event); this.dispatchEvent(event);
} }
checkInput(e){ checkInput(e) {
if (!this.hasAttribute('readonly')) { if (!this.hasAttribute('readonly')) {
if (this.input.value.trim() !== '') { if (this.input.value.trim() !== '') {
this.clearBtn.classList.remove('hide') this.clearBtn.classList.remove('hide')
@ -1175,7 +1175,7 @@ customElements.define('sm-popup', class extends HTMLElement {
} }
show(options = {}) { show(options = {}) {
const {pinned = false, popupStack = undefined} = options const { pinned = false, popupStack = undefined } = options
if (popupStack) if (popupStack)
this.popupStack = popupStack this.popupStack = popupStack
if (this.popupStack && !this.hasAttribute('open')) { if (this.popupStack && !this.hasAttribute('open')) {

View File

@ -579,6 +579,7 @@ details[open] > summary .icon {
} }
.quick-action { .quick-action {
color: inherit;
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
display: flex; display: flex;
@ -722,21 +723,34 @@ details[open] > summary .icon {
.status-tag:not(:empty) .icon { .status-tag:not(:empty) .icon {
margin-right: 0.3rem; margin-right: 0.3rem;
} }
.status-tag:not(:empty).success, .status-tag:not(:empty).active { .status-tag:not(:empty).active {
color: var(--green); color: var(--green);
background-color: rgba(0, 230, 118, 0.1); 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 { .status-tag:not(:empty).failed {
color: var(--danger-color); color: var(--danger-color);
background-color: rgba(255, 75, 75, 0.1); background-color: rgba(255, 75, 75, 0.1);
} }
.status-tag:not(:empty).failed .icon {
fill: var(--danger-color);
}
.status-tag:not(:empty).pending { .status-tag:not(:empty).pending {
color: var(--yellow); color: var(--yellow);
background-color: rgba(255, 252, 75, 0.1); background-color: rgba(255, 252, 75, 0.1);
} }
.status-tag:not(:empty).closed { .status-tag:not(:empty).pending .icon {
color: rgba(var(--text-color), 0.7); fill: var(--yellow);
background-color: rgba(var(--text-color), 0.06);
} }
.activity-card--response { .activity-card--response {
@ -758,14 +772,14 @@ details[open] > summary .icon {
fill: var(--green); fill: var(--green);
} }
.pending .icon {
fill: var(--yellow);
}
.failed .icon { .failed .icon {
fill: var(--danger-color); fill: var(--danger-color);
} }
.pending .icon {
fill: var(--yellow);
}
#user_section { #user_section {
display: grid; display: grid;
-ms-flex-line-pack: start; -ms-flex-line-pack: start;
@ -950,7 +964,6 @@ details[open] > summary .icon {
.account-step { .account-step {
opacity: 0; opacity: 0;
grid-template-columns: auto minmax(0, 1fr); grid-template-columns: auto minmax(0, 1fr);
grid-template-areas: "step-icon step-title" ". step-description";
gap: 0.3rem 0.8rem; gap: 0.3rem 0.8rem;
-webkit-animation: slide-down 0.3s forwards; -webkit-animation: slide-down 0.3s forwards;
animation: slide-down 0.3s forwards; animation: slide-down 0.3s forwards;
@ -971,31 +984,24 @@ details[open] > summary .icon {
--height: 1rem; --height: 1rem;
--width: 1rem; --width: 1rem;
} }
.account-step:not(:last-of-type)::after { .account-step:not(:last-of-type) .step__line {
position: relative; position: relative;
content: "";
height: 3rem; height: 3rem;
width: 0.1rem; width: 0.1rem;
margin: 0.5rem 0 1rem 0; margin: 0.5rem 0 1rem 0;
margin-left: 0.7rem; justify-self: center;
background-color: var(--green); background-color: var(--green);
} }
.account-step .step__icon {
grid-area: step-icon;
}
.account-step .icon { .account-step .icon {
height: 1.5rem; height: 1.5rem;
width: 1.5rem; width: 1.5rem;
} }
.account-step:not(.loading) .step__title { .account-step:not(.loading) .step__title {
text-transform: capitalize;
grid-area: step-title;
font-weight: 500; font-weight: 500;
font-size: 0.9rem; font-size: 0.9rem;
padding: 0.2rem 0; padding: 0.2rem 0;
} }
.account-step .step__description { .account-step .step__description {
grid-area: step-description;
font-size: 0.8rem; font-size: 0.8rem;
} }
@ -1024,6 +1030,104 @@ details[open] > summary .icon {
transform: none; 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) { @media screen and (max-width: 640px) {
sm-button { sm-button {
--padding: 1rem; --padding: 1rem;
@ -1058,7 +1162,8 @@ details[open] > summary .icon {
} }
#transaction_action_button, #transaction_action_button,
#account_action_button { #account_action_button,
#deposit_button {
margin-top: auto; 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; margin: 2rem 0;
} }
.quick-action { .quick-action {
color: inherit;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@ -629,22 +630,34 @@ details {
.icon { .icon {
margin-right: 0.3rem; margin-right: 0.3rem;
} }
&.success,
&.active { &.active {
color: var(--green); color: var(--green);
background-color: rgb(0, 230, 118, 0.1); 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 { &.failed {
color: var(--danger-color); color: var(--danger-color);
background-color: rgb(255, 75, 75, 0.1); background-color: rgb(255, 75, 75, 0.1);
.icon {
fill: var(--danger-color);
}
} }
&.pending { &.pending {
color: var(--yellow); color: var(--yellow);
background-color: rgba(255, 252, 75, 0.1); background-color: rgba(255, 252, 75, 0.1);
} .icon {
&.closed { fill: var(--yellow);
color: rgba(var(--text-color), 0.7); }
background-color: rgba(var(--text-color), 0.06);
} }
} }
.activity-card--response { .activity-card--response {
@ -666,16 +679,16 @@ details {
fill: var(--green); fill: var(--green);
} }
} }
.pending {
.icon {
fill: var(--yellow);
}
}
.failed { .failed {
.icon { .icon {
fill: var(--danger-color); fill: var(--danger-color);
} }
} }
.pending {
.icon {
fill: var(--yellow);
}
}
#user_section { #user_section {
display: grid; display: grid;
align-content: flex-start; align-content: flex-start;
@ -810,7 +823,6 @@ details {
.account-step { .account-step {
opacity: 0; opacity: 0;
grid-template-columns: auto minmax(0, 1fr); grid-template-columns: auto minmax(0, 1fr);
grid-template-areas: "step-icon step-title" ". step-description";
gap: 0.3rem 0.8rem; gap: 0.3rem 0.8rem;
animation: slide-down 0.3s forwards; animation: slide-down 0.3s forwards;
&:nth-of-type(2) { &:nth-of-type(2) {
@ -826,33 +838,26 @@ details {
--height: 1rem; --height: 1rem;
--width: 1rem; --width: 1rem;
} }
&:not(:last-of-type)::after { &:not(:last-of-type) .step__line {
position: relative; position: relative;
content: "";
height: 3rem; height: 3rem;
width: 0.1rem; width: 0.1rem;
margin: 0.5rem 0 1rem 0; margin: 0.5rem 0 1rem 0;
margin-left: 0.7rem; justify-self: center;
background-color: var(--green); background-color: var(--green);
} }
.step__icon {
grid-area: step-icon;
}
.icon { .icon {
height: 1.5rem; height: 1.5rem;
width: 1.5rem; width: 1.5rem;
} }
&:not(.loading) { &:not(.loading) {
.step__title { .step__title {
text-transform: capitalize;
grid-area: step-title;
font-weight: 500; font-weight: 500;
font-size: 0.9rem; font-size: 0.9rem;
padding: 0.2rem 0; padding: 0.2rem 0;
} }
} }
.step__description { .step__description {
grid-area: step-description;
font-size: 0.8rem; font-size: 0.8rem;
} }
} }
@ -866,6 +871,71 @@ details {
transform: none; 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) { @media screen and (max-width: 640px) {
sm-button { sm-button {
--padding: 1rem; --padding: 1rem;
@ -889,7 +959,8 @@ details {
} }
} }
#transaction_action_button, #transaction_action_button,
#account_action_button { #account_action_button,
#deposit_button {
margin-top: auto; margin-top: auto;
} }
#account_process { #account_process {

View File

@ -174,7 +174,7 @@
Quick actions Quick actions
</h4> </h4>
<div id="quick_actions_container"> <div id="quick_actions_container">
<button class="quick-action"> <a class="quick-action" href="#/deposit">
<div class="quick-action__icon"> <div class="quick-action__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" <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"> height="24px" viewBox="0 0 24 24" width="24px" fill="#000000">
@ -186,8 +186,8 @@
</svg> </svg>
</div> </div>
<span class="quick-action__title">Make deposit</span> <span class="quick-action__title">Make deposit</span>
</button> </a>
<button class="quick-action"> <a class="quick-action" href="#/loan">
<div class="quick-action__icon"> <div class="quick-action__icon">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<path <path
@ -197,7 +197,7 @@
</svg> </svg>
</div> </div>
<span class="quick-action__title">Get loan</span> <span class="quick-action__title">Get loan</span>
</button> </a>
</div> </div>
</section> </section>
<section> <section>
@ -309,6 +309,70 @@
</div> </div>
</section> </section>
</article> </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"> <article id="transaction" class="page hide-completely page-layout">
<button class="icon-button justify-self-start" onclick="history.back()"> <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"> <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> <time id="transaction_detail__time"></time>
<div id="transaction_detail__status"></div> <div id="transaction_detail__status"></div>
</div> </div>
<sm-button id="transaction_action_button" variant="primary"></sm-button>
</div> </div>
</section> </section>
</article> </article>
@ -391,6 +454,7 @@
<div class="account-step grid"> <div class="account-step grid">
<div class="step__icon"></div> <div class="step__icon"></div>
<span class="step__title"></span> <span class="step__title"></span>
<div class="step__line"></div>
<p class="step__description"></p> <p class="step__description"></p>
</div> </div>
</template> </template>
@ -632,7 +696,7 @@
return `${month} ${year}`; return `${month} ${year}`;
} }
else else
return `${finalHours} ${month} ${date} ${year}`; return `${month} ${date} ${year}, ${finalHours}`;
} catch (e) { } catch (e) {
console.error(e); console.error(e);
return time; return time;
@ -707,6 +771,14 @@
getRef('generated_flo_id').value = floID getRef('generated_flo_id').value = floID
getRef('generated_private_key').value = privKey getRef('generated_private_key').value = privKey
break; 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': case 'transaction':
showTransactionDetails(params) showTransactionDetails(params)
break; break;
@ -981,7 +1053,7 @@
card.querySelector('.activity-card__icon').innerHTML = icon card.querySelector('.activity-card__icon').innerHTML = icon
card.querySelector('.activity-card__type').textContent = type card.querySelector('.activity-card__type').textContent = type
card.querySelector('.activity-card__time').textContent = getFormattedTime(parseInt(openTime)) 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').classList.add(status)
card.querySelector('.activity-card__status').textContent = status card.querySelector('.activity-card__status').textContent = status
return card return card
@ -1068,7 +1140,6 @@
function showTransactionDetails(params) { function showTransactionDetails(params) {
const { requestID } = params const { requestID } = params
const { amount, rtype, timestamp, status, index } = getRequestDetails(requestID) const { amount, rtype, timestamp, status, index } = getRequestDetails(requestID)
const { status: accountStatus } = bank_app.accounts[index]
let type = (rtype === 'openDeposit' || rtype === 'closeDeposit') ? 'deposit' : 'loan' let type = (rtype === 'openDeposit' || rtype === 'closeDeposit') ? 'deposit' : 'loan'
const icon = utils.getRelatedIcon(rtype) const icon = utils.getRelatedIcon(rtype)
@ -1079,22 +1150,6 @@
getRef('transaction_detail__type').textContent = type getRef('transaction_detail__type').textContent = type
getRef('transaction_detail__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' }) getRef('transaction_detail__amount').textContent = amount.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
getRef('transaction_detail__time').textContent = getFormattedTime(timestamp) 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) { function getAccountStatus(index) {
@ -1131,19 +1186,19 @@
function renderAccountProgress(index) { function renderAccountProgress(index) {
const { type, status, openTime, closeTime = 0, amount, netAmt } = bank_app.accounts[index] const { type, status, openTime, closeTime = 0, amount, netAmt } = bank_app.accounts[index]
getRef('account_process__steps').innerHTML = '' 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) 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]))) 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 { } else {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Withdrawal complete', getFormattedTime(closeTime))) getRef('account_process__steps').append(render.accountProgressStep('success', 'Withdrawal complete', getFormattedTime(closeTime)))
} }
} else { } else {
if (isPending) { if (isPending) {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Sent repay request', getFormattedTime(pendingRequest.split('_')[0]))) 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 { } else {
getRef('account_process__steps').append(render.accountProgressStep('success', 'Repayment complete', getFormattedTime(closeTime))) getRef('account_process__steps').append(render.accountProgressStep('success', 'Repayment complete', getFormattedTime(closeTime)))
} }
@ -1223,8 +1278,8 @@
accountChart.data.datasets[0].data = [depositTotal, loanTotal] accountChart.data.datasets[0].data = [depositTotal, loanTotal]
accountChart.update() accountChart.update()
} }
getRef('total_deposit').textContent = depositTotal getRef('total_deposit').textContent = depositTotal.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
getRef('total_loan').textContent = loanTotal getRef('total_loan').textContent = loanTotal.toLocaleString(`en-IN`, { style: 'currency', currency: 'INR' })
} }
document.querySelector('theme-toggle').addEventListener('themechange', e => { 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>
<script id="onLoadStartUp"> <script id="onLoadStartUp">
const requestResponsePairs = {} const requestResponsePairs = {}