Added wallet deposit/withdraw UI

This commit is contained in:
sairaj mote 2021-10-04 19:12:31 +05:30
parent 75879ca2f5
commit 5a67beb249
6 changed files with 885 additions and 223 deletions

View File

@ -1,11 +0,0 @@
{
"secret": "Secret_For_Session__Enter_A_Strong_String(Text/Password)",
"blockchain_id": "FLO_ID_of_the_admin",
"blockchain_private": "Private_Key_of_the_Admin",
"port": "8080",
"sql_user": "mySQL_user",
"sql_pwd": "mySQL_password",
"sql_db": "supernode",
"sql_host": "localhost"
}

View File

@ -418,7 +418,7 @@ input{
color: var(--accent-color) color: var(--accent-color)
} }
:host([variant="outlined"]) .input { :host([variant="outlined"]) .input {
box-shadow: 0 0 0 0.1rem rgba(var(--text-color), 0.4) inset; box-shadow: 0 0 0 0.1rem var(--border-color, rgba(var(--text-color), 0.4)) inset;
background: rgba(var(--background-color), 1); background: rgba(var(--background-color), 1);
} }
:host([variant="outlined"]) .label { :host([variant="outlined"]) .label {
@ -2207,3 +2207,405 @@ class SlideButton extends HTMLElement {
window.customElements.define('slide-button', SlideButton); window.customElements.define('slide-button', SlideButton);
const smSelect = document.createElement('template')
smSelect.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
display: -webkit-box;
display: -ms-flexbox;
display: flex;
--accent-color: #4d2588;
--text-color: 17, 17, 17;
--background-color: 255, 255, 255;
--max-height: auto;
--min-width: 100%;
}
:host([disabled]) .select{
opacity: 0.6;
cursor: not-allowed;
}
.hide{
display: none !important;
}
.select{
position: relative;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
cursor: pointer;
width: 100%;
-webkit-tap-highlight-color: transparent;
}
.icon {
height: 1.5rem;
width: 1.5rem;
fill: rgba(var(--text-color), 0.7);
}
.selected-option-text{
font-size: 0.9rem;
overflow: hidden;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;
white-space: nowrap;
}
.selection{
border-radius: 0.3rem;
display: -ms-grid;
display: grid;
-ms-grid-columns: 1fr auto;
grid-template-columns: 1fr auto;
grid-template-areas: 'heading heading' '. .';
padding: 0.4rem 1rem;
background: rgba(var(--text-color), 0.06);
border: solid 1px rgba(var(--text-color), 0.2);
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
outline: none;
}
.selection:focus{
-webkit-box-shadow: 0 0 0 0.1rem var(--accent-color);
box-shadow: 0 0 0 0.1rem var(--accent-color)
}
.icon{
margin-left: 1rem;
}
:host([align-select="left"]) .options{
left: 0;
}
:host([align-select="right"]) .options{
right: 0;
}
.options{
top: 100%;
margin-top: 0.2rem;
overflow: hidden auto;
position: absolute;
grid-area: options;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-orient: vertical;
-webkit-box-direction: normal;
-ms-flex-direction: column;
flex-direction: column;
min-width: var(--min-width);
max-height: var(--max-height);
background: rgba(var(--background-color), 1);
border: solid 1px rgba(var(--text-color), 0.2);
border-radius: 0.3rem;
z-index: 2;
-webkit-box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
box-shadow: 0.4rem 0.8rem 1.2rem #00000030;
}
.rotate{
-webkit-transform: rotate(180deg);
-ms-transform: rotate(180deg);
transform: rotate(180deg)
}
@media (any-hover: hover){
::-webkit-scrollbar{
width: 0.5rem;
height: 0.5rem;
}
::-webkit-scrollbar-thumb{
background: rgba(var(--text-color), 0.3);
border-radius: 1rem;
&:hover{
background: rgba(var(--text-color), 0.5);
}
}
}
</style>
<div class="select" >
<div class="selection">
<div class="selected-option-text"></div>
<svg class="icon toggle" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 13.172l4.95-4.95 1.414 1.414L12 16 5.636 9.636 7.05 8.222z"/></svg>
</div>
<div part="options" class="options hide">
<slot></slot>
</div>
</div>`;
customElements.define('sm-select', class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(smSelect.content.cloneNode(true))
this.reset = this.reset.bind(this)
this.open = this.open.bind(this)
this.collapse = this.collapse.bind(this)
this.toggle = this.toggle.bind(this)
this.handleOptionsNavigation = this.handleOptionsNavigation.bind(this)
this.handleOptionSelection = this.handleOptionSelection.bind(this)
this.handleKeydown = this.handleKeydown.bind(this)
this.handleClickOutside = this.handleClickOutside.bind(this)
this.availableOptions
this.previousOption
this.isOpen = false;
this.slideDown = [{
transform: `translateY(-0.5rem)`,
opacity: 0
},
{
transform: `translateY(0)`,
opacity: 1
}
]
this.slideUp = [{
transform: `translateY(0)`,
opacity: 1
},
{
transform: `translateY(-0.5rem)`,
opacity: 0
}
]
this.animationOptions = {
duration: 300,
fill: "forwards",
easing: 'ease'
}
this.optionList = this.shadowRoot.querySelector('.options')
this.chevron = this.shadowRoot.querySelector('.toggle')
this.selection = this.shadowRoot.querySelector('.selection')
this.selectedOptionText = this.shadowRoot.querySelector('.selected-option-text')
}
static get observedAttributes() {
return ['value', 'disabled']
}
get value() {
return this.getAttribute('value')
}
set value(val) {
this.setAttribute('value', val)
}
reset(fire = true) {
if (this.availableOptions[0] && this.previousOption !== this.availableOptions[0]) {
const firstElement = this.availableOptions[0];
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
}
firstElement.classList.add('check-selected')
this.value = firstElement.getAttribute('value')
this.selectedOptionText.textContent = firstElement.textContent
this.previousOption = firstElement;
if (fire) {
this.fireEvent()
}
}
}
open() {
this.optionList.classList.remove('hide')
this.optionList.animate(this.slideDown, this.animationOptions)
this.chevron.classList.add('rotate')
this.isOpen = true
}
collapse() {
this.chevron.classList.remove('rotate')
this.optionList.animate(this.slideUp, this.animationOptions)
.onfinish = () => {
this.optionList.classList.add('hide')
this.isOpen = false
}
}
toggle() {
if (!this.isOpen && !this.hasAttribute('disabled')) {
this.open()
} else {
this.collapse()
}
}
fireEvent() {
this.dispatchEvent(new CustomEvent('change', {
bubbles: true,
composed: true,
detail: {
value: this.value
}
}))
}
handleOptionsNavigation(e) {
if (e.code === 'ArrowUp') {
e.preventDefault()
if (document.activeElement.previousElementSibling) {
document.activeElement.previousElementSibling.focus()
} else {
this.availableOptions[this.availableOptions.length - 1].focus()
}
}
else if (e.code === 'ArrowDown') {
e.preventDefault()
if (document.activeElement.nextElementSibling) {
document.activeElement.nextElementSibling.focus()
} else {
this.availableOptions[0].focus()
}
}
}
handleOptionSelection(e) {
if (this.previousOption !== document.activeElement) {
this.value = document.activeElement.getAttribute('value')
this.selectedOptionText.textContent = document.activeElement.textContent;
this.fireEvent()
if (this.previousOption) {
this.previousOption.classList.remove('check-selected')
}
document.activeElement.classList.add('check-selected')
this.previousOption = document.activeElement
}
}
handleClick(e) {
if (e.target === this) {
this.toggle()
}
else {
this.handleOptionSelection()
this.collapse()
}
}
handleKeydown(e) {
if (e.target === this) {
if (this.isOpen && e.code === 'ArrowDown') {
e.preventDefault()
this.availableOptions[0].focus()
this.handleOptionSelection(e)
}
else if (e.code === 'Enter' || e.code === 'Space') {
e.preventDefault()
this.toggle()
}
}
else {
this.handleOptionsNavigation(e)
this.handleOptionSelection(e)
if (e.code === 'Enter' || e.code === 'Space') {
e.preventDefault()
this.collapse()
}
}
}
handleClickOutside(e) {
if (this.isOpen && !this.contains(e.target)) {
this.collapse()
}
}
connectedCallback() {
this.setAttribute('role', 'listbox')
if (!this.hasAttribute('disabled')) {
this.selection.setAttribute('tabindex', '0')
}
let slot = this.shadowRoot.querySelector('slot')
slot.addEventListener('slotchange', e => {
this.availableOptions = slot.assignedElements()
this.reset(false)
});
this.addEventListener('click', this.handleClick)
this.addEventListener('keydown', this.handleKeydown)
document.addEventListener('mousedown', this.handleClickOutside)
}
disconnectedCallback() {
this.removeEventListener('click', this.toggle)
this.removeEventListener('keydown', this.handleKeydown)
document.removeEventListener('mousedown', this.handleClickOutside)
}
attributeChangedCallback(name) {
if (name === "disabled") {
if (this.hasAttribute('disabled')) {
this.selection.removeAttribute('tabindex')
} else {
this.selection.setAttribute('tabindex', '0')
}
}
}
})
// option
const smOption = document.createElement('template')
smOption.innerHTML = `
<style>
*{
padding: 0;
margin: 0;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
:host{
display: -webkit-box;
display: -ms-flexbox;
display: flex;
}
.option{
display: grid;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
min-width: 100%;
gap: 0.5rem;
grid-template-columns: max-content minmax(0, 1fr);
padding: 0.8rem 1.2rem;
cursor: pointer;
overflow-wrap: break-word;
outline: none;
user-select: none;
}
:host(:focus){
outline: none;
background: rgba(var(--text-color), 0.1);
}
.icon {
opacity: 0;
height: 1.2rem;
width: 1.2rem;
fill: rgba(var(--text-color), 0.8);
}
:host(:focus) .option .icon{
opacity: 0.4
}
:host(.check-selected) .icon{
opacity: 1
}
@media (hover: hover){
.option:hover{
background: rgba(var(--text-color), 0.1);
}
:host(:not(.check-selected):hover) .icon{
opacity: 0.4
}
}
</style>
<div class="option">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="none" d="M0 0h24v24H0z"/><path d="M10 15.172l9.192-9.193 1.415 1.414L10 18l-6.364-6.364 1.414-1.414z"/></svg>
<slot></slot>
</div>`;
customElements.define('sm-option', class extends HTMLElement {
constructor() {
super()
this.attachShadow({
mode: 'open'
}).append(smOption.content.cloneNode(true))
}
connectedCallback() {
this.setAttribute('role', 'option')
this.setAttribute('tabindex', '0')
}
})

View File

@ -376,24 +376,29 @@ ul {
fill: var(--accent-color); fill: var(--accent-color);
} }
#confirmation_popup { #confirmation_popup,
#prompt_popup {
-webkit-box-orient: vertical; -webkit-box-orient: vertical;
-webkit-box-direction: normal; -webkit-box-direction: normal;
-ms-flex-direction: column; -ms-flex-direction: column;
flex-direction: column; flex-direction: column;
} }
#confirmation_popup h4 { #confirmation_popup h4,
#prompt_popup h4 {
font-weight: 500; font-weight: 500;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
#confirmation_popup sm-button { #confirmation_popup sm-button,
#prompt_popup sm-button {
margin: 0; margin: 0;
} }
#confirmation_popup .flex { #confirmation_popup .flex,
#prompt_popup .flex {
padding: 0; padding: 0;
margin-top: 1rem; margin-top: 1rem;
} }
#confirmation_popup .flex sm-button:first-of-type { #confirmation_popup .flex sm-button:first-of-type,
#prompt_popup .flex sm-button:first-of-type {
margin-right: 0.6rem; margin-right: 0.6rem;
margin-left: auto; margin-left: auto;
} }
@ -405,6 +410,22 @@ button:active,
transform: scale(0.96); transform: scale(0.96);
} }
.popup__header {
display: grid;
gap: 0.5rem;
width: 100%;
padding: 0 1.5rem 0 0.5rem;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
grid-template-columns: auto 1fr auto;
}
.popup__header__close {
padding: 0.5rem;
cursor: pointer;
}
#main_page { #main_page {
padding: 1.5rem; padding: 1.5rem;
} }
@ -571,12 +592,11 @@ strip-option:last-of-type {
#home { #home {
height: 100%; height: 100%;
display: grid; display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr);
} }
#main_header { #main_header {
padding: 1.5rem; padding: 1.8rem 1.5rem;
display: grid; display: grid;
gap: 1rem; gap: 1rem;
-webkit-box-align: center; -webkit-box-align: center;
@ -589,7 +609,7 @@ strip-option:last-of-type {
--width: min(24rem, 100%); --width: min(24rem, 100%);
-ms-flex-item-align: start; -ms-flex-item-align: start;
align-self: flex-start; align-self: flex-start;
padding: 0 1.5rem; padding: 1rem 1.5rem;
} }
#quantity_selector .button { #quantity_selector .button {
@ -611,22 +631,48 @@ strip-option:last-of-type {
min-width: 8ch; min-width: 8ch;
} }
#orders_section {
padding: 1.5rem;
}
#user_section { #user_section {
gap: 1.5rem; gap: 1.5rem;
padding: 0 1.5rem; padding: 1.5rem;
-ms-flex-line-pack: start; -ms-flex-line-pack: start;
align-content: flex-start; align-content: flex-start;
} }
.wallet_actions__wrapper {
grid-column: span 3;
gap: 0.5rem;
margin-top: 0.5rem;
}
.wallet_actions__wrapper .button {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
}
.balance-card { .balance-card {
display: grid; display: grid;
grid-template-columns: auto 1fr auto;
-webkit-box-align: center; -webkit-box-align: center;
-ms-flex-align: center; -ms-flex-align: center;
align-items: center; align-items: center;
gap: 0.3rem 1rem; gap: 0.3rem 1rem;
padding: 0.5rem 0;
border-radius: 0.5rem; border-radius: 0.5rem;
} }
.balance-card.is-locked {
grid-template-columns: auto 1fr;
gap: 1rem;
}
.balance-card.is-locked .label {
font-size: 0.8rem;
color: rgba(var(--text-color), 0.8);
}
.balance-card:not(.is-locked) {
grid-template-columns: auto 1fr auto;
}
.balance-card__icon { .balance-card__icon {
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
@ -649,27 +695,58 @@ strip-option:last-of-type {
font-size: 0.9rem; font-size: 0.9rem;
font-weight: 500; font-weight: 500;
} }
.balance-card__amount { .balance-card__amount-wrapper {
font-size: 1rem; grid-column: span 2;
font-weight: 700; gap: 0.3rem 1rem;
grid-template-columns: 1fr 1fr;
} }
.balance-card__actions { .balance-card__amount-wrapper > :nth-child(even) {
grid-column: span 3; text-align: right;
gap: 0.5rem;
margin-top: 0.5rem;
}
.balance-card__actions .button {
-webkit-box-flex: 1;
-ms-flex: 1;
flex: 1;
} }
@media screen and (max-width: 640px) { .loader-button-wrapper {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
position: relative;
-webkit-box-pack: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.loader-button-wrapper sm-button,
.loader-button-wrapper slide-button {
width: 100%;
z-index: 1;
-webkit-transition: -webkit-clip-path 0.3s;
transition: -webkit-clip-path 0.3s;
transition: clip-path 0.3s;
transition: clip-path 0.3s, -webkit-clip-path 0.3s;
-webkit-clip-path: circle(100%);
clip-path: circle(100%);
}
.loader-button-wrapper sm-button.clip,
.loader-button-wrapper slide-button.clip {
pointer-events: none;
-webkit-clip-path: circle(0);
clip-path: circle(0);
}
.loader-button-wrapper sm-spinner {
position: absolute;
}
@media screen and (max-width: 40rem) {
sm-button { sm-button {
--padding: 0.9rem 1.6rem; --padding: 0.9rem 1.6rem;
} }
} }
@media screen and (min-width: 640px) { @media screen and (min-width: 40rem) {
sm-popup {
--width: 24rem;
}
.h1 { .h1 {
font-size: 2rem; font-size: 2rem;
} }
@ -686,6 +763,10 @@ strip-option:last-of-type {
font-size: 1rem; font-size: 1rem;
} }
.popup__header {
padding: 1rem 1.5rem 0 0.5rem;
}
#confirmation_popup { #confirmation_popup {
--width: 24rem; --width: 24rem;
} }
@ -694,25 +775,30 @@ strip-option:last-of-type {
grid-template-columns: 1fr 90vw 1fr; grid-template-columns: 1fr 90vw 1fr;
} }
} }
@media screen and (min-width: 1024px) { @media screen and (min-width: 64rem) {
.page-layout { .page-layout {
grid-template-columns: 1fr 80vw 1fr; grid-template-columns: 1fr 80vw 1fr;
} }
#home { #home {
-webkit-box-align: start;
-ms-flex-align: start;
align-items: flex-start;
padding: 1.5vmax 3vmax;
grid-template-columns: 24rem minmax(0, 1fr) 20rem; grid-template-columns: 24rem minmax(0, 1fr) 20rem;
grid-template-rows: auto 1fr; gap: 1rem;
} }
#home > * {
#main_header { border-radius: 0.5rem;
grid-column: span 3; background-color: var(--foreground-color);
border: solid thin rgba(var(--text-color), 0.1);
} }
.hide-on-desktop { .hide-on-desktop {
display: none; display: none;
} }
} }
@media screen and (min-width: 1920px) { @media screen and (min-width: 120rem) {
.page-layout { .page-layout {
grid-template-columns: 1fr 70vw 1fr; grid-template-columns: 1fr 70vw 1fr;
} }

File diff suppressed because one or more lines are too long

View File

@ -341,22 +341,19 @@ ul {
fill: var(--accent-color); fill: var(--accent-color);
} }
} }
#confirmation_popup { #confirmation_popup,
#prompt_popup {
flex-direction: column; flex-direction: column;
h4 { h4 {
font-weight: 500; font-weight: 500;
margin-bottom: 0.5rem; margin-bottom: 0.5rem;
} }
sm-button { sm-button {
margin: 0; margin: 0;
} }
.flex { .flex {
padding: 0; padding: 0;
margin-top: 1rem; margin-top: 1rem;
sm-button:first-of-type { sm-button:first-of-type {
margin-right: 0.6rem; margin-right: 0.6rem;
margin-left: auto; margin-left: auto;
@ -370,6 +367,20 @@ button:active,
transform: scale(0.96); transform: scale(0.96);
} }
.popup__header {
display: grid;
gap: 0.5rem;
width: 100%;
padding: 0 1.5rem 0 0.5rem;
align-items: center;
grid-template-columns: auto 1fr auto;
}
.popup__header__close {
padding: 0.5rem;
cursor: pointer;
}
#main_page { #main_page {
padding: 1.5rem; padding: 1.5rem;
@ -517,12 +528,11 @@ strip-option {
#home { #home {
height: 100%; height: 100%;
display: grid; display: grid;
grid-template-rows: auto 1fr auto;
grid-template-columns: minmax(0, 1fr); grid-template-columns: minmax(0, 1fr);
} }
#main_header { #main_header {
padding: 1.5rem; padding: 1.8rem 1.5rem;
display: grid; display: grid;
gap: 1rem; gap: 1rem;
align-items: center; align-items: center;
@ -532,7 +542,7 @@ strip-option {
#trade_form { #trade_form {
--width: min(24rem, 100%); --width: min(24rem, 100%);
align-self: flex-start; align-self: flex-start;
padding: 0 1.5rem; padding: 1rem 1.5rem;
} }
#quantity_selector { #quantity_selector {
.button { .button {
@ -551,19 +561,41 @@ strip-option {
font-weight: 500; font-weight: 500;
min-width: 8ch; min-width: 8ch;
} }
#orders_section {
padding: 1.5rem;
}
#user_section { #user_section {
gap: 1.5rem; gap: 1.5rem;
padding: 0 1.5rem; padding: 1.5rem;
align-content: flex-start; align-content: flex-start;
} }
.user_section__header { .user_section__header {
} }
.wallet_actions__wrapper {
grid-column: span 3;
gap: 0.5rem;
margin-top: 0.5rem;
.button {
flex: 1;
}
}
.balance-card { .balance-card {
display: grid; display: grid;
grid-template-columns: auto 1fr auto;
align-items: center; align-items: center;
gap: 0.3rem 1rem; gap: 0.3rem 1rem;
padding: 0.5rem 0;
border-radius: 0.5rem; border-radius: 0.5rem;
&.is-locked {
grid-template-columns: auto 1fr;
gap: 1rem;
.label {
font-size: 0.8rem;
color: rgba(var(--text-color), 0.8);
}
}
&:not(.is-locked) {
grid-template-columns: auto 1fr auto;
}
&__icon { &__icon {
display: flex; display: flex;
align-content: center; align-content: center;
@ -581,25 +613,44 @@ strip-option {
font-size: 0.9rem; font-size: 0.9rem;
font-weight: 500; font-weight: 500;
} }
&__amount { &__amount-wrapper {
font-size: 1rem; grid-column: span 2;
font-weight: 700; gap: 0.3rem 1rem;
} grid-template-columns: 1fr 1fr;
&__actions { & > :nth-child(even) {
grid-column: span 3; text-align: right;
gap: 0.5rem;
margin-top: 0.5rem;
.button {
flex: 1;
} }
} }
} }
@media screen and (max-width: 640px) { .loader-button-wrapper {
display: flex;
position: relative;
justify-content: center;
align-items: center;
sm-button,
slide-button {
width: 100%;
z-index: 1;
transition: clip-path 0.3s;
clip-path: circle(100%);
&.clip {
pointer-events: none;
clip-path: circle(0);
}
}
sm-spinner {
position: absolute;
}
}
@media screen and (max-width: 40rem) {
sm-button { sm-button {
--padding: 0.9rem 1.6rem; --padding: 0.9rem 1.6rem;
} }
} }
@media screen and (min-width: 640px) { @media screen and (min-width: 40rem) {
sm-popup {
--width: 24rem;
}
.h1 { .h1 {
font-size: 2rem; font-size: 2rem;
} }
@ -615,6 +666,9 @@ strip-option {
.h4 { .h4 {
font-size: 1rem; font-size: 1rem;
} }
.popup__header {
padding: 1rem 1.5rem 0 0.5rem;
}
#confirmation_popup { #confirmation_popup {
--width: 24rem; --width: 24rem;
} }
@ -622,24 +676,28 @@ strip-option {
grid-template-columns: 1fr 90vw 1fr; grid-template-columns: 1fr 90vw 1fr;
} }
} }
@media screen and (max-width: 1024px) { @media screen and (max-width: 64rem) {
} }
@media screen and (min-width: 1024px) { @media screen and (min-width: 64rem) {
.page-layout { .page-layout {
grid-template-columns: 1fr 80vw 1fr; grid-template-columns: 1fr 80vw 1fr;
} }
#home { #home {
align-items: flex-start;
padding: 1.5vmax 3vmax;
grid-template-columns: 24rem minmax(0, 1fr) 20rem; grid-template-columns: 24rem minmax(0, 1fr) 20rem;
grid-template-rows: auto 1fr; gap: 1rem;
} & > * {
#main_header { border-radius: 0.5rem;
grid-column: span 3; background-color: var(--foreground-color);
border: solid thin rgba(var(--text-color), 0.1);
}
} }
.hide-on-desktop { .hide-on-desktop {
display: none; display: none;
} }
} }
@media screen and (min-width: 1920px) { @media screen and (min-width: 120rem) {
.page-layout { .page-layout {
grid-template-columns: 1fr 70vw 1fr; grid-template-columns: 1fr 70vw 1fr;
} }

View File

@ -50,6 +50,15 @@
<sm-button variant="no-outline" class="submit-btn">OK</sm-button> <sm-button variant="no-outline" class="submit-btn">OK</sm-button>
</div> </div>
</sm-popup> </sm-popup>
<sm-popup id="prompt_popup">
<h4 id="prompt_title"></h4>
<p id="prompt_message"></p>
<sm-input id="prompt_input"></sm-input>
<div class="flex align-center">
<sm-button variant="no-outline" class="cancel-btn">Cancel</sm-button>
<sm-button variant="no-outline" class="submit-btn" type="submit">OK</sm-button>
</div>
</sm-popup>
<article id="landing" class="page page-layout hide-completely"> <article id="landing" class="page page-layout hide-completely">
<header class="flex space-between"> <header class="flex space-between">
<div class="logo"> <div class="logo">
@ -139,48 +148,58 @@
<h4>Loading RanchiMall Market</h4> <h4>Loading RanchiMall Market</h4>
</article> </article>
<article id="home" class="page"> <article id="home" class="page">
<header id="main_header"> <section>
<div class="logo"> <header id="main_header">
<svg class="main-logo" viewBox="0 0 27.25 32"> <div class="logo">
<title>RanchiMall</title> <svg class="main-logo" viewBox="0 0 27.25 32">
<path <title>RanchiMall</title>
d="M27.14,30.86c-.74-2.48-3-4.36-8.25-6.94a20,20,0,0,1-4.2-2.49,6,6,0,0,1-1.25-1.67,4,4,0,0,1,0-2.26c.37-1.08.79-1.57,3.89-4.55a11.66,11.66,0,0,0,3.34-4.67,6.54,6.54,0,0,0,.05-2.82C20,3.6,18.58,2,16.16.49c-.89-.56-1.29-.64-1.3-.24a3,3,0,0,1-.3.72l-.3.55L13.42.94C13,.62,12.4.26,12.19.15c-.4-.2-.73-.18-.72.05a9.39,9.39,0,0,1-.61,1.33s-.14,0-.27-.13C8.76.09,8-.27,8,.23A11.73,11.73,0,0,1,6.76,2.6C4.81,5.87,2.83,7.49.77,7.49c-.89,0-.88,0-.61,1,.22.85.33.92,1.09.69A5.29,5.29,0,0,0,3,8.33c.23-.17.45-.29.49-.26a2,2,0,0,1,.22.63A1.31,1.31,0,0,0,4,9.34a5.62,5.62,0,0,0,2.27-.87L7,8l.13.55c.19.74.32.82,1,.65a7.06,7.06,0,0,0,3.46-2.47l.6-.71-.06.64c-.17,1.63-1.3,3.42-3.39,5.42L6.73,14c-3.21,3.06-3,5.59.6,8a46.77,46.77,0,0,0,4.6,2.41c.28.13,1,.52,1.59.87,3.31,2,4.95,3.92,4.95,5.93a2.49,2.49,0,0,0,.07.77h0c.09.09,0,.1.9-.14a2.61,2.61,0,0,0,.83-.32,3.69,3.69,0,0,0-.55-1.83A11.14,11.14,0,0,0,17,26.81a35.7,35.7,0,0,0-5.1-2.91C9.37,22.64,8.38,22,7.52,21.17a3.53,3.53,0,0,1-1.18-2.48c0-1.38.71-2.58,2.5-4.23,2.84-2.6,3.92-3.91,4.67-5.65a3.64,3.64,0,0,0,.42-2A3.37,3.37,0,0,0,13.61,5l-.32-.74.29-.48c.17-.27.37-.63.46-.8l.15-.3.44.64a5.92,5.92,0,0,1,1,2.81,5.86,5.86,0,0,1-.42,1.94c0,.12-.12.3-.15.4a9.49,9.49,0,0,1-.67,1.1,28,28,0,0,1-4,4.29C8.62,15.49,8.05,16.44,8,17.78a3.28,3.28,0,0,0,1.11,2.76c.95,1,2.07,1.74,5.25,3.32,3.64,1.82,5.22,2.9,6.41,4.38A4.78,4.78,0,0,1,21.94,31a3.21,3.21,0,0,0,.14.92,1.06,1.06,0,0,0,.43-.05l.83-.22.46-.12-.06-.46c-.21-1.53-1.62-3.25-3.94-4.8a37.57,37.57,0,0,0-5.22-2.82A13.36,13.36,0,0,1,11,21.19a3.36,3.36,0,0,1-.8-4.19c.41-.85.83-1.31,3.77-4.15,2.39-2.31,3.43-4.13,3.43-6a5.85,5.85,0,0,0-2.08-4.29c-.23-.21-.44-.43-.65-.65A2.5,2.5,0,0,1,15.27.69a10.6,10.6,0,0,1,2.91,2.78A4.16,4.16,0,0,1,19,6.16a4.91,4.91,0,0,1-.87,3c-.71,1.22-1.26,1.82-4.27,4.67a9.47,9.47,0,0,0-2.07,2.6,2.76,2.76,0,0,0-.33,1.54,2.76,2.76,0,0,0,.29,1.47c.57,1.21,2.23,2.55,4.65,3.73a32.41,32.41,0,0,1,5.82,3.24c2.16,1.6,3.2,3.16,3.2,4.8a1.94,1.94,0,0,0,.09.76,4.54,4.54,0,0,0,1.66-.4C27.29,31.42,27.29,31.37,27.14,30.86ZM6.1,7h0a3.77,3.77,0,0,1-1.46.45L4,7.51l.68-.83a25.09,25.09,0,0,0,3-4.82A12,12,0,0,1,8.28.76c.11-.12.77.32,1.53,1l.63.58-.57.84A10.34,10.34,0,0,1,6.1,7Zm5.71-1.78A9.77,9.77,0,0,1,9.24,7.18h0a5.25,5.25,0,0,1-1.17.28l-.58,0,.65-.78a21.29,21.29,0,0,0,2.1-3.12c.22-.41.42-.76.44-.79s.5.43.9,1.24L12,5ZM13.41,3a2.84,2.84,0,0,1-.45.64,11,11,0,0,1-.9-.91l-.84-.9.19-.45c.34-.79.39-.8,1-.31A9.4,9.4,0,0,1,13.8,2.33q-.18.34-.39.69Z" /> <path
</svg> d="M27.14,30.86c-.74-2.48-3-4.36-8.25-6.94a20,20,0,0,1-4.2-2.49,6,6,0,0,1-1.25-1.67,4,4,0,0,1,0-2.26c.37-1.08.79-1.57,3.89-4.55a11.66,11.66,0,0,0,3.34-4.67,6.54,6.54,0,0,0,.05-2.82C20,3.6,18.58,2,16.16.49c-.89-.56-1.29-.64-1.3-.24a3,3,0,0,1-.3.72l-.3.55L13.42.94C13,.62,12.4.26,12.19.15c-.4-.2-.73-.18-.72.05a9.39,9.39,0,0,1-.61,1.33s-.14,0-.27-.13C8.76.09,8-.27,8,.23A11.73,11.73,0,0,1,6.76,2.6C4.81,5.87,2.83,7.49.77,7.49c-.89,0-.88,0-.61,1,.22.85.33.92,1.09.69A5.29,5.29,0,0,0,3,8.33c.23-.17.45-.29.49-.26a2,2,0,0,1,.22.63A1.31,1.31,0,0,0,4,9.34a5.62,5.62,0,0,0,2.27-.87L7,8l.13.55c.19.74.32.82,1,.65a7.06,7.06,0,0,0,3.46-2.47l.6-.71-.06.64c-.17,1.63-1.3,3.42-3.39,5.42L6.73,14c-3.21,3.06-3,5.59.6,8a46.77,46.77,0,0,0,4.6,2.41c.28.13,1,.52,1.59.87,3.31,2,4.95,3.92,4.95,5.93a2.49,2.49,0,0,0,.07.77h0c.09.09,0,.1.9-.14a2.61,2.61,0,0,0,.83-.32,3.69,3.69,0,0,0-.55-1.83A11.14,11.14,0,0,0,17,26.81a35.7,35.7,0,0,0-5.1-2.91C9.37,22.64,8.38,22,7.52,21.17a3.53,3.53,0,0,1-1.18-2.48c0-1.38.71-2.58,2.5-4.23,2.84-2.6,3.92-3.91,4.67-5.65a3.64,3.64,0,0,0,.42-2A3.37,3.37,0,0,0,13.61,5l-.32-.74.29-.48c.17-.27.37-.63.46-.8l.15-.3.44.64a5.92,5.92,0,0,1,1,2.81,5.86,5.86,0,0,1-.42,1.94c0,.12-.12.3-.15.4a9.49,9.49,0,0,1-.67,1.1,28,28,0,0,1-4,4.29C8.62,15.49,8.05,16.44,8,17.78a3.28,3.28,0,0,0,1.11,2.76c.95,1,2.07,1.74,5.25,3.32,3.64,1.82,5.22,2.9,6.41,4.38A4.78,4.78,0,0,1,21.94,31a3.21,3.21,0,0,0,.14.92,1.06,1.06,0,0,0,.43-.05l.83-.22.46-.12-.06-.46c-.21-1.53-1.62-3.25-3.94-4.8a37.57,37.57,0,0,0-5.22-2.82A13.36,13.36,0,0,1,11,21.19a3.36,3.36,0,0,1-.8-4.19c.41-.85.83-1.31,3.77-4.15,2.39-2.31,3.43-4.13,3.43-6a5.85,5.85,0,0,0-2.08-4.29c-.23-.21-.44-.43-.65-.65A2.5,2.5,0,0,1,15.27.69a10.6,10.6,0,0,1,2.91,2.78A4.16,4.16,0,0,1,19,6.16a4.91,4.91,0,0,1-.87,3c-.71,1.22-1.26,1.82-4.27,4.67a9.47,9.47,0,0,0-2.07,2.6,2.76,2.76,0,0,0-.33,1.54,2.76,2.76,0,0,0,.29,1.47c.57,1.21,2.23,2.55,4.65,3.73a32.41,32.41,0,0,1,5.82,3.24c2.16,1.6,3.2,3.16,3.2,4.8a1.94,1.94,0,0,0,.09.76,4.54,4.54,0,0,0,1.66-.4C27.29,31.42,27.29,31.37,27.14,30.86ZM6.1,7h0a3.77,3.77,0,0,1-1.46.45L4,7.51l.68-.83a25.09,25.09,0,0,0,3-4.82A12,12,0,0,1,8.28.76c.11-.12.77.32,1.53,1l.63.58-.57.84A10.34,10.34,0,0,1,6.1,7Zm5.71-1.78A9.77,9.77,0,0,1,9.24,7.18h0a5.25,5.25,0,0,1-1.17.28l-.58,0,.65-.78a21.29,21.29,0,0,0,2.1-3.12c.22-.41.42-.76.44-.79s.5.43.9,1.24L12,5ZM13.41,3a2.84,2.84,0,0,1-.45.64,11,11,0,0,1-.9-.91l-.84-.9.19-.45c.34-.79.39-.8,1-.31A9.4,9.4,0,0,1,13.8,2.33q-.18.34-.39.69Z" />
<div class="grid"> </svg>
<h4>RanchiMall Market</h4> <div class="grid">
<h4>RanchiMall Market</h4>
</div>
</div> </div>
</div> <theme-toggle></theme-toggle>
<theme-toggle></theme-toggle> </header>
</header> <sm-form id="trade_form">
<sm-form id="trade_form"> <div class="flex space-between align-center">
<h4>Trade FLO</h4>
<strip-select id="trade_type_selector">
<strip-option value="buy" selected>Buy</strip-option>
<strip-option value="sell">Sell</strip-option>
</strip-select>
</div>
<sm-input id="get_price" variant="outlined" placeholder="Max price" type="number" step="0.00000001"
required hiderequired animate>
</sm-input>
<sm-input id="get_quantity" variant="outlined" placeholder="Quantity" type="number" step="0.00000001"
required hiderequired animate>
</sm-input>
<div id="quantity_selector" class="flex align-center">
<span id="quantity_type">Rupee</span>
<button class="button" value="25">25%</button>
<button class="button" value="50">50%</button>
<button class="button" value="75">75%</button>
<button class="button" value="100">100%</button>
</div>
<sm-button id="trade_button" class="uppercase" variant="primary" onclick="tradeFlo()">BUY</sm-button>
</sm-form>
</section>
<section id="orders_section" class="grid gap-1-5">
<div class="flex space-between align-center"> <div class="flex space-between align-center">
<h4>Trade FLO</h4> <h4>My orders</h4>
<strip-select id="trade_type_selector"> <strip-select id="orders_scope_selector">
<strip-option value="buy" selected>Buy</strip-option> <strip-option value="active" selected>Open</strip-option>
<strip-option value="sell">Sell</strip-option> <strip-option value="completed">Completed</strip-option>
</strip-select> </strip-select>
</div> </div>
<sm-input id="get_price" placeholder="Max price" type="number" step="0.00000001" required hiderequired>
</sm-input>
<sm-input id="get_quantity" placeholder="Quantity" type="number" step="0.0001" required hiderequired>
</sm-input>
<div id="quantity_selector" class="flex align-center">
<span id="quantity_type">Rupee</span>
<button class="button" value="25">25%</button>
<button class="button" value="50">50%</button>
<button class="button" value="75">75%</button>
<button class="button" value="100">100%</button>
</div>
<sm-button id="trade_button" class="uppercase" variant="primary" onclick="tradeFlo()">BUY</sm-button>
</sm-form>
<section>
<h4>My orders</h4>
<div class="table" style="--table-columns: 4;"> <div class="table" style="--table-columns: 4;">
<div class="table__header table__row"> <div class="table__header table__row">
<div></div> <div></div>
<div>Quantity</div> <div>Quantity</div>
<div>At price</div> <div>At price</div>
<div>Order Placed</div> <div>Order placed</div>
</div> </div>
</div> </div>
</section> </section>
@ -195,44 +214,69 @@
</svg> </svg>
My wallet My wallet
</h4> </h4>
<div class="balance-card"> <div id="wallet_actions">
<div class="balance-card__icon"> <p>Select asset</p>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <sm-select id="wallet_asset_selector">
<path <sm-option value="FLO">FLO</sm-option>
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" /> <sm-option value="Rupee">Rupee</sm-option>
</svg> </sm-select>
</div> <div class="flex wallet_actions__wrapper">
<div class="balance-card__token">FLO</div> <button class="button" value="deposit">
<div id="flo_balance" class="balance-card__amount"></div>
<div class="flex balance-card__actions">
<button class="button" onclick="UI_evt.depositFLO();">
Deposit Deposit
</button> </button>
<button class="button" onclick="UI_evt.withdrawFLO()"> <button class="button" value="withdraw">
Withdraw Withdraw
</button> </button>
</div> </div>
</div> </div>
<div class="balance-card"> <div class="grid gap-0-5">
<div class="balance-card__icon"> <h4>Balance</h4>
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <div class="balance-card">
<path <div class="balance-card__icon">
d="M15.3,4.91a4.78,4.78,0,0,0-.39-.5l3.14,0L18.75,2H6L5.25,4.6H9a4.22,4.22,0,0,1,3.06,1,3.16,3.16,0,0,1,.75,1.24H5.93L5.25,9.22h7.62a3.15,3.15,0,0,1-.34.82,3,3,0,0,1-1.37,1.17,5.34,5.34,0,0,1-2.2.4H5.5l0,1.9,7,8.49h3.56v-.17L9.68,14l.09,0a8.07,8.07,0,0,0,3.65-1,5,5,0,0,0,2-2.09A6.29,6.29,0,0,0,16,9.22h2.1l.69-2.42H15.93A5.93,5.93,0,0,0,15.3,4.91Z" /> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
</svg> <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"></div>
</div> </div>
<div class="balance-card__token">Rupee</div> <div class="balance-card">
<div id="rupee_balance" class="balance-card__amount">₹15402</div> <div class="balance-card__icon">
<div class="flex balance-card__actions"> <svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<button class="button" onclick="UI_evt.depositRupee()"> <path
Deposit d="M15.3,4.91a4.78,4.78,0,0,0-.39-.5l3.14,0L18.75,2H6L5.25,4.6H9a4.22,4.22,0,0,1,3.06,1,3.16,3.16,0,0,1,.75,1.24H5.93L5.25,9.22h7.62a3.15,3.15,0,0,1-.34.82,3,3,0,0,1-1.37,1.17,5.34,5.34,0,0,1-2.2.4H5.5l0,1.9,7,8.49h3.56v-.17L9.68,14l.09,0a8.07,8.07,0,0,0,3.65-1,5,5,0,0,0,2-2.09A6.29,6.29,0,0,0,16,9.22h2.1l.69-2.42H15.93A5.93,5.93,0,0,0,15.3,4.91Z" />
</button> </svg>
<button class="button" onclick="UI_evt.withdrawRupee()"> </div>
Withdraw <div class="balance-card__token">Rupee</div>
</button> <div id="rupee_balance"></div>
</div> </div>
</div> </div>
</section> </section>
</article> </article>
<sm-popup id="wallet_popup">
<header slot="header" class="popup__header">
<button class="popup__header__close" onclick="hidePopup()">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24">
<path fill="none" d="M0 0h24v24H0z" />
<path
d="M12 10.586l4.95-4.95 1.414 1.414-4.95 4.95 4.95 4.95-1.414 1.414-4.95-4.95-4.95 4.95-1.414-1.414 4.95-4.95-4.95-4.95L7.05 5.636z" />
</svg>
</button>
<h4 id="wallet_popup__title" class="capitalize"></h4>
</header>
<sm-form id="wallet_form">
<sm-input id="get_user_amount" variant="outlined" placeholder="Quantity" type="number" step="0.00000001"
required hiderequired animate>
</sm-input>
<sm-input id="get_private_key" variant="outlined" placeholder="FLO private key" type="password" required
error-text="Invalid private key" hiderequired animate>
</sm-input>
<div id="wallet_popup__cta_wrapper" class="loader-button-wrapper">
<sm-button id="wallet_popup__cta" variant="primary"></sm-button>
</div>
</sm-form>
</sm-popup>
<form id="login-form"> <form id="login-form">
<fieldset> <fieldset>
<legend>Login</legend> <legend>Login</legend>
@ -247,8 +291,6 @@
<fieldset> <fieldset>
<legend>Profile</legend> <legend>Profile</legend>
<span id="user_id"></span><br /> <span id="user_id"></span><br />
FLO: <span id="flo_bal"></span><br />
Rupee: <span id="rupee_bal"></span><br />
<button onclick="proxy.lock();">Add password lock</button><br /> <button onclick="proxy.lock();">Add password lock</button><br />
<button onclick="UI_evt.logout();">logout</button> <button onclick="UI_evt.logout();">logout</button>
<button onclick="toggle_view('my-profile');">Toggle</button> <button onclick="toggle_view('my-profile');">Toggle</button>
@ -278,7 +320,7 @@
<th>Select</th> <th>Select</th>
<th>Quantity</th> <th>Quantity</th>
<th>Min Price</th> <th>Min Price</th>
<th>Order Placed</th> <th>Order placed</th>
</tr> </tr>
</thead> </thead>
<tbody data-type="sell"></tbody> <tbody data-type="sell"></tbody>
@ -360,6 +402,19 @@
</fieldset> </fieldset>
</div> </div>
</div> </div>
<template id="net_balance_template">
<span class="available-balance"></span>
</template>
<template id="locked_balance_template">
<div>
<span class="label">Locked</span>
<span class="locked-balance"></span>
</div>
<div>
<span class="label">Available</span>
<span class="available-balance"></span>
</div>
</template>
<script id="ui_utils"> <script id="ui_utils">
// Global variables // Global variables
const domRefs = {}; const domRefs = {};
@ -503,6 +558,34 @@
}) })
} }
// displays a popup for asking user input. Use this instead of JS prompt
async function getPromptInput(title, message = '', options = {}) {
const { isPassword = true, cancelText = 'Cancel', confirmText = 'OK' } = options
showPopup('prompt_popup', true)
getRef('prompt_title').textContent = title;
let input = getRef('prompt_input');
input.setAttribute("placeholder", message)
let buttons = getRef('prompt_popup').querySelectorAll("sm-button");
if (isPassword)
input.setAttribute("type", "text")
else
input.setAttribute("type", "password")
input.focusIn()
buttons[0].textContent = cancelText;
buttons[1].textContent = confirmText;
return new Promise((resolve, reject) => {
buttons[0].onclick = () => {
hidePopup()
return;
}
buttons[1].onclick = () => {
let value = input.value;
hidePopup()
resolve(value)
}
})
}
//Function for displaying toast notifications. pass in error for mode param if you want to show an error. //Function for displaying toast notifications. pass in error for mode param if you want to show an error.
function notify(message, mode, options = {}) { function notify(message, mode, options = {}) {
const { pinned = false, sound = false } = options const { pinned = false, sound = false } = options
@ -742,23 +825,23 @@
} }
</script> </script>
<script> <script>
var user_id; //container for user ID and proxy private-key let user_id; //container for user ID and proxy private-key
const proxy = { const proxy = {
private: null, private: null,
public: null, public: null,
lock() { async lock() {
if (!this.private) if (!this.private)
throw "No proxy key found!"; throw "No proxy key found!";
let pwd = prompt("Enter password: "); let pwd = await getPromptInput("Enter password", '', { isPassword: true });
if (!pwd) if (!pwd)
alert("Password cannot be empty"); notify("Password cannot be empty", 'error');
else if (pwd.length < 4) else if (pwd.length < 4)
alert("Password minimum length is 4"); notify("Password minimum length is 4", 'error');
else { else {
let tmp = Crypto.AES.encrypt(this.private, pwd); let tmp = Crypto.AES.encrypt(this.private, pwd);
localStorage.setItem("proxy_secret", "?" + tmp); localStorage.setItem("proxy_secret", "?" + tmp);
alert("Successfully locked with Password"); notify("Successfully locked with Password", 'success');
} }
}, },
clear() { clear() {
@ -777,17 +860,18 @@
try { try {
let tmp = localStorage.getItem("proxy_secret"); let tmp = localStorage.getItem("proxy_secret");
if (typeof tmp === "string" && tmp.startsWith("?")) { if (typeof tmp === "string" && tmp.startsWith("?")) {
let pwd = prompt("Enter password: "); getPromptInput("Enter password", '', { isPassword: true }).then(pwd => {
if (!pwd) if (!pwd)
throw "Password Required for making transactions"; throw "Password Required for making transactions";
else { else {
try { try {
tmp = Crypto.AES.decrypt(tmp.substring(1), pwd); tmp = Crypto.AES.decrypt(tmp.substring(1), pwd);
} catch (error) { } catch (error) {
throw "Incorrect Password! Password Required for making transactions"; throw "Incorrect Password! Password Required for making transactions";
} }
} }
});
} }
this.private = tmp; this.private = tmp;
this.public = floCrypto.getPubKeyHex(tmp); this.public = floCrypto.getPubKeyHex(tmp);
@ -865,6 +949,19 @@
account(); account();
} }
function showBalance(containerId, availableBalance = 0, lockedBalance = 0) {
getRef(containerId).innerHTML = ''
const templateToClone = lockedBalance ? 'locked_balance_template' : 'net_balance_template';
const card = getRef(templateToClone).content.cloneNode(true).firstElementChild
card.querySelector('.available-balance').textContent = availableBalance
if (lockedBalance) {
card.querySelector('.locked-balance').textContent = lockedBalance
}
getRef(containerId).className = lockedBalance ? 'grid balance-card__amount-wrapper' : ''
getRef(containerId).parentNode.className = `balance-card ${lockedBalance ? 'is-locked' : ''}`
getRef(containerId).append(card)
}
function account() { function account() {
getAccount().then(acc => { getAccount().then(acc => {
console.debug(acc); console.debug(acc);
@ -878,13 +975,14 @@
let flo_locked = acc.sellOrders.reduce((a, x) => a + x.quantity, 0); let flo_locked = acc.sellOrders.reduce((a, x) => a + x.quantity, 0);
let flo_net = flo_total - flo_locked; let flo_net = flo_total - flo_locked;
console.debug("FLO", flo_total, flo_locked, flo_net); console.debug("FLO", flo_total, flo_locked, flo_net);
document.getElementById("flo_bal").textContent = flo_net + "(+" + flo_locked + ")";
showBalance("flo_balance", flo_net, flo_locked)
//Rupee Balance //Rupee Balance
let rupee_total = acc.rupee_total; let rupee_total = acc.rupee_total;
let rupee_locked = acc.buyOrders.reduce((a, x) => a + x.quantity * x.maxPrice, 0); let rupee_locked = acc.buyOrders.reduce((a, x) => a + x.quantity * x.maxPrice, 0);
let rupee_net = rupee_total - rupee_locked; let rupee_net = rupee_total - rupee_locked;
console.debug("RUPEE", rupee_total, rupee_locked, rupee_net); console.debug("RUPEE", rupee_total, rupee_locked, rupee_net);
document.getElementById("rupee_bal").textContent = rupee_net + "(+" + rupee_locked + ")"; showBalance("rupee_balance", rupee_net, rupee_locked)
//My buy orders //My buy orders
let container = document.getElementById("my-buy-orders").getElementsByTagName("tbody")[0]; let container = document.getElementById("my-buy-orders").getElementsByTagName("tbody")[0];
container.innerHTML = ''; container.innerHTML = '';
@ -948,16 +1046,17 @@
const UI_evt = {}; const UI_evt = {};
UI_evt.signup = function () { UI_evt.signup = async function () {
let sid = document.forms['login-form']['sid'].value; let sid = document.forms['login-form']['sid'].value;
let privKey = prompt("Enter Private Key of floID to register: "); let privKey = await getPromptInput("Register private key", "Enter the private key of floID you want to register", { isPassword: true });
signUp(privKey, sid).then(result => { if (privKey) {
console.info(result); signUp(privKey, sid).then(result => {
alert("Account registered!") console.info(result);
}).catch(error => { notify("Account registered!", 'success')
console.error(error) }).catch(error => {
alert(error); notify(error, 'error');
}); });
}
}; };
UI_evt.logout = function () { UI_evt.logout = function () {
@ -981,83 +1080,40 @@
}).catch(error => console.error(error)); }).catch(error => console.error(error));
}; };
UI_evt.sell = function () {
let formInputs = document.forms['sell-form'];
sell(parseFloat(formInputs["quantity"].value), parseFloat(formInputs["min-price"].value), proxy.secret)
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(_ => formInputs.reset());
};
UI_evt.buy = function () {
let formInputs = document.forms['buy-form'];
buy(parseFloat(formInputs["quantity"].value), parseFloat(formInputs["max-price"].value), proxy.secret)
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(_ => formInputs.reset());
};
UI_evt.cancelOrders = function () { UI_evt.cancelOrders = function () {
let container = document.getElementById('my-orders'); let container = document.getElementById('my-orders');
let cancel = []; let cancel = [];
let inputs = container.getElementsByTagName('input') let inputs = container.querySelectorAll('input[checked]')
for (let i = 0; i < inputs.length; i++) { for (let i = 0; i < inputs.length; i++) {
if (inputs[i].type === "checkbox" && inputs[i].checked) { let row = inputs[i].parentElement.parentElement
let row = inputs[i].parentElement.parentElement let id = row.dataset['id'];
let id = row.dataset['id']; let type = row.parentElement.dataset['type'];
let type = row.parentElement.dataset['type']; cancel.push([type, id]);
cancel.push([type, id]);
}
} }
cancel.forEach(o => cancelOrder(o[0], o[1], proxy.secret) cancel.forEach(o => cancelOrder(o[0], o[1], proxy.secret)
.then(result => console.log(result)) .then(result => console.log(result))
.catch(error => console.error(o, error))) .catch(error => console.error(o, error)))
}; };
UI_evt.depositFLO = function () {
let formInputs = document.forms['deposit-withdraw-form'];
let privKey = prompt("Enter private key");
depositFLO(parseFloat(formInputs["quantity"].value), user_id, privKey, proxy.secret)
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(_ => formInputs.reset());
}
UI_evt.depositRupee = function () {
let formInputs = document.forms['deposit-withdraw-form'];
let privKey = prompt("Enter private key");
depositRupee(parseFloat(formInputs["quantity"].value), user_id, privKey, proxy.secret)
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(_ => formInputs.reset());
}
UI_evt.withdrawFLO = function () {
let formInputs = document.forms['deposit-withdraw-form'];
withdrawFLO(parseFloat(formInputs["quantity"].value), proxy.secret)
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(_ => formInputs.reset());
}
UI_evt.withdrawRupee = function () {
let formInputs = document.forms['deposit-withdraw-form'];
withdrawRupee(parseFloat(formInputs["quantity"].value), proxy.secret)
.then(result => console.log(result))
.catch(error => console.error(error))
.finally(_ => formInputs.reset());
}
refresh(true); refresh(true);
</script> </script>
<script> <script>
function showProcess(id) {
getRef(id).children[0].classList.add('clip')
getRef(id).append(document.createElement('sm-spinner'))
}
function hideProcess(id) {
getRef(id).children[0].classList.remove('clip')
getRef(id).querySelector('sm-spinner')?.remove()
}
let tradeType = 'buy'
getRef('trade_type_selector').addEventListener('change', e => { getRef('trade_type_selector').addEventListener('change', e => {
getRef('get_price').setAttribute('placeholder', e.detail.value === 'buy' ? 'Max price' : 'Min price') tradeType = e.detail.value
getRef('trade_button').textContent = e.detail.value getRef('get_price').setAttribute('placeholder', tradeType === 'buy' ? 'Max price' : 'Min price')
getRef('quantity_type').textContent = e.detail.value === 'buy' ? `Rupee` : `FLO` getRef('trade_button').textContent = tradeType
getRef('quantity_type').textContent = tradeType === 'buy' ? `Rupee` : `FLO`
}) })
async function tradeFlo() { async function tradeFlo() {
const tradeType = getRef('trade_type_selector').value
const quantity = parseFloat(getRef('get_quantity').value) const quantity = parseFloat(getRef('get_quantity').value)
const price = parseFloat(getRef('get_price').value) const price = parseFloat(getRef('get_price').value)
try { try {
@ -1075,6 +1131,77 @@
getRef('trade_form').reset() getRef('trade_form').reset()
} }
} }
const balance = {
flo: 5.1245,
rupee: 457.2
}
const rate = {
flo: 1.487
}
getRef('quantity_selector').addEventListener('click', e => {
// Get latest balance and exchange rate
if (e.target.closest('button')) {
const target = e.target.closest('button')
const fraction = parseInt(target.value) / 100
if (tradeType === 'buy') {
getRef('get_quantity').value = parseFloat(((balance.rupee * fraction) / rate.flo).toFixed(8))
} else {
getRef('get_quantity').value = parseFloat((balance.flo * fraction).toFixed(8))
}
}
})
getRef('wallet_actions').addEventListener('click', e => {
if (e.target.closest('.button')) {
const target = e.target.closest('.button')
showPopup('wallet_popup')
const type = target.value
const asset = getRef('wallet_asset_selector').value
getRef('wallet_popup__cta').textContent = `${type}`
getRef('wallet_popup__cta').setAttribute('value', type)
getRef('wallet_popup__title').textContent = `${type} ${asset}`
if (type === 'withdraw') {
getRef('get_private_key').classList.add('hide-completely')
getRef('get_private_key').removeAttribute('required')
getRef('get_private_key').removeAttribute('hiderequired')
} else {
getRef('get_private_key').setAttribute('required', '')
getRef('get_private_key').setAttribute('hiderequired', '')
getRef('get_private_key').classList.remove('hide-completely')
}
getRef('wallet_form').elementsChanged()
}
})
getRef('wallet_popup__cta').addEventListener('click', async e => {
const asset = getRef('wallet_asset_selector').value
const type = e.target.getAttribute('value')
const quantity = parseFloat(getRef('get_quantity').value)
console.log(type, asset)
try {
showProcess('wallet_popup__cta_wrapper')
if (type === 'deposit') {
const privKey = getRef('get_private_key').value;
if (asset === 'FLO') {
await depositFLO(quantity, user_id, privKey, proxy.secret)
} else {
await depositRupee(quantity, user_id, privKey, proxy.secret)
}
notify(`Deposited ${asset} successfully`)
} else {
if (asset === 'FLO') {
await withdrawFLO(quantity, proxy.secret)
} else {
await withdrawRupee(quantity, proxy.secret)
}
notify(`Withdrawn ${asset} successfully`)
}
}
catch (err) {
notify(err, 'error')
}
finally {
hideProcess('wallet_popup__cta_wrapper')
}
})
</script> </script>
</body> </body>