1460 lines
72 KiB
HTML
1460 lines
72 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>RanchiMall market</title>
|
|
|
|
<script src="components.js" defer></script>
|
|
<link rel="stylesheet" href="css/main.min.css">
|
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
<link href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap" rel="stylesheet">
|
|
<script id="floGlobals">
|
|
/* Constants for FLO blockchain operations !!Make sure to add this at beginning!! */
|
|
const floGlobals = {
|
|
|
|
//Required for all
|
|
blockchain: "FLO",
|
|
|
|
//Required for blockchain API operators
|
|
apiURL: {
|
|
FLO: ['https://livenet.flocha.in/', 'https://flosight.duckdns.org/'],
|
|
FLO_TEST: ['https://testnet-flosight.duckdns.org/', 'https://testnet.flocha.in/']
|
|
},
|
|
tokenURL: "https://ranchimallflo.duckdns.org/",
|
|
token: "rupee",
|
|
adminID: "FKAEdnPfjXLHSYwrXQu377ugN4tXU7VGdf",
|
|
sendAmt: 0.001,
|
|
fee: 0.0005,
|
|
}
|
|
</script>
|
|
<script src="https://sairajzero.github.io/Standard_Operations/cdn/floCrypto.js"></script>
|
|
<script src="https://github.com/sairajzero/Standard_Operations/releases/download/test/floBlockchainAPI.js"></script>
|
|
<script src="fn.js"></script>
|
|
</head>
|
|
|
|
<body class="hide-completely">
|
|
<sm-notifications id="notification_drawer"></sm-notifications>
|
|
<audio id="notification_sound">
|
|
<source src="https://rmservices.duckdns.org/files/notification-sound.mp3" type="audio/mpeg">
|
|
<source src="https://rmservices.duckdns.org/files/notification-sound.ogg" type="audio/ogg">
|
|
</audio>
|
|
<sm-popup id="confirmation_popup">
|
|
<h4 id="confirm_title"></h4>
|
|
<p id="confirm_message"></p>
|
|
<div class="flex align-center">
|
|
<sm-button variant="no-outline" class="cancel-btn">Cancel</sm-button>
|
|
<sm-button variant="no-outline" class="submit-btn">OK</sm-button>
|
|
</div>
|
|
</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">
|
|
<header class="flex space-between">
|
|
<div class="logo">
|
|
<svg class="main-logo" viewBox="0 0 27.25 32">
|
|
<title>RanchiMall</title>
|
|
<path
|
|
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" />
|
|
</svg>
|
|
<div class="grid">
|
|
<h4>RanchiMall market</h4>
|
|
</div>
|
|
</div>
|
|
<div class="flex">
|
|
<!-- <a href="#/sign_up" class="button">Sign up</a> -->
|
|
<a href="#/sign_in" class="button button--primary">Sign in</a>
|
|
</div>
|
|
</header>
|
|
<div class="grid justify-center">
|
|
<h1 class="h1">Decentralized banking <br> made simple</h1>
|
|
<p>*Interest rates are re-calculated with each new transaction done on network</p>
|
|
<div class="interest-container">
|
|
|
|
</div>
|
|
</div>
|
|
</article>
|
|
<article id="sign_in" class="page page-layout hide-completely">
|
|
<header>
|
|
<div class="logo">
|
|
<svg class="main-logo" viewBox="0 0 27.25 32">
|
|
<title>RanchiMall</title>
|
|
<path
|
|
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" />
|
|
</svg>
|
|
<div class="grid">
|
|
<h4>RanchiMall market</h4>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
<section>
|
|
<h1 class="h2">Sign In</h1>
|
|
<p>Welcome back, glad to see you again</p>
|
|
<sm-form>
|
|
<sm-input id="private_key_field" type="password" placeholder="FLO private key"
|
|
error-text="Private key is invalid" data-private-key required></sm-input>
|
|
<sm-button id="sign_in_button" variant="primary" disabled>Sign In</sm-button>
|
|
</sm-form>
|
|
<p>
|
|
New here? <a href="#/sign_up">get your FLO login credentials</a>
|
|
</p>
|
|
</section>
|
|
</article>
|
|
<article id="sign_up" class="page page-layout hide-completely">
|
|
<header>
|
|
<div class="logo">
|
|
<svg class="main-logo" viewBox="0 0 27.25 32">
|
|
<title>RanchiMall</title>
|
|
<path
|
|
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" />
|
|
</svg>
|
|
<div class="grid">
|
|
<h4>RanchiMall market</h4>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
<section class="grid">
|
|
<h1 class="h2">FLO credentials</h1>
|
|
<p>Get your FLO credentials to use RanchiMall market and all RanchiMall FLO apps. </p>
|
|
<div class="grid gap-1-5 card">
|
|
<div class="grid gap-0-5">
|
|
<h5>FLO ID</h5>
|
|
<sm-copy id="generated_flo_id"></sm-copy>
|
|
</div>
|
|
<div class="grid gap-0-5">
|
|
<h5>Private key</h5>
|
|
<sm-copy id="generated_private_key"></sm-copy>
|
|
</div>
|
|
</div>
|
|
<sm-button id="sign_up_button" variant="primary">Sign in with these credentials</sm-button>
|
|
<strong class="warning">
|
|
Keep your private key secure and don't share with anyone.
|
|
Once lost there is no way to recover private key.
|
|
</strong>
|
|
</section>
|
|
</article>
|
|
<article id="loading" class="page page-layout hide-completely">
|
|
<sm-spinner></sm-spinner>
|
|
<h4>Loading RanchiMall Market</h4>
|
|
</article>
|
|
<article id="home" class="page">
|
|
<section>
|
|
<header id="main_header">
|
|
<div class="logo">
|
|
<svg class="main-logo" viewBox="0 0 27.25 32">
|
|
<title>RanchiMall</title>
|
|
<path
|
|
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" />
|
|
</svg>
|
|
<div class="grid">
|
|
<h4>RanchiMall Market</h4>
|
|
</div>
|
|
</div>
|
|
<theme-toggle></theme-toggle>
|
|
</header>
|
|
<sm-form id="trade_form">
|
|
<div class="flex space-between align-center">
|
|
<h4>Trade FLO</h4>
|
|
<strip-select id="trade_type_selector" class="tab">
|
|
<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 id="orders_section__header" class="flex">
|
|
<div id="orders_section__header--primary" class="flex w-100 align-center space-between">
|
|
<sm-tab-header target="orders_tab">
|
|
<sm-tab>My orders</sm-tab>
|
|
<sm-tab>Market orders</sm-tab>
|
|
</sm-tab-header>
|
|
<sm-select id="orders_scope_selector" class="tab" align-select="right">
|
|
<sm-option value="active" selected>Open</sm-option>
|
|
<sm-option value="completed">Completed</sm-option>
|
|
</sm-select>
|
|
</div>
|
|
<div id="orders_section__header--secondary"
|
|
class="flex w-100 align-center space-between hide-completely">
|
|
<button class="" onclick="clearSelection()" title="Clear all selection">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon button__icon--left" height="24px"
|
|
viewBox="0 0 24 24" width="24px">
|
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
|
<path
|
|
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z" />
|
|
</svg>
|
|
<span id="selected_orders"></span>
|
|
</button>
|
|
<div class="options">
|
|
<button class="button" title="Cancel selected orders" onclick="cancelAll()">
|
|
Cancel selected
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<sm-tab-panels id="orders_tab">
|
|
<div class="table">
|
|
<ul id="my_order_list"></ul>
|
|
</div>
|
|
<div class="table">
|
|
<ul id="market_order_list">
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
sdgkmsdg <br>
|
|
</ul>
|
|
</div>
|
|
</sm-tab-panels>
|
|
</section>
|
|
<section id="user_section" class="grid">
|
|
<h4 class="flex align-center user_section__header">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon button__icon--left" height="24px"
|
|
viewBox="0 0 24 24" width="24px">
|
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
|
<path
|
|
d="M21 7.28V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-2.28c.59-.35 1-.98 1-1.72V9c0-.74-.41-1.37-1-1.72zM20 9v6h-7V9h7zM5 19V5h14v2h-6c-1.1 0-2 .9-2 2v6c0 1.1.9 2 2 2h6v2H5z" />
|
|
<circle cx="16" cy="12" r="1.5" />
|
|
</svg>
|
|
My wallet
|
|
</h4>
|
|
<div id="wallet_actions">
|
|
<p class="label">Select asset</p>
|
|
<sm-select id="wallet_asset_selector">
|
|
<sm-option value="FLO">FLO</sm-option>
|
|
<sm-option value="Rupee">Rupee</sm-option>
|
|
</sm-select>
|
|
<div class="flex wallet_actions__wrapper">
|
|
<button class="button" value="deposit">
|
|
Deposit
|
|
</button>
|
|
<button class="button" value="withdraw">
|
|
Withdraw
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="grid gap-0-5">
|
|
<h4>Balance</h4>
|
|
<div class="balance-card">
|
|
<div class="balance-card__icon">
|
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
<path
|
|
d="M16.36,15.39c1.83,0,4.26-2.49,4.36-4.74-5.65-.19-4.91.47-7.28,2.39,2.19-2.4,1.42-7.79-1.43-10V6.17c2.33,1.49,2.21,5.14,0,7.15-2.23-2-2.27-5.69,0-7.15V3c-2.83,2.26-3.62,7.66-1.44,10-2.36-1.93-1.63-2.58-7.28-2.39.1,2.26,2.55,4.73,4.36,4.74,0,0-1.93.22-2.74-2.62,2.38-.37,4.29-.14,6.28,2-.79-.11-4.89,1.13-4.38,3.26.53.06,3,.3,3.58-.83-.17.18-1.25.5-1.53.05.38-1.39,2.32-2,2.32-2-1,1.82-.48,4.63.82,5.72,1.31-1.08,1.8-3.95.82-5.72,0,0,1.95.6,2.32,2-.29.46-1.36.12-1.53-.05.58,1.14,3.06.88,3.58.83.49-2.17-3.58-3.36-4.38-3.26,2-2.17,3.92-2.39,6.28-2C18.3,15.62,16.36,15.39,16.36,15.39ZM12,19.46c-.91-.79-.5-3,0-3.59C12.5,16.45,12.91,18.66,12,19.46Z" />
|
|
</svg>
|
|
</div>
|
|
<div class="balance-card__token">FLO</div>
|
|
<div id="flo_balance"></div>
|
|
</div>
|
|
<div class="balance-card">
|
|
<div class="balance-card__icon">
|
|
<svg class="icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
|
<path
|
|
d="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>
|
|
</div>
|
|
<div class="balance-card__token">Rupee</div>
|
|
<div id="rupee_balance"></div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</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">
|
|
<fieldset>
|
|
<legend>Login</legend>
|
|
<input type="password" name="priv-key" placeholder="Enter Private Key" />
|
|
<input type="text" name="sid" style="display: none;" />
|
|
<input type="button" name="login" value="login" onclick="UI_evt.login();" /><br />
|
|
<input type="checkbox" name="remember-me" checked />RememberMe <br />
|
|
<button type="button" onclick="UI_evt.signup();">Not registered? click here!</button>
|
|
</fieldset>
|
|
</form>
|
|
<div id="user-container">
|
|
<fieldset>
|
|
<legend>Profile</legend>
|
|
<span id="user_id"></span><br />
|
|
<button onclick="proxy.lock();">Add password lock</button><br />
|
|
<button onclick="UI_evt.logout();">logout</button>
|
|
<button onclick="toggle_view('my-profile');">Toggle</button>
|
|
<div id="my-profile">
|
|
<div id="my-orders">
|
|
<fieldset>
|
|
<legend>My Orders</legend>
|
|
<fieldset id="my-buy-orders">
|
|
<legend>Buying</legend>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Select</th>
|
|
<th>Quantity</th>
|
|
<th>Max Price</th>
|
|
<th>Order Placed</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody data-type="buy"></tbody>
|
|
</table>
|
|
</fieldset>
|
|
<fieldset id="my-sell-orders">
|
|
<legend>Selling</legend>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Select</th>
|
|
<th>Quantity</th>
|
|
<th>Min Price</th>
|
|
<th>Order placed</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody data-type="sell"></tbody>
|
|
</table>
|
|
</fieldset>
|
|
<button name="cancel-orders" onclick="UI_evt.cancelOrders();">Cancel Orders</button>
|
|
</fieldset>
|
|
</div>
|
|
<div id="my-transactions">
|
|
<fieldset>
|
|
<legend>My Transactions</legend>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Sold/Brought</th>
|
|
<th>To/From</th>
|
|
<th>Quantity</th>
|
|
<th>Unit Value</th>
|
|
<th>Time</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
</div>
|
|
</fieldset>
|
|
</div>
|
|
<button onclick="toggle_view('all-container');">Toggle All</button>
|
|
<button onclick="refresh();">Refresh</button>
|
|
<div id="all-container">
|
|
<div id="buy-orders">
|
|
<fieldset>
|
|
<legend>BuyOrders</legend>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Buyer</th>
|
|
<th>Quantity</th>
|
|
<th>Max Price</th>
|
|
<th>Order Placed</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
<div id="sell-orders">
|
|
<fieldset>
|
|
<legend>SellOrders</legend>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Seller</th>
|
|
<th>Quantity</th>
|
|
<th>Min Price</th>
|
|
<th>Order Placed</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</fieldset>
|
|
</div>
|
|
<div id="transactions">
|
|
<fieldset>
|
|
<legend>Transactions</legend>
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Seller</th>
|
|
<th>Buyer</th>
|
|
<th>Quantity</th>
|
|
<th>Unit Value</th>
|
|
<th>Time</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody></tbody>
|
|
</table>
|
|
</fieldset>
|
|
</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>
|
|
<template id="order_template">
|
|
<li class="table__row order-card">
|
|
<sm-checkbox></sm-checkbox>
|
|
<div class="grid">
|
|
<div class="order-card__type capitalize"></div>
|
|
<div class="order-card__quantity"></div>
|
|
</div>
|
|
<div class="grid">
|
|
<span class="label order-card__price-type">Unit price</span>
|
|
<div class="order-card__price"></div>
|
|
</div>
|
|
<time class="order-card__time"></time>
|
|
<button class="cancel-order" title="Cancel this order">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon" height="24px" viewBox="0 0 24 24" width="24px">
|
|
<path d="M0 0h24v24H0V0z" fill="none" />
|
|
<path
|
|
d="M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z" />
|
|
</svg>
|
|
<span>Cancel</span>
|
|
</button>
|
|
</li>
|
|
</template>
|
|
<script id="ui_utils">
|
|
// Global variables
|
|
const domRefs = {};
|
|
let timerId;
|
|
const currentYear = new Date().getFullYear();
|
|
|
|
//Checks for internet connection status
|
|
if (!navigator.onLine)
|
|
notify(
|
|
"There seems to be a problem connecting to the internet, Please check you internet connection.",
|
|
"error",
|
|
{ sound: true }
|
|
);
|
|
window.addEventListener("offline", () => {
|
|
notify(
|
|
"There seems to be a problem connecting to the internet, Please check you internet connection.",
|
|
"error",
|
|
{ pinned: true, sound: true }
|
|
);
|
|
});
|
|
window.addEventListener("online", () => {
|
|
getRef("notification_drawer").clearAll();
|
|
notify("We are back online.", "success");
|
|
});
|
|
|
|
// Use instead of document.getElementById
|
|
function getRef(elementId) {
|
|
if (!domRefs.hasOwnProperty(elementId)) {
|
|
domRefs[elementId] = {
|
|
count: 1,
|
|
ref: null,
|
|
};
|
|
return document.getElementById(elementId);
|
|
} else {
|
|
if (domRefs[elementId].count < 3) {
|
|
domRefs[elementId].count = domRefs[elementId].count + 1;
|
|
return document.getElementById(elementId);
|
|
} else {
|
|
if (!domRefs[elementId].ref)
|
|
domRefs[elementId].ref = document.getElementById(elementId);
|
|
return domRefs[elementId].ref;
|
|
}
|
|
}
|
|
}
|
|
|
|
// returns dom with specified element
|
|
function createElement(tagName, options) {
|
|
const { className, textContent, innerHTML, attributes = {} } = options
|
|
const elem = document.createElement(tagName)
|
|
for (let attribute in attributes) {
|
|
elem.setAttribute(attribute, attributes[attribute])
|
|
}
|
|
if (className)
|
|
elem.className = className
|
|
if (textContent)
|
|
elem.textContent = textContent
|
|
if (innerHTML)
|
|
elem.innerHTML = innerHTML
|
|
return elem
|
|
}
|
|
|
|
// Use when a function needs to be executed after user finishes changes
|
|
const debounce = (callback, wait) => {
|
|
let timeoutId = null;
|
|
return (...args) => {
|
|
window.clearTimeout(timeoutId);
|
|
timeoutId = window.setTimeout(() => {
|
|
callback.apply(null, args);
|
|
}, wait);
|
|
};
|
|
}
|
|
|
|
// Limits the rate of function execution
|
|
function throttle(func, delay) {
|
|
// If setTimeout is already scheduled, no need to do anything
|
|
if (timerId) {
|
|
return;
|
|
}
|
|
|
|
// Schedule a setTimeout after delay seconds
|
|
timerId = setTimeout(function () {
|
|
func();
|
|
|
|
// Once setTimeout function execution is finished, timerId = undefined so that in
|
|
// the next scroll event function execution can be scheduled by the setTimeout
|
|
timerId = undefined;
|
|
}, delay);
|
|
}
|
|
|
|
class Stack {
|
|
constructor() {
|
|
this.items = [];
|
|
}
|
|
push(element) {
|
|
this.items.push(element);
|
|
}
|
|
pop() {
|
|
if (this.items.length == 0)
|
|
return "Underflow";
|
|
return this.items.pop();
|
|
}
|
|
peek() {
|
|
return this.items[this.items.length - 1];
|
|
}
|
|
}
|
|
let popupStack = new Stack()
|
|
let zIndex = 10
|
|
// function required for popups or modals to appear
|
|
function showPopup(popupId, pinned) {
|
|
zIndex++
|
|
getRef(popupId).setAttribute('style', `z-index: ${zIndex}`)
|
|
popupStack = getRef(popupId).show({ pinned, popupStack })
|
|
return getRef(popupId);
|
|
}
|
|
|
|
// hides the popup or modal
|
|
function hidePopup() {
|
|
if (popupStack.peek() === undefined)
|
|
return;
|
|
popupStack.peek().popup.hide()
|
|
}
|
|
|
|
// displays a popup for asking permission. Use this instead of JS confirm
|
|
const getConfirmation = (title, message, cancelText = 'Cancel', confirmText = 'OK') => {
|
|
return new Promise(resolve => {
|
|
showPopup('confirmation_popup', true)
|
|
getRef('confirm_title').textContent = title;
|
|
getRef('confirm_message').textContent = message;
|
|
let cancelButton = getRef('confirmation_popup').children[2].children[0],
|
|
submitButton = getRef('confirmation_popup').children[2].children[1]
|
|
submitButton.textContent = confirmText
|
|
cancelButton.textContent = cancelText
|
|
submitButton.onclick = () => {
|
|
hidePopup()
|
|
resolve(true);
|
|
}
|
|
cancelButton.onclick = () => {
|
|
hidePopup()
|
|
resolve(false);
|
|
}
|
|
})
|
|
}
|
|
|
|
// 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 notify(message, mode, options = {}) {
|
|
const { pinned = false, sound = false } = options
|
|
let icon
|
|
switch (mode) {
|
|
case 'success':
|
|
icon = `<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>`
|
|
break;
|
|
case 'error':
|
|
icon = `<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 22C6.477 22 2 17.523 2 12S6.477 2 12 2s10 4.477 10 10-4.477 10-10 10zm-1-7v2h2v-2h-2zm0-8v6h2V7h-2z"/></svg>`
|
|
break;
|
|
}
|
|
getRef("notification_drawer").push(message, { pinned, icon });
|
|
if (navigator.onLine && sound) {
|
|
getRef("notification_sound").currentTime = 0;
|
|
getRef("notification_sound").play();
|
|
}
|
|
if (mode === 'error') {
|
|
console.error(message)
|
|
}
|
|
}
|
|
|
|
function getFormattedTime(time, relative) {
|
|
try {
|
|
if (String(time).indexOf('_'))
|
|
time = String(time).split('_')[0]
|
|
const intTime = parseInt(time)
|
|
if (String(intTime).length < 13)
|
|
time *= 1000
|
|
let timeFrag = new Date(intTime).toString().split(' '),
|
|
day = timeFrag[0],
|
|
month = timeFrag[1],
|
|
date = timeFrag[2],
|
|
year = timeFrag[3],
|
|
minutes = new Date(intTime).getMinutes(),
|
|
hours = new Date(intTime).getHours(),
|
|
currentTime = new Date().toString().split(' ')
|
|
|
|
minutes = minutes < 10 ? `0${minutes}` : minutes
|
|
let finalHours = ``;
|
|
if (hours > 12)
|
|
finalHours = `${hours - 12}:${minutes}`
|
|
else if (hours === 0)
|
|
finalHours = `12:${minutes}`
|
|
else
|
|
finalHours = `${hours}:${minutes}`
|
|
|
|
finalHours = hours >= 12 ? `${finalHours} PM` : `${finalHours} AM`
|
|
if (relative) {
|
|
if (year == currentYear) {
|
|
if (currentTime[1] === month) {
|
|
const dateDiff = (parseInt(currentTime[2]) - parseInt(date))
|
|
if (dateDiff === 0)
|
|
return `${finalHours}`;
|
|
else if (dateDiff === 1)
|
|
return `Yesterday`;
|
|
else if (dateDiff > 1 && dateDiff < 8)
|
|
return currentTime[0];
|
|
else
|
|
return ` ${date} ${month}`;
|
|
}
|
|
else
|
|
return ` ${date} ${month}`;
|
|
}
|
|
else
|
|
return `${month} ${year}`;
|
|
}
|
|
else
|
|
return `${finalHours}, ${month} ${date} ${year}`;
|
|
} catch (e) {
|
|
console.error(e);
|
|
return time;
|
|
}
|
|
}
|
|
|
|
window.addEventListener('hashchange', e => showPage(window.location.hash))
|
|
window.addEventListener("load", () => {
|
|
document.body.classList.remove('hide-completely')
|
|
document.querySelectorAll('sm-input[data-private-key]').forEach(input => input.customValidation = floCrypto.getPubKeyHex)
|
|
document.addEventListener('keyup', (e) => {
|
|
if (e.code === 'Escape') {
|
|
hidePopup()
|
|
}
|
|
})
|
|
document.addEventListener('copy', () => {
|
|
notify('copied', 'success')
|
|
})
|
|
});
|
|
|
|
const pagesData = {
|
|
openedPages: [],
|
|
params: {}
|
|
}
|
|
|
|
async function showPage(targetPage, options = {}) {
|
|
const { firstLoad, hashChange } = options
|
|
let pageId
|
|
let subPageId
|
|
let searchParams
|
|
let params
|
|
if (targetPage === '') {
|
|
if (typeof myFloID === "undefined") {
|
|
pageId = 'landing'
|
|
} else {
|
|
pageId = 'home'
|
|
}
|
|
} else {
|
|
if (targetPage.includes('/')) {
|
|
if (targetPage.includes('?')) {
|
|
const splitAddress = targetPage.split('?')
|
|
searchParams = splitAddress.pop()
|
|
const pages = splitAddress.pop().split('/')
|
|
pageId = pages[1]
|
|
subPageId = pages[2]
|
|
} else {
|
|
const pages = targetPage.split('/')
|
|
pageId = pages[1]
|
|
subPageId = pages[2]
|
|
}
|
|
} else {
|
|
pageId = targetPage
|
|
}
|
|
}
|
|
if (typeof myFloID === "undefined" && !(['sign_up', 'sign_in', 'loading', 'landing'].includes(pageId))) return
|
|
if (searchParams) {
|
|
const urlSearchParams = new URLSearchParams('?' + searchParams);
|
|
params = Object.fromEntries(urlSearchParams.entries());
|
|
pagesData.params = params
|
|
}
|
|
if (pagesData.lastPage !== pageId) {
|
|
switch (pageId) {
|
|
case 'sign_in':
|
|
setTimeout(() => {
|
|
getRef('private_key_field').focusIn()
|
|
}, 0);
|
|
break;
|
|
case 'sign_up':
|
|
const { floID, privKey } = floCrypto.generateNewID()
|
|
getRef('generated_flo_id').value = floID
|
|
getRef('generated_private_key').value = privKey
|
|
break;
|
|
}
|
|
document.querySelector('.page:not(.hide-completely)')?.classList.add('hide-completely')
|
|
getRef(pageId)?.classList.remove('hide-completely')
|
|
getRef(pageId)?.animate([
|
|
{
|
|
opacity: 0,
|
|
},
|
|
{
|
|
opacity: 1,
|
|
},
|
|
],
|
|
{
|
|
duration: 300,
|
|
easing: 'ease'
|
|
})
|
|
}
|
|
pagesData.lastPage = pageId
|
|
if (!pagesData.openedPages.includes(pageId)) {
|
|
pagesData.openedPages.push(pageId)
|
|
}
|
|
}
|
|
// class based lazy loading
|
|
class LazyLoader {
|
|
constructor(container, elementsToRender, renderFn, options = {}) {
|
|
const { batchSize = 10 } = options
|
|
|
|
this.elementsToRender = elementsToRender
|
|
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
|
this.renderFn = renderFn
|
|
this.intersectionObserver
|
|
|
|
this.batchSize = batchSize
|
|
|
|
this.lazyContainer = document.querySelector(container)
|
|
|
|
this.update = this.update.bind(this)
|
|
this.render = this.render.bind(this)
|
|
this.init = this.init.bind(this)
|
|
this.clear = this.clear.bind(this)
|
|
}
|
|
init() {
|
|
this.intersectionObserver = new IntersectionObserver((entries, observer) => {
|
|
entries.forEach(entry => {
|
|
if (entry.isIntersecting) {
|
|
observer.disconnect()
|
|
this.render({ lazyLoad: true })
|
|
}
|
|
})
|
|
}, {
|
|
threshold: 0.3
|
|
})
|
|
this.mutationObserver = new MutationObserver(mutationList => {
|
|
mutationList.forEach(mutation => {
|
|
if (mutation.type === 'childList') {
|
|
if (mutation.addedNodes.length) {
|
|
this.intersectionObserver.observe(this.lazyContainer.lastElementChild)
|
|
}
|
|
}
|
|
})
|
|
})
|
|
this.mutationObserver.observe(this.lazyContainer, {
|
|
childList: true,
|
|
})
|
|
this.render()
|
|
}
|
|
update(elementsToRender) {
|
|
this.arrayOfElements = (typeof elementsToRender === 'function') ? this.elementsToRender() : elementsToRender || []
|
|
this.render()
|
|
}
|
|
render(options = {}) {
|
|
let { lazyLoad = false } = options
|
|
const frag = document.createDocumentFragment();
|
|
if (lazyLoad) {
|
|
this.updateStartIndex = this.updateEndIndex
|
|
this.updateEndIndex = this.arrayOfElements.length > this.updateEndIndex + this.batchSize ? this.updateEndIndex + this.batchSize : this.arrayOfElements.length
|
|
} else {
|
|
this.intersectionObserver.disconnect()
|
|
this.lazyContainer.innerHTML = ``;
|
|
this.updateStartIndex = 0
|
|
this.updateEndIndex = this.arrayOfElements.length > this.batchSize ? this.batchSize : this.arrayOfElements.length
|
|
}
|
|
for (let index = this.updateStartIndex; index < this.updateEndIndex; index++) {
|
|
frag.append(this.renderFn(this.arrayOfElements[index]))
|
|
}
|
|
this.lazyContainer.append(frag)
|
|
}
|
|
clear() {
|
|
this.intersectionObserver.disconnect()
|
|
this.mutationObserver.disconnect()
|
|
this.lazyContainer.innerHTML = ``;
|
|
}
|
|
reset() {
|
|
this.arrayOfElements = (typeof this.elementsToRender === 'function') ? this.elementsToRender() : this.elementsToRender || []
|
|
this.render()
|
|
}
|
|
}
|
|
</script>
|
|
<script>
|
|
let user_id; //container for user ID and proxy private-key
|
|
|
|
const proxy = {
|
|
private: null,
|
|
public: null,
|
|
async lock() {
|
|
if (!this.private)
|
|
throw "No proxy key found!";
|
|
let pwd = await getPromptInput("Enter password", '', { isPassword: true });
|
|
if (!pwd)
|
|
notify("Password cannot be empty", 'error');
|
|
else if (pwd.length < 4)
|
|
notify("Password minimum length is 4", 'error');
|
|
else {
|
|
let tmp = Crypto.AES.encrypt(this.private, pwd);
|
|
localStorage.setItem("proxy_secret", "?" + tmp);
|
|
notify("Successfully locked with Password", 'success');
|
|
}
|
|
},
|
|
clear() {
|
|
localStorage.removeItem("proxy_secret");
|
|
this.private = null;
|
|
this.public = null;
|
|
},
|
|
set secret(key) {
|
|
localStorage.setItem("proxy_secret", key);
|
|
this.private = key;
|
|
this.public = floCrypto.getPubKeyHex(key);
|
|
},
|
|
get secret() {
|
|
if (this.private)
|
|
return this.private;
|
|
try {
|
|
let tmp = localStorage.getItem("proxy_secret");
|
|
if (typeof tmp === "string" && tmp.startsWith("?")) {
|
|
getPromptInput("Enter password", '', { isPassword: true }).then(pwd => {
|
|
if (!pwd)
|
|
throw "Password Required for making transactions";
|
|
else {
|
|
try {
|
|
tmp = Crypto.AES.decrypt(tmp.substring(1), pwd);
|
|
} catch (error) {
|
|
throw "Incorrect Password! Password Required for making transactions";
|
|
}
|
|
|
|
}
|
|
});
|
|
}
|
|
this.private = tmp;
|
|
this.public = floCrypto.getPubKeyHex(tmp);
|
|
return this.private;
|
|
} catch (error) {
|
|
alert(error);
|
|
console.error(error);
|
|
throw "Unable to fetch Proxy secret";
|
|
}
|
|
}
|
|
}
|
|
|
|
function toggle_view(id) {
|
|
let element = document.getElementById(id);
|
|
if (element.style.display === "none")
|
|
element.style.display = "block";
|
|
else
|
|
element.style.display = "none";
|
|
}
|
|
|
|
function list_buy() {
|
|
getBuyList().then(list => {
|
|
let container = document.getElementById("buy-orders").getElementsByTagName("tbody")[0];
|
|
container.innerHTML = '';
|
|
list.forEach(o => {
|
|
let row = container.insertRow();
|
|
row.insertCell().textContent = o.floID;
|
|
row.insertCell().textContent = o.quantity;
|
|
row.insertCell().textContent = o.maxPrice;
|
|
row.insertCell().textContent = new Date(o.time_placed);
|
|
row.dataset["id"] = o.id;
|
|
});
|
|
}).catch(error => console.error(error))
|
|
}
|
|
|
|
function list_sell() {
|
|
getSellList().then(list => {
|
|
let container = document.getElementById("sell-orders").getElementsByTagName("tbody")[0];
|
|
container.innerHTML = '';
|
|
list.forEach(o => {
|
|
let row = container.insertRow();
|
|
row.insertCell().textContent = o.floID;
|
|
row.insertCell().textContent = o.quantity;
|
|
row.insertCell().textContent = o.minPrice;
|
|
row.insertCell().textContent = new Date(o.time_placed);
|
|
row.dataset["id"] = o.id;
|
|
});
|
|
}).catch(error => console.error(error))
|
|
}
|
|
|
|
function list_txns() {
|
|
getTransactionList().then(list => {
|
|
let container = document.getElementById("transactions").getElementsByTagName("tbody")[0];
|
|
container.innerHTML = '';
|
|
list.forEach(o => {
|
|
let row = container.insertRow();
|
|
row.insertCell().textContent = o.seller;
|
|
row.insertCell().textContent = o.buyer;
|
|
row.insertCell().textContent = o.quantity;
|
|
row.insertCell().textContent = o.unitValue;
|
|
row.insertCell().textContent = new Date(o.tx_time);
|
|
});
|
|
}).catch(error => console.error(error))
|
|
}
|
|
|
|
function refresh(init = false) {
|
|
if (init)
|
|
console.info("init");
|
|
else
|
|
console.info("refresh");
|
|
list_buy();
|
|
list_sell();
|
|
list_txns();
|
|
if (init || document.getElementById('user-container').style.display === "block")
|
|
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)
|
|
}
|
|
|
|
const myBuyOrders = [
|
|
{
|
|
id: 'dfs5g16sdg1',
|
|
time_placed: generateRandomDate(),
|
|
quantity: 14.5,
|
|
maxPrice: 1.36,
|
|
},
|
|
{
|
|
id: 'f4gd1d56fg1',
|
|
time_placed: generateRandomDate(),
|
|
quantity: 78.3,
|
|
maxPrice: 1.26,
|
|
},
|
|
{
|
|
id: 's4dg5s4d1g98',
|
|
time_placed: generateRandomDate(),
|
|
quantity: 14.5,
|
|
maxPrice: 1.28,
|
|
},
|
|
]
|
|
const mySellOrders = [
|
|
{
|
|
id: 'sd8g45g419s6',
|
|
time_placed: generateRandomDate(),
|
|
quantity: 15,
|
|
minPrice: 1.16,
|
|
},
|
|
{
|
|
id: 's59d1g9ws18d',
|
|
time_placed: generateRandomDate(),
|
|
quantity: 8.3,
|
|
minPrice: 1.86,
|
|
},
|
|
{
|
|
id: 'w899e1g4d1g98',
|
|
time_placed: generateRandomDate(),
|
|
quantity: 18.5,
|
|
minPrice: 1.64,
|
|
},
|
|
]
|
|
|
|
function generateRandomDate() {
|
|
return new Date() - Math.floor(Math.random() * 10000000000);
|
|
}
|
|
|
|
function account() {
|
|
getAccount().then(acc => {
|
|
console.debug(acc);
|
|
//Element display
|
|
document.getElementById("login-form").style.display = "none";
|
|
document.getElementById('user-container').style.display = "block";
|
|
document.getElementById("user_id").textContent = acc.floID;
|
|
user_id = acc.floID;
|
|
//FLO Balance
|
|
let flo_total = acc.coins.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;
|
|
console.debug("FLO", flo_total, flo_locked, flo_net);
|
|
|
|
showBalance("flo_balance", flo_net, flo_locked)
|
|
//Rupee Balance
|
|
let rupee_total = acc.rupee_total;
|
|
let rupee_locked = acc.buyOrders.reduce((a, x) => a + x.quantity * x.maxPrice, 0);
|
|
let rupee_net = rupee_total - rupee_locked;
|
|
console.debug("RUPEE", rupee_total, rupee_locked, rupee_net);
|
|
showBalance("rupee_balance", rupee_net, rupee_locked)
|
|
//My orders
|
|
renderOpenOrders(acc.buyOrders, acc.sellOrders)
|
|
|
|
//My Transactions
|
|
container = document.getElementById("my-transactions").getElementsByTagName("tbody")[0];
|
|
container.innerHTML = '';
|
|
acc.transactions.forEach(o => {
|
|
let type, other;
|
|
if (o.seller === acc.floID) {
|
|
type = 'Sold To';
|
|
other = o.buyer === acc.floID ? 'MySelf' : o.buyer;
|
|
} else if (o.buyer === acc.floID) {
|
|
type = 'Brought From';
|
|
other = o.seller;
|
|
} else
|
|
return;
|
|
let row = container.insertRow();
|
|
row.insertCell().textContent = type;
|
|
row.insertCell().textContent = other;
|
|
row.insertCell().textContent = o.quantity;
|
|
row.insertCell().textContent = o.unitValue;
|
|
row.insertCell().textContent = new Date(o.tx_time);
|
|
});
|
|
try {
|
|
proxy.secret;
|
|
} catch (error) {
|
|
console.warn(error);
|
|
}
|
|
}).catch(error => {
|
|
if (error instanceof ResponseError) {
|
|
let response = JSON.parse(error.data)
|
|
console.log(error);
|
|
console.log(response);
|
|
document.getElementById('user-container').style.display = "none";
|
|
document.getElementById("login-form").style.display = "block";
|
|
document.forms['login-form']["sid"].value = response.sid;
|
|
proxy.clear();
|
|
} else
|
|
console.error(error);
|
|
})
|
|
};
|
|
|
|
const UI_evt = {};
|
|
|
|
UI_evt.signup = async function () {
|
|
let sid = document.forms['login-form']['sid'].value;
|
|
let privKey = await getPromptInput("Register private key", "Enter the private key of floID you want to register", { isPassword: true });
|
|
if (privKey) {
|
|
signUp(privKey, sid).then(result => {
|
|
console.info(result);
|
|
notify("Account registered!", 'success')
|
|
}).catch(error => {
|
|
notify(error, 'error');
|
|
});
|
|
}
|
|
};
|
|
|
|
UI_evt.logout = function () {
|
|
logout().then(result => {
|
|
console.warn(result);
|
|
proxy.clear();
|
|
location.reload();
|
|
}).catch(error => console.error(error));
|
|
};
|
|
|
|
UI_evt.login = function () {
|
|
let formInputs = document.forms['login-form'];
|
|
let privKey = formInputs['priv-key'].value;
|
|
let sid = formInputs['sid'].value;
|
|
let rememberMe = formInputs['remember-me'].checked;
|
|
let tmpKey = floCrypto.generateNewID();
|
|
login(privKey, tmpKey.pubKey, sid, rememberMe).then(result => {
|
|
console.log(result);
|
|
proxy.secret = tmpKey.privKey;
|
|
account();
|
|
}).catch(error => console.error(error));
|
|
};
|
|
|
|
UI_evt.cancelOrders = function () {
|
|
let container = document.getElementById('my-orders');
|
|
let cancel = [];
|
|
let inputs = container.querySelectorAll('input[checked]')
|
|
for (let i = 0; i < inputs.length; i++) {
|
|
let row = inputs[i].parentElement.parentElement
|
|
let id = row.dataset['id'];
|
|
let type = row.parentElement.dataset['type'];
|
|
cancel.push([type, id]);
|
|
}
|
|
cancel.forEach(o => cancelOrder(o[0], o[1], proxy.secret)
|
|
.then(result => console.log(result))
|
|
.catch(error => console.error(o, error)))
|
|
};
|
|
|
|
refresh(true);
|
|
</script>
|
|
<script>
|
|
const render = {
|
|
orderCard(orderDetails = {}) {
|
|
const { id, quantity, price, time, type } = orderDetails
|
|
const card = getRef('order_template').content.cloneNode(true).firstElementChild
|
|
card.dataset.id = id
|
|
card.dataset.type = type
|
|
card.querySelector('.order-card__type').textContent = type
|
|
card.querySelector('.order-card__quantity').textContent = `${quantity} FLO`
|
|
card.querySelector('.order-card__price-type').textContent = type === 'buy' ? 'Max price' : 'Min price'
|
|
card.querySelector('.order-card__price').textContent = `₹${price}`
|
|
card.querySelector('.order-card__time').textContent = getFormattedTime(time, true)
|
|
return card
|
|
}
|
|
}
|
|
|
|
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 => {
|
|
tradeType = e.detail.value
|
|
getRef('get_price').setAttribute('placeholder', tradeType === 'buy' ? 'Max price' : 'Min price')
|
|
getRef('trade_button').textContent = tradeType
|
|
getRef('quantity_type').textContent = tradeType === 'buy' ? `Rupee` : `FLO`
|
|
})
|
|
async function tradeFlo() {
|
|
const quantity = parseFloat(getRef('get_quantity').value)
|
|
const price = parseFloat(getRef('get_price').value)
|
|
try {
|
|
if (tradeType === 'buy') {
|
|
await buy(quantity, price, proxy.secret)
|
|
} else {
|
|
await sell(quantity, price, proxy.secret)
|
|
}
|
|
notify(`Placed ${tradeType} order`, 'success')
|
|
}
|
|
catch (err) {
|
|
notify(err, 'error')
|
|
}
|
|
finally {
|
|
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')
|
|
}
|
|
})
|
|
const selectedOrders = new Map()
|
|
const slideInLeft = [
|
|
{
|
|
opacity: 0,
|
|
transform: 'translateX(1.5rem)'
|
|
},
|
|
{
|
|
opacity: 1,
|
|
transform: 'translateX(0)'
|
|
}
|
|
]
|
|
const slideOutLeft = [
|
|
{
|
|
opacity: 1,
|
|
transform: 'translateX(0)'
|
|
},
|
|
{
|
|
opacity: 0,
|
|
transform: 'translateX(-1.5rem)'
|
|
},
|
|
]
|
|
const slideInRight = [
|
|
{
|
|
opacity: 0,
|
|
transform: 'translateX(-1.5rem)'
|
|
},
|
|
{
|
|
opacity: 1,
|
|
transform: 'translateX(0)'
|
|
}
|
|
]
|
|
const slideOutRight = [
|
|
{
|
|
opacity: 1,
|
|
transform: 'translateX(0)'
|
|
},
|
|
{
|
|
opacity: 0,
|
|
transform: 'translateX(1.5rem)'
|
|
},
|
|
]
|
|
getRef('my_order_list').addEventListener('change', e => {
|
|
const animOptions = {
|
|
duration: 150,
|
|
easing: 'ease',
|
|
fill: 'forwards'
|
|
}
|
|
const target = e.target.parentNode;
|
|
target.classList.toggle('order-card--selected')
|
|
if (e.target.checked) {
|
|
selectedOrders.set(target.dataset.id, target.dataset.type)
|
|
} else {
|
|
selectedOrders.delete(target.dataset.id)
|
|
}
|
|
getRef('selected_orders').textContent = `${selectedOrders.size} selected`
|
|
if (selectedOrders.size === 1 && !getRef('orders_section__header').children[0].classList.contains('hide-completely')) {
|
|
getRef('orders_section__header').children[0].animate(slideOutLeft, animOptions)
|
|
.onfinish = () => {
|
|
getRef('orders_section__header').children[0].classList.add('hide-completely')
|
|
getRef('orders_section__header').children[1].classList.remove('hide-completely')
|
|
getRef('orders_section__header').children[1].animate(slideInLeft, animOptions)
|
|
}
|
|
} else if (selectedOrders.size === 0 && getRef('orders_section__header').children[0].classList.contains('hide-completely')) {
|
|
getRef('orders_section__header').children[1].animate(slideOutRight, animOptions)
|
|
.onfinish = () => {
|
|
getRef('orders_section__header').children[1].classList.add('hide-completely')
|
|
getRef('orders_section__header').children[0].classList.remove('hide-completely')
|
|
getRef('orders_section__header').children[0].animate(slideInRight, animOptions)
|
|
}
|
|
}
|
|
})
|
|
function clearSelection() {
|
|
getRef('my_order_list').querySelectorAll('sm-checkbox[checked]').forEach(elem => elem.checked = false)
|
|
}
|
|
getRef('my_order_list').addEventListener('click', e => {
|
|
if (e.target.closest('.cancel-order')) {
|
|
getConfirmation('Cancel this order?').then(res => {
|
|
if (res) {
|
|
const target = e.target.closest('.order-card')
|
|
const id = target.dataset.id
|
|
const type = target.dataset.type
|
|
cancelOrder(type, id, proxy.secret)
|
|
.then(() => {
|
|
notify('Order cancelled', 'success')
|
|
target.remove()
|
|
})
|
|
.catch(err => notify(err, 'error'))
|
|
}
|
|
})
|
|
}
|
|
})
|
|
function cancelAll() {
|
|
getConfirmation('Cancel all selected orders?').then(res => {
|
|
if (res) {
|
|
try {
|
|
selectedOrders.forEach(async (type, id) => {
|
|
await cancelOrder(type, id, proxy.secret)
|
|
.then(() => {
|
|
getRef('my_order_list').querySelector(`data-id="${id}"`).remove()
|
|
})
|
|
})
|
|
notify('All selected orders cancelled', 'success')
|
|
}
|
|
catch (err) {
|
|
notify(err, 'error')
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
function renderAllOrders(buyOrders, sellOrders) {
|
|
getRef('my_order_list').innerHTML = '';
|
|
const frag = document.createDocumentFragment()
|
|
const allOpenOrders = [...(buyOrders || myBuyOrders), ...(sellOrders || mySellOrders)].sort((a, b) => b.time_placed - a.time_placed)
|
|
console.log(allOpenOrders)
|
|
allOpenOrders.forEach(order => {
|
|
const { id, quantity, minPrice = undefined, maxPrice = undefined, time_placed } = order
|
|
const orderDetails = {
|
|
id,
|
|
quantity,
|
|
type: minPrice ? 'sell' : 'buy',
|
|
price: minPrice || maxPrice,
|
|
time: time_placed
|
|
}
|
|
frag.append(render.orderCard(orderDetails))
|
|
})
|
|
getRef('my_order_list').append(frag)
|
|
}
|
|
function renderOpenOrders(buyOrders, sellOrders) {
|
|
getRef('my_order_list').innerHTML = '';
|
|
const frag = document.createDocumentFragment()
|
|
const allOpenOrders = [...(buyOrders || myBuyOrders), ...(sellOrders || mySellOrders)].sort((a, b) => b.time_placed - a.time_placed)
|
|
allOpenOrders.forEach(order => {
|
|
const { id, quantity, minPrice = undefined, maxPrice = undefined, time_placed } = order
|
|
const orderDetails = {
|
|
id,
|
|
quantity,
|
|
type: minPrice ? 'sell' : 'buy',
|
|
price: minPrice || maxPrice,
|
|
time: time_placed
|
|
}
|
|
frag.append(render.orderCard(orderDetails))
|
|
})
|
|
getRef('my_order_list').append(frag)
|
|
}
|
|
renderOpenOrders()
|
|
getRef('orders_scope_selector').addEventListener('change', e => {
|
|
if (e.target.value === 'open') {
|
|
renderOpenOrders()
|
|
} else {
|
|
renderCompletedOrders()
|
|
}
|
|
})
|
|
|
|
</script>
|
|
</body>
|
|
|
|
</html> |