From fcdd4c99ead3832a195abdc36636d3bf138b822c Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sat, 19 Feb 2022 03:23:59 -0800 Subject: [PATCH] Update deps and upgrade to latest vaadin. Minor fixes --- qortal-ui-plugins/build-config.js | 254 +- qortal-ui-plugins/package.json | 8 +- .../plugins/core/components/ChatPage.js | 4 +- .../core/components/ChatWelcomePage.js | 2 +- .../plugins/core/components/TimeAgo.js | 1 - .../plugins/core/components/ToolTip.js | 2 - .../group-management/group-management.src.js | 82 +- .../group-transaction.src.js | 118 - .../group-transaction/index.html | 25 +- .../plugins/core/group-management/index.html | 1 - qortal-ui-plugins/plugins/core/main.js | 2 +- qortal-ui-plugins/plugins/core/main.src.js | 4 +- .../chain-messaging/chain-messaging.src.js | 4 +- .../plugins/core/messaging/index.html | 2 +- .../plugins/core/messaging/messaging.src.js | 2 - .../plugins/core/messaging/q-chat/index.html | 3 +- .../core/messaging/q-chat/q-chat.src.js | 8 +- .../plugins/core/minting/index.html | 2 +- .../plugins/core/minting/minting-info.src.js | 60 +- .../plugins/core/name-registration/index.html | 4 +- .../name-registration.src.js | 35 +- .../node-management/node-management.src.js | 480 +-- .../plugins/core/puzzles/index.html | 4 +- .../plugins/core/puzzles/puzzles.src.js | 596 ++-- .../plugins/core/qdn/browser/browser.src.js | 254 +- .../plugins/core/qdn/browser/index.html | 1 + .../data-management/data-management.src.js | 7 +- qortal-ui-plugins/plugins/core/qdn/index.html | 1 - .../plugins/core/qdn/publish/index.html | 1 + .../plugins/core/qdn/publish/publish.src.js | 592 ++-- .../plugins/core/qdn/websites.src.js | 73 +- .../plugins/core/reward-share/index.html | 4 +- .../core/reward-share/reward-share.src.js | 40 +- .../plugins/core/send-coin/index.html | 1 + .../plugins/core/send-coin/send-coin.src.js | 1331 ++++---- .../plugins/core/streams/AddressWatcher.js | 10 +- .../streams/UnconfirmedTransactionWatcher.js | 10 +- .../plugins/core/trade-portal/index.html | 5 +- .../core/trade-portal/trade-portal.src.js | 2770 ++++++++--------- .../plugins/core/wallet/index.html | 70 +- .../plugins/core/wallet/wallet-app.src.js | 809 +++-- 41 files changed, 3782 insertions(+), 3900 deletions(-) diff --git a/qortal-ui-plugins/build-config.js b/qortal-ui-plugins/build-config.js index 63500fb3..4751866b 100644 --- a/qortal-ui-plugins/build-config.js +++ b/qortal-ui-plugins/build-config.js @@ -9,139 +9,139 @@ const path = require("path"); const alias = require("@rollup/plugin-alias"); const aliases = { - // 'qortal-ui-crypto': 'node_modules/qortal-ui-crypto/api.js' + // 'qortal-ui-crypto': 'node_modules/qortal-ui-crypto/api.js' }; const generateRollupConfig = (inputFile, outputFile) => { - return { - inputOptions: { - onwarn: (warning, rollupWarn) => { - if (warning.code !== "CIRCULAR_DEPENDENCY") { - rollupWarn(warning); - } - }, - input: inputFile, - plugins: [ - alias({ - // entries: {} - entries: Object.keys(aliases).map((find) => { - return { - find, - replacement: aliases[find], - }; - }), - }), - nodeResolve({ - preferBuiltins: false, - mainFields: ['module', 'browser'] - }), - replace({ - preventAssignment: true, - "process.env.NODE_ENV": JSON.stringify("production"), - }), - commonjs(), - globals(), - progress(), - babel.babel({ - babelHelpers: 'bundled', - exclude: "node_modules/**", - }), - terser({ - compress: true, - output: { - comments: false, - }, - }) - ], - }, - outputOptions: { - file: outputFile, - format: "umd", - }, - }; + return { + inputOptions: { + onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + if (warning.code !== 'CIRCULAR_DEPENDENCY') throw new Error(warning.message); + warn(warning); + }, + input: inputFile, + plugins: [ + alias({ + // entries: {} + entries: Object.keys(aliases).map((find) => { + return { + find, + replacement: aliases[find], + }; + }), + }), + nodeResolve({ + preferBuiltins: false, + mainFields: ['module', 'browser'] + }), + replace({ + preventAssignment: true, + "process.env.NODE_ENV": JSON.stringify("production"), + }), + commonjs(), + globals(), + progress(), + babel.babel({ + babelHelpers: 'bundled', + exclude: "node_modules/**", + }), + terser({ + compress: true, + output: { + comments: false, + }, + }) + ], + }, + outputOptions: { + file: outputFile, + format: "umd", + }, + }; }; const generateForPlugins = () => { - const configs = [ - { - in: "plugins/core/main.src.js", - out: "plugins/core/main.js", - }, - { - in: "plugins/core/trade-portal/trade-portal.src.js", - out: "plugins/core/trade-portal/trade-portal.js", - }, - { - in: "plugins/core/send-coin/send-coin.src.js", - out: "plugins/core/send-coin/send-coin.js", - }, - { - in: "plugins/core/wallet/wallet-app.src.js", - out: "plugins/core/wallet/wallet-app.js", - }, - { - in: "plugins/core/reward-share/reward-share.src.js", - out: "plugins/core/reward-share/reward-share.js", - }, - { - in: "plugins/core/node-management/node-management.src.js", - out: "plugins/core/node-management/node-management.js", - }, - { - in: "plugins/core/group-management/group-management.src.js", - out: "plugins/core/group-management/group-management.js", - }, - // { - // in: 'plugins/core/group-management/group-transaction/group-transaction.src.js', - // out: 'plugins/core/group-management/group-transaction/group-transaction.js' - // }, - { - in: "plugins/core/name-registration/name-registration.src.js", - out: "plugins/core/name-registration/name-registration.js", - }, - { - in: "plugins/core/qdn/websites.src.js", - out: "plugins/core/qdn/websites.js", - }, - { - in: "plugins/core/qdn/publish/publish.src.js", - out: "plugins/core/qdn/publish/publish.js", - }, - { - in: "plugins/core/qdn/browser/browser.src.js", - out: "plugins/core/qdn/browser/browser.js", - }, - { - in: "plugins/core/qdn/data-management/data-management.src.js", - out: "plugins/core/qdn/data-management/data-management.js", - }, - { - in: "plugins/core/messaging/messaging.src.js", - out: "plugins/core/messaging/messaging.js", - }, - { - in: "plugins/core/messaging/chain-messaging/chain-messaging.src.js", - out: "plugins/core/messaging/chain-messaging/chain-messaging.js", - }, - { - in: "plugins/core/messaging/q-chat/q-chat.src.js", - out: "plugins/core/messaging/q-chat/q-chat.js", - }, - { - in: "plugins/core/minting/minting-info.src.js", - out: "plugins/core/minting/minting-info.js", - }, - { - in: "plugins/core/puzzles/puzzles.src.js", - out: "plugins/core/puzzles/puzzles.js", - }, - ].map((file) => { - return generateRollupConfig( - path.join(__dirname, file.in), - path.join(__dirname, file.out) - ); - }); + const configs = [ + { + in: "plugins/core/main.src.js", + out: "plugins/core/main.js", + }, + { + in: "plugins/core/trade-portal/trade-portal.src.js", + out: "plugins/core/trade-portal/trade-portal.js", + }, + { + in: "plugins/core/send-coin/send-coin.src.js", + out: "plugins/core/send-coin/send-coin.js", + }, + { + in: "plugins/core/wallet/wallet-app.src.js", + out: "plugins/core/wallet/wallet-app.js", + }, + { + in: "plugins/core/reward-share/reward-share.src.js", + out: "plugins/core/reward-share/reward-share.js", + }, + { + in: "plugins/core/node-management/node-management.src.js", + out: "plugins/core/node-management/node-management.js", + }, + { + in: "plugins/core/group-management/group-management.src.js", + out: "plugins/core/group-management/group-management.js", + }, + // { + // in: 'plugins/core/group-management/group-transaction/group-transaction.src.js', + // out: 'plugins/core/group-management/group-transaction/group-transaction.js' + // }, + { + in: "plugins/core/name-registration/name-registration.src.js", + out: "plugins/core/name-registration/name-registration.js", + }, + { + in: "plugins/core/qdn/websites.src.js", + out: "plugins/core/qdn/websites.js", + }, + { + in: "plugins/core/qdn/publish/publish.src.js", + out: "plugins/core/qdn/publish/publish.js", + }, + { + in: "plugins/core/qdn/browser/browser.src.js", + out: "plugins/core/qdn/browser/browser.js", + }, + { + in: "plugins/core/qdn/data-management/data-management.src.js", + out: "plugins/core/qdn/data-management/data-management.js", + }, + { + in: "plugins/core/messaging/messaging.src.js", + out: "plugins/core/messaging/messaging.js", + }, + { + in: "plugins/core/messaging/chain-messaging/chain-messaging.src.js", + out: "plugins/core/messaging/chain-messaging/chain-messaging.js", + }, + { + in: "plugins/core/messaging/q-chat/q-chat.src.js", + out: "plugins/core/messaging/q-chat/q-chat.js", + }, + { + in: "plugins/core/minting/minting-info.src.js", + out: "plugins/core/minting/minting-info.js", + }, + { + in: "plugins/core/puzzles/puzzles.src.js", + out: "plugins/core/puzzles/puzzles.js", + }, + ].map((file) => { + return generateRollupConfig( + path.join(__dirname, file.in), + path.join(__dirname, file.out) + ); + }); - return configs; + return configs; }; module.exports = generateForPlugins; diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index b098343f..77d20b32 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -22,7 +22,7 @@ "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js" }, "devDependencies": { - "@babel/core": "^7.17.2", + "@babel/core": "^7.17.5", "@github/time-elements": "^3.1.2", "@material/mwc-button": "^0.25.3", "@material/mwc-dialog": "^0.25.3", @@ -39,11 +39,11 @@ "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-node-resolve": "^13.1.3", "@rollup/plugin-replace": "^3.1.0", - "@vaadin/vaadin-grid": "^5.9.3", + "@vaadin/grid": "^22.0.5", "epml": "^0.3.3", "html-escaper": "^3.0.3", - "lit": "^2.1.3", - "rollup": "^2.67.2", + "lit": "^2.2.0", + "rollup": "^2.67.3", "rollup-plugin-node-globals": "^1.4.0", "rollup-plugin-progress": "^1.1.2", "rollup-plugin-terser": "^7.0.2" diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 107b40c2..603623e7 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -2,11 +2,9 @@ import { LitElement, html, css } from 'lit' import { Epml } from '../../../epml.js' import { escape, unescape } from 'html-escaper'; -import { inputKeyCodes } from '../../utils/keyCodes.js'; - +import { inputKeyCodes } from '../../utils/keyCodes.js' import './ChatScroller.js' import './TimeAgo.js' - import { EmojiPicker } from 'emoji-picker-js'; import '@polymer/paper-spinner/paper-spinner-lite.js' diff --git a/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js b/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js index 4c03d6e9..cbb17c6d 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js @@ -406,7 +406,7 @@ class ChatWelcomePage extends LitElement { getAddressPublicKey() } - _textMenu(event) { + _textMenu(event) { const getSelectedText = () => { var text = ""; if (typeof window.getSelection != "undefined") { diff --git a/qortal-ui-plugins/plugins/core/components/TimeAgo.js b/qortal-ui-plugins/plugins/core/components/TimeAgo.js index b2bc5648..c212a736 100644 --- a/qortal-ui-plugins/plugins/core/components/TimeAgo.js +++ b/qortal-ui-plugins/plugins/core/components/TimeAgo.js @@ -46,7 +46,6 @@ class TimeAgo extends LitElement { } firstUpdated() { - // ... } } diff --git a/qortal-ui-plugins/plugins/core/components/ToolTip.js b/qortal-ui-plugins/plugins/core/components/ToolTip.js index e558c452..2994a00e 100644 --- a/qortal-ui-plugins/plugins/core/components/ToolTip.js +++ b/qortal-ui-plugins/plugins/core/components/ToolTip.js @@ -1,7 +1,6 @@ import { LitElement, html, css } from 'lit' import { Epml } from '../../../epml.js' - const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class ToolTip extends LitElement { @@ -92,7 +91,6 @@ class ToolTip extends LitElement { }) parentEpml.subscribe('config', c => { if (!configLoaded) { - // setTimeout(getGroupIdFromURL, 1) configLoaded = true } this.config = JSON.parse(c) diff --git a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js index 64ed8ce0..8da2a455 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js +++ b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js @@ -6,11 +6,9 @@ import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-textfield' import '@material/mwc-dialog' - import '@polymer/paper-spinner/paper-spinner-lite.js' -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' - +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' import '@github/time-elements' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -143,7 +141,7 @@ class GroupManagement extends LitElement {

Your Joined Groups

- + { @@ -160,7 +158,7 @@ class GroupManagement extends LitElement {

Public Groups

- + @@ -494,18 +492,18 @@ class GroupManagement extends LitElement { const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const url = `${nodeUrl}/transactions/unitfee?txType=CREATE_GROUP`; await fetch(url) - .then((response) => { - if (response.ok) { - return response.json(); - } - return Promise.reject(response); - }) - .then((json) => { - this.createFee = (Number(json) / 1e8).toFixed(8); - }) - .catch((response) => { - console.log(response.status, response.statusText, 'Need Core Update'); - }) + .then((response) => { + if (response.ok) { + return response.json(); + } + return Promise.reject(response); + }) + .then((json) => { + this.createFee = (Number(json) / 1e8).toFixed(8); + }) + .catch((response) => { + console.log(response.status, response.statusText, 'Need Core Update'); + }) } async unitJoinFee() { @@ -513,18 +511,18 @@ class GroupManagement extends LitElement { const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const url = `${nodeUrl}/transactions/unitfee?txType=JOIN_GROUP`; await fetch(url) - .then((response) => { - if (response.ok) { - return response.json(); - } - return Promise.reject(response); - }) - .then((json) => { - this.joinFee = (Number(json) / 1e8).toFixed(8); - }) - .catch((response) => { - console.log(response.status, response.statusText, 'Need Core Update'); - }) + .then((response) => { + if (response.ok) { + return response.json(); + } + return Promise.reject(response); + }) + .then((json) => { + this.joinFee = (Number(json) / 1e8).toFixed(8); + }) + .catch((response) => { + console.log(response.status, response.statusText, 'Need Core Update'); + }) } async unitLeaveFee() { @@ -532,18 +530,18 @@ class GroupManagement extends LitElement { const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const url = `${nodeUrl}/transactions/unitfee?txType=LEAVE_GROUP`; await fetch(url) - .then((response) => { - if (response.ok) { - return response.json(); - } - return Promise.reject(response); - }) - .then((json) => { - this.leaveFee = (Number(json) / 1e8).toFixed(8); - }) - .catch((response) => { - console.log(response.status, response.statusText, 'Need Core Update'); - }) + .then((response) => { + if (response.ok) { + return response.json(); + } + return Promise.reject(response); + }) + .then((json) => { + this.leaveFee = (Number(json) / 1e8).toFixed(8); + }) + .catch((response) => { + console.log(response.status, response.statusText, 'Need Core Update'); + }) } resetDefaultSettings() { diff --git a/qortal-ui-plugins/plugins/core/group-management/group-transaction/group-transaction.src.js b/qortal-ui-plugins/plugins/core/group-management/group-transaction/group-transaction.src.js index 71fd44ab..efb84a23 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-transaction/group-transaction.src.js +++ b/qortal-ui-plugins/plugins/core/group-management/group-transaction/group-transaction.src.js @@ -1,19 +1,8 @@ import { LitElement, html, css } from 'lit' -// import { render } from 'lit/html.js' -// import { Epml } from '../../../src/epml.js' import { Epml } from '../../../../epml.js' import '@polymer/paper-spinner/paper-spinner-lite.js' -// import * as thing from 'time-elements' -// import '@vaadin/vaadin-grid/vaadin-grid.js' -// import '@vaadin/vaadin-grid/theme/material/all-imports.js' - -// import '@material/mwc-icon' -// import '@material/mwc-textfield' -// import '@material/mwc-button' -// import '@material/mwc-dialog' - const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class GroupTransaction extends LitElement { @@ -75,7 +64,6 @@ class GroupTransaction extends LitElement { } .group-transaction-card { - /* margin:12px; */ padding:12px 24px; background:#fff; border-radius:2px; @@ -132,121 +120,16 @@ class GroupTransaction extends LitElement { render() { return html`
-

Group Transaction

-

${this.addMintingAccountMessage}

-
` } - // getMintingAccountGrid() { - - // const myGrid = this.shadowRoot.querySelector('#mintingAccountsGrid') - - // myGrid.addEventListener('click', (e) => { - // this.tempMintingAccount = myGrid.getEventContext(e).item - - // this.shadowRoot.querySelector('#removeMintingAccountDialog').show() - // }) - - // } - - - // addPeer(e) { - // this.addPeerLoading = true - // const addPeerAddress = this.shadowRoot.querySelector('#addPeerAddress').value - - // parentEpml.request('apiCall', { - // url: `/peers`, - // method: 'POST', - // body: addPeerAddress - // }).then(res => { - // this.addPeerMessage = res.message - - // this.addPeerLoading = false - // }) - - // } - - - // addMintingAccount(e) { - // this.addMintingAccountLoading = true - // this.addMintingAccountMessage = "Loading..." - - // this.addMintingAccountKey = this.shadowRoot.querySelector('#addMintingAccountKey').value - - // parentEpml.request('apiCall', { - // url: `/admin/mintingaccounts`, - // method: 'POST', - // body: this.addMintingAccountKey - // }).then(res => { - // if (res === true) { - // this.updateMintingAccounts() - // this.addMintingAccountKey = '' - // this.addMintingAccountMessage = 'Minting Node Added Successfully!' - // this.addMintingAccountLoading = false - // } else { - // this.addMintingAccountKey = '' - // this.addMintingAccountMessage = 'Failed to Add Minting Node!' // Corrected an error here thanks to crow (-_-) - // this.addMintingAccountLoading = false - // } - // }) - // } - - // updateMintingAccounts() { - // parentEpml.request('apiCall', { - // url: `/admin/mintingaccounts` - // }).then(res => { - - // this.mintingAccounts = [] - // setTimeout(() => { this.mintingAccounts = res }, 1) - // }) - - // // setTimeout(updateMintingAccounts, this.config.user.nodeSettings.pingInterval) // Perhaps should be slower...? - // } - - // removeMintingAccount(e) { - // this.removeMintingAccountLoading = true - // this.removeMintingAccountMessage = "Loading..." - - // this.removeMintingAccountKey = this.shadowRoot.querySelector('#removeMintingAccountKey').value - - // this.mintingAccounts.forEach(mintingAccount => { - // if (this.tempMintingAccount.recipientAccount === mintingAccount.recipientAccount) { - - // parentEpml.request('apiCall', { - // url: `/admin/mintingaccounts`, - // method: 'DELETE', - // body: this.removeMintingAccountKey - // }).then(res => { - // if (res === true) { - // this.updateMintingAccounts() - // this.removeMintingAccountKey = '' - // this.removeMintingAccountMessage = 'Minting Node Removed Successfully!' - // this.removeMintingAccountLoading = false - // } else { - // this.removeMintingAccountKey = '' - // this.removeMintingAccountMessage = 'Failed to Remove Minting Node!' - // this.removeMintingAccountLoading = false - // } - // }) - // } - // }) - - // } - firstUpdated() { - // Call getMintingAccountGrid - // this.getMintingAccountGrid() - - // Call updateMintingAccounts - // this.updateMintingAccounts() - const getGroupIdFromURL = () => { let tempUrl = document.location.href let decodeTempUrl = decodeURI(tempUrl) @@ -276,7 +159,6 @@ class GroupTransaction extends LitElement { }) }) - parentEpml.imReady() } diff --git a/qortal-ui-plugins/plugins/core/group-management/group-transaction/index.html b/qortal-ui-plugins/plugins/core/group-management/group-transaction/index.html index 68da30df..1a331212 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-transaction/index.html +++ b/qortal-ui-plugins/plugins/core/group-management/group-transaction/index.html @@ -4,6 +4,30 @@ - + \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index 5fe0664c..ba73945c 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -2,13 +2,10 @@ import { LitElement, html, css } from 'lit' import { render } from 'lit/html.js' import { Epml } from '../../../../epml.js' -// Components import '../../components/ChatWelcomePage.js' import '../../components/ChatHead.js' import '../../components/ChatPage.js' - import '@polymer/paper-spinner/paper-spinner-lite.js' - import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-dialog' @@ -296,11 +293,10 @@ class Chat extends LitElement {
-
this.scrollToBottom()}> +
this.scrollToBottom()}> New Message (Click to scroll down) keyboard_arrow_down
-
${window.parent.location.pathname !== "/app/q-chat" ? html`${this.renderChatPage(this.chatId)}` : html`${this.renderChatWelcomePage()}`}
@@ -474,9 +470,7 @@ class Chat extends LitElement { }) parentEpml.subscribe('chat_heads', chatHeads => { chatHeads = JSON.parse(chatHeads) - // setTimeout(() => { this.getChatHeadFromState(chatHeads) - // }, 5000) }) parentEpml.request('apiCall', { url: `/addresses/balance/${window.parent.reduxStore.getState().app.selectedAddress.address}` diff --git a/qortal-ui-plugins/plugins/core/minting/index.html b/qortal-ui-plugins/plugins/core/minting/index.html index afe19715..5b664c0f 100644 --- a/qortal-ui-plugins/plugins/core/minting/index.html +++ b/qortal-ui-plugins/plugins/core/minting/index.html @@ -32,7 +32,7 @@ body { margin: 0; font-family: "Roboto", sans-serif; - background: #fff; + background-color: #fff; } diff --git a/qortal-ui-plugins/plugins/core/minting/minting-info.src.js b/qortal-ui-plugins/plugins/core/minting/minting-info.src.js index c4301c50..fd5a8895 100644 --- a/qortal-ui-plugins/plugins/core/minting/minting-info.src.js +++ b/qortal-ui-plugins/plugins/core/minting/minting-info.src.js @@ -1,13 +1,13 @@ -import { LitElement, html, css } from "lit"; -import { render } from "lit/html.js"; -import { Epml } from "../../../epml.js"; +import { LitElement, html, css } from 'lit' +import { render } from 'lit/html.js' +import { Epml } from '../../../epml.js' -import "@material/mwc-icon"; -import "@material/mwc-button"; -import "@material/mwc-dialog"; -import "@material/mwc-textfield"; +import '@material/mwc-icon' +import '@material/mwc-button' +import '@material/mwc-dialog' +import '@material/mwc-textfield' -const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); +const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class MintingInfo extends LitElement { static get properties() { @@ -18,7 +18,7 @@ class MintingInfo extends LitElement { nodeInfo: { type: Array }, sampleBlock: { type: Array }, addressInfo: { type: Array }, - addressLevel: { type: Array }, + addressLevel: { type: Array } } } @@ -195,8 +195,8 @@ class MintingInfo extends LitElement { } render() { - if (this.renderMintingPage() === "false") { - return html` + if (this.renderMintingPage() === "false") { + return html`
General Minting Details @@ -247,7 +247,7 @@ class MintingInfo extends LitElement {
`} else { - return html` + return html`
General Minting Details @@ -356,14 +356,14 @@ class MintingInfo extends LitElement { firstUpdated() { const getAdminInfo = () => { - parentEpml.request("apiCall", {url: `/admin/info`}).then((res) => { - setTimeout(() => {this.adminInfo = res;}, 1); + parentEpml.request("apiCall", { url: `/admin/info` }).then((res) => { + setTimeout(() => { this.adminInfo = res; }, 1); }); setTimeout(getAdminInfo, 30000); }; const getNodeInfo = () => { - parentEpml.request("apiCall", {url: `/admin/status`}).then((res) => { + parentEpml.request("apiCall", { url: `/admin/status` }).then((res) => { this.nodeInfo = res; // Now look up the sample block getSampleBlock() @@ -373,21 +373,21 @@ class MintingInfo extends LitElement { const getSampleBlock = () => { let callBlock = parseFloat(this.nodeInfo.height) - 10000; - parentEpml.request("apiCall", {url: `/blocks/byheight/${callBlock}`}).then((res) => { - setTimeout(() => {this.sampleBlock = res;}, 1); + parentEpml.request("apiCall", { url: `/blocks/byheight/${callBlock}` }).then((res) => { + setTimeout(() => { this.sampleBlock = res; }, 1); }); }; const getAddressInfo = () => { - parentEpml.request('apiCall', {url: `/addresses/${window.parent.reduxStore.getState().app.selectedAddress.address}`}).then((res) => { - setTimeout(() => {this.addressInfo = res;}, 1); + parentEpml.request('apiCall', { url: `/addresses/${window.parent.reduxStore.getState().app.selectedAddress.address}` }).then((res) => { + setTimeout(() => { this.addressInfo = res; }, 1); }); setTimeout(getAddressInfo, 30000); }; const getAddressLevel = () => { - parentEpml.request('apiCall', {url: `/addresses/online/levels`}).then((res) => { - setTimeout(() => {this.addressLevel = res;}, 1); + parentEpml.request('apiCall', { url: `/addresses/online/levels` }).then((res) => { + setTimeout(() => { this.addressLevel = res; }, 1); }); setTimeout(getAddressLevel, 30000); }; @@ -432,30 +432,30 @@ class MintingInfo extends LitElement { renderActivateHelp() { if (this.renderMintingPage() === "false") { - return html `Activate Account Details
==>
Not Activated
this.shadowRoot.querySelector("#activateAccountDialog").show()}>help_outline Press For Help`; + return html`Activate Account Details
==>
Not Activated
this.shadowRoot.querySelector("#activateAccountDialog").show()}>help_outline Press For Help`; } else { return "No Details"; } } _averageBlockTime() { let avgBlockString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString(); - let averageTimeString = ((avgBlockString / 1000) / 10000).toFixed(2); - let averageBlockTimeString = (averageTimeString).toString(); + let averageTimeString = ((avgBlockString / 1000) / 10000).toFixed(2); + let averageBlockTimeString = (averageTimeString).toString(); return "" + averageBlockTimeString; } _timeCalc() { let timeString = (this.adminInfo.currentTimestamp - this.sampleBlock.timestamp).toString(); - let averageString = ((timeString / 1000) / 10000).toFixed(2); - let averageBlockDay = (86400 / averageString).toFixed(2); - let averageBlockDayString = (averageBlockDay).toString(); + let averageString = ((timeString / 1000) / 10000).toFixed(2); + let averageBlockDay = (86400 / averageString).toFixed(2); + let averageBlockDayString = (averageBlockDay).toString(); return "" + averageBlockDayString; } _dayReward() { let rewardString = (this._timeCalc() * this._blockReward()).toFixed(2); - let rewardDayString = (rewardString).toString(); - return "" + rewardDayString ; + let rewardDayString = (rewardString).toString(); + return "" + rewardDayString; } _mintingStatus() { @@ -478,7 +478,7 @@ class MintingInfo extends LitElement { renderMintingHelp() { if (this._mintingStatus() === "Not Minting") { - return html `Minting Account Details
==>
Not A Minter
this.shadowRoot.querySelector("#becomeMinterDialog").show()}>help_outline Press For Help`; + return html`Minting Account Details
==>
Not A Minter
this.shadowRoot.querySelector("#becomeMinterDialog").show()}>help_outline Press For Help`; } else { return "Minting Account Details"; } diff --git a/qortal-ui-plugins/plugins/core/name-registration/index.html b/qortal-ui-plugins/plugins/core/name-registration/index.html index 4ec6e455..879ea894 100644 --- a/qortal-ui-plugins/plugins/core/name-registration/index.html +++ b/qortal-ui-plugins/plugins/core/name-registration/index.html @@ -32,14 +32,14 @@ body { margin: 0; font-family: "Roboto", sans-serif; - background: #fff; + background-color: #fff; } - + \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js b/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js index 1be248f7..bbc4b4f7 100644 --- a/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js +++ b/qortal-ui-plugins/plugins/core/name-registration/name-registration.src.js @@ -6,10 +6,9 @@ import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-textfield' import '@material/mwc-dialog' - import '@polymer/paper-spinner/paper-spinner-lite.js' -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -86,10 +85,10 @@ class NameRegistration extends LitElement {

Registered Names

- + { render(html`${this.renderAvatar(data.item)}`, root) - }}> + }}> { @@ -216,18 +215,18 @@ class NameRegistration extends LitElement { const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const url = `${nodeUrl}/transactions/unitfee?txType=REGISTER_NAME`; await fetch(url) - .then((response) => { - if (response.ok) { - return response.json(); - } - return Promise.reject(response); - }) - .then((json) => { - this.fee = (Number(json) / 1e8).toFixed(8); - }) - .catch((response) => { - console.log(response.status, response.statusText, 'Need Core Update'); - }) + .then((response) => { + if (response.ok) { + return response.json(); + } + return Promise.reject(response); + }) + .then((json) => { + this.fee = (Number(json) / 1e8).toFixed(8); + }) + .catch((response) => { + console.log(response.status, response.statusText, 'Need Core Update'); + }) } getApiKey() { @@ -248,7 +247,7 @@ class NameRegistration extends LitElement { const nameInput = this.shadowRoot.getElementById("nameInput").value const descInput = this.shadowRoot.getElementById("descInput").value - // Check for valid...^ + // Check for valid... this.registerNameLoading = true // Get Last Ref diff --git a/qortal-ui-plugins/plugins/core/node-management/node-management.src.js b/qortal-ui-plugins/plugins/core/node-management/node-management.src.js index 6a2a54f1..405e57f2 100644 --- a/qortal-ui-plugins/plugins/core/node-management/node-management.src.js +++ b/qortal-ui-plugins/plugins/core/node-management/node-management.src.js @@ -1,42 +1,42 @@ -import { LitElement, html, css } from "lit"; +import { LitElement, html, css } from 'lit' import { render } from 'lit/html.js' -import { Epml } from "../../../epml.js"; +import { Epml } from '../../../epml.js' -import "@polymer/paper-spinner/paper-spinner-lite.js"; -import "@vaadin/vaadin-grid/vaadin-grid.js"; -import "@vaadin/vaadin-grid/theme/material/all-imports.js"; -import "@material/mwc-icon"; -import "@material/mwc-textfield"; -import "@material/mwc-button"; -import "@material/mwc-dialog"; +import '@polymer/paper-spinner/paper-spinner-lite.js' +import '@material/mwc-icon' +import '@material/mwc-textfield' +import '@material/mwc-button' +import '@material/mwc-dialog' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' -const parentEpml = new Epml({ type: "WINDOW", source: window.parent }); +const parentEpml = new Epml({ type: "WINDOW", source: window.parent }) class NodeManagement extends LitElement { - static get properties() { - return { - loading: { type: Boolean }, - upTime: { type: String }, - mintingAccounts: { type: Array }, - peers: { type: Array }, - addMintingAccountLoading: { type: Boolean }, - removeMintingAccountLoading: { type: Boolean }, - addPeerLoading: { type: Boolean }, - confPeerLoading: { type: Boolean }, - addMintingAccountKey: { type: String }, - removeMintingAccountKey: { type: String }, - addPeerMessage: { type: String }, - confPeerMessage: { type: String }, - addMintingAccountMessage: { type: String }, - removeMintingAccountMessage: { type: String }, - tempMintingAccount: { type: Object }, - nodeConfig: { type: Object }, - nodeDomain: { type: String }, - }; - } + static get properties() { + return { + loading: { type: Boolean }, + upTime: { type: String }, + mintingAccounts: { type: Array }, + peers: { type: Array }, + addMintingAccountLoading: { type: Boolean }, + removeMintingAccountLoading: { type: Boolean }, + addPeerLoading: { type: Boolean }, + confPeerLoading: { type: Boolean }, + addMintingAccountKey: { type: String }, + removeMintingAccountKey: { type: String }, + addPeerMessage: { type: String }, + confPeerMessage: { type: String }, + addMintingAccountMessage: { type: String }, + removeMintingAccountMessage: { type: String }, + tempMintingAccount: { type: Object }, + nodeConfig: { type: Object }, + nodeDomain: { type: String } + }; + } - static get styles() { - return css` + static get styles() { + return css` * { --mdc-theme-primary: rgb(3, 169, 244); --paper-input-container-focus-color: var(--mdc-theme-primary); @@ -72,7 +72,6 @@ class NodeManagement extends LitElement { } .node-card { - /* margin:12px; */ padding: 12px 24px; background: #fff; border-radius: 2px; @@ -95,38 +94,39 @@ class NodeManagement extends LitElement { display: hidden !important; visibility: none !important; } + .details { display: flex; font-size: 18px; } `; - } + } - constructor() { - super(); - this.upTime = ""; - this.mintingAccounts = []; - this.peers = []; - this.addPeerLoading = false; - this.confPeerLoading = false; - this.addMintingAccountLoading = false; - this.removeMintingAccountLoading = false; - this.addMintingAccountKey = ""; - this.addPeerMessage = ""; - this.confPeerMessage = ""; - this.addMintingAccountMessage = ""; - this.tempMintingAccount = {}; - this.config = { - user: { - node: {}, - }, - }; - this.nodeConfig = {}; - this.nodeDomain = ""; - } + constructor() { + super(); + this.upTime = ""; + this.mintingAccounts = []; + this.peers = []; + this.addPeerLoading = false; + this.confPeerLoading = false; + this.addMintingAccountLoading = false; + this.removeMintingAccountLoading = false; + this.addMintingAccountKey = ""; + this.addPeerMessage = ""; + this.confPeerMessage = ""; + this.addMintingAccountMessage = ""; + this.tempMintingAccount = {}; + this.config = { + user: { + node: {}, + }, + }; + this.nodeConfig = {}; + this.nodeDomain = ""; + } - render() { - return html` + render() { + return html`

Node management for: ${this.nodeDomain}

@@ -143,7 +143,7 @@ class NodeManagement extends LitElement { - this.shadowRoot + this.shadowRoot .querySelector("#addMintingAccountDialog") .show()} >addAdd minting account - + { @@ -253,12 +253,12 @@ class NodeManagement extends LitElement { - + - { + { render(html` this.removePeer(data.item.address, data.index)}>deleteRemove this.forceSyncPeer(data.item.address, data.index)}>Force Sync`, root) }}> @@ -269,81 +269,81 @@ class NodeManagement extends LitElement {
`; - } - - forceSyncPeer (peerAddress, rowIndex) { - parentEpml - .request("apiCall", { - url: `/admin/forcesync?apiKey=${this.getApiKey()}`, - method: "POST", - body: peerAddress, - }) - .then((res) => { - parentEpml.request('showSnackBar', "Starting Sync with Peer: " + peerAddress ); - }); - } - - removePeer(peerAddress, rowIndex) { - parentEpml - .request("apiCall", { - url: `/peers?apiKey=${this.getApiKey()}`, - method: "DELETE", - body: peerAddress, - }) - .then((res) => { - parentEpml.request('showSnackBar', "Successfully removed Peer: " + peerAddress ); - this.peers.splice(rowIndex, 1); - }); - } - - onPageNavigation(pageUrl) { - parentEpml.request("setPageUrl", pageUrl); - } + } - addPeer(e) { - this.addPeerLoading = true; - const addPeerAddress = this.shadowRoot.querySelector("#addPeerAddress") - .value; + forceSyncPeer(peerAddress, rowIndex) { + parentEpml + .request("apiCall", { + url: `/admin/forcesync?apiKey=${this.getApiKey()}`, + method: "POST", + body: peerAddress, + }) + .then((res) => { + parentEpml.request('showSnackBar', "Starting Sync with Peer: " + peerAddress); + }); + } - parentEpml - .request("apiCall", { - url: `/peers?apiKey=${this.getApiKey()}`, - method: "POST", - body: addPeerAddress, - }) - .then((res) => { - this.addPeerMessage = res.message; - this.addPeerLoading = false; - }); - } + removePeer(peerAddress, rowIndex) { + parentEpml + .request("apiCall", { + url: `/peers?apiKey=${this.getApiKey()}`, + method: "DELETE", + body: peerAddress, + }) + .then((res) => { + parentEpml.request('showSnackBar', "Successfully removed Peer: " + peerAddress); + this.peers.splice(rowIndex, 1); + }); + } - addMintingAccount(e) { - this.addMintingAccountLoading = true; - this.addMintingAccountMessage = "Loading..."; + onPageNavigation(pageUrl) { + parentEpml.request("setPageUrl", pageUrl); + } - this.addMintingAccountKey = this.shadowRoot.querySelector( - "#addMintingAccountKey" - ).value; + addPeer(e) { + this.addPeerLoading = true; + const addPeerAddress = this.shadowRoot.querySelector("#addPeerAddress") + .value; - parentEpml - .request("apiCall", { - url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`, - method: "POST", - body: this.addMintingAccountKey, - }) - .then((res) => { - if (res === true) { - this.updateMintingAccounts(); - this.addMintingAccountKey = ""; - this.addMintingAccountMessage = "Minting Node Added Successfully!"; - this.addMintingAccountLoading = false; - } else { - this.addMintingAccountKey = ""; - this.addMintingAccountMessage = "Failed to Add Minting Node!"; // Corrected an error here thanks to crow (-_-) - this.addMintingAccountLoading = false; - } - }); - } + parentEpml + .request("apiCall", { + url: `/peers?apiKey=${this.getApiKey()}`, + method: "POST", + body: addPeerAddress, + }) + .then((res) => { + this.addPeerMessage = res.message; + this.addPeerLoading = false; + }); + } + + addMintingAccount(e) { + this.addMintingAccountLoading = true; + this.addMintingAccountMessage = "Loading..."; + + this.addMintingAccountKey = this.shadowRoot.querySelector( + "#addMintingAccountKey" + ).value; + + parentEpml + .request("apiCall", { + url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`, + method: "POST", + body: this.addMintingAccountKey, + }) + .then((res) => { + if (res === true) { + this.updateMintingAccounts(); + this.addMintingAccountKey = ""; + this.addMintingAccountMessage = "Minting Node Added Successfully!"; + this.addMintingAccountLoading = false; + } else { + this.addMintingAccountKey = ""; + this.addMintingAccountMessage = "Failed to Add Minting Node!"; // Corrected an error here thanks to crow (-_-) + this.addMintingAccountLoading = false; + } + }); + } updateMintingAccounts() { parentEpml.request("apiCall", { @@ -358,9 +358,9 @@ class NodeManagement extends LitElement { const getSelectedText = () => { var text = ""; if (typeof window.getSelection != "undefined") { - text = window.getSelection().toString(); + text = window.getSelection().toString(); } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { - text = this.shadowRoot.selection.createRange().text; + text = this.shadowRoot.selection.createRange().text; } return text; } @@ -369,18 +369,18 @@ class NodeManagement extends LitElement { let selectedText = getSelectedText(); if (selectedText && typeof selectedText === 'string') { - let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } + let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } - let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } + let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } - parentEpml.request('openCopyTextMenu', textMenuObject) + parentEpml.request('openCopyTextMenu', textMenuObject) } } checkSelectedTextAndShowMenu() } - removeMintingAccount(publicKey) { + removeMintingAccount(publicKey) { this.removeMintingAccountLoading = true; parentEpml.request("apiCall", { @@ -397,116 +397,116 @@ class NodeManagement extends LitElement { parentEpml.request('showSnackBar', "Failed to Remove Minting Account!"); } }); - } - - firstUpdated() { - - // Call updateMintingAccounts - this.updateMintingAccounts(); - - window.addEventListener("contextmenu", (event) => { - event.preventDefault(); - this._textMenu(event) - }); - window.addEventListener("click", () => { - parentEpml.request('closeCopyTextMenu', null) - }); - window.onkeyup = (e) => { - if (e.keyCode === 27) parentEpml.request('closeCopyTextMenu', null) } - // Calculate HH MM SS from Milliseconds... - const convertMsToTime = (milliseconds) => { - let day, hour, minute, seconds; - seconds = Math.floor(milliseconds / 1000); - minute = Math.floor(seconds / 60); - seconds = seconds % 60; - hour = Math.floor(minute / 60); - minute = minute % 60; - day = Math.floor(hour / 24); - hour = hour % 24; - if (isNaN(day)) { - return "offline"; - } - return day + "d " + hour + "h " + minute + "m"; - }; + firstUpdated() { - const getNodeUpTime = () => { - parentEpml - .request("apiCall", { - url: `/admin/uptime`, - }) - .then((res) => { - this.upTime = ""; - setTimeout(() => { - this.upTime = convertMsToTime(res); - }, 1); + // Call updateMintingAccounts + this.updateMintingAccounts(); + + window.addEventListener("contextmenu", (event) => { + event.preventDefault(); + this._textMenu(event) }); - - setTimeout(getNodeUpTime, this.config.user.nodeSettings.pingInterval); - }; - - const updatePeers = () => { - parentEpml - .request("apiCall", { - url: `/peers`, - }) - .then((res) => { - setTimeout(() => { - this.peers = res; - }, 1); + window.addEventListener("click", () => { + parentEpml.request('closeCopyTextMenu', null) }); - - setTimeout(updatePeers, this.config.user.nodeSettings.pingInterval); - }; - - const getNodeConfig = () => { - parentEpml.request("getNodeConfig").then((res) => { - setTimeout(() => { - this.nodeConfig = res; - }, 1); - let myNode = window.parent.reduxStore.getState().app.nodeConfig - .knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - this.nodeDomain = myNode.domain + ":" + myNode.port; - }); - - setTimeout(getNodeConfig, 1000); - }; - - let configLoaded = false; - parentEpml.ready().then(() => { - parentEpml.subscribe("config", async c => { - if (!configLoaded) { - setTimeout(getNodeUpTime, 1); - setTimeout(updatePeers, 1); - setTimeout(this.updateMintingAccounts, 1); - setTimeout(getNodeConfig, 1); - configLoaded = true; + window.onkeyup = (e) => { + if (e.keyCode === 27) parentEpml.request('closeCopyTextMenu', null) } - this.config = JSON.parse(c); - }) - parentEpml.subscribe('copy_menu_switch', async value => { - if (value === 'false' && window.getSelection().toString().length !== 0) this.clearSelection(); - }) - }); - parentEpml.imReady(); - } - getApiKey() { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - let apiKey = myNode.apiKey; - return apiKey; - } + // Calculate HH MM SS from Milliseconds... + const convertMsToTime = (milliseconds) => { + let day, hour, minute, seconds; + seconds = Math.floor(milliseconds / 1000); + minute = Math.floor(seconds / 60); + seconds = seconds % 60; + hour = Math.floor(minute / 60); + minute = minute % 60; + day = Math.floor(hour / 24); + hour = hour % 24; + if (isNaN(day)) { + return "offline"; + } + return day + "d " + hour + "h " + minute + "m"; + }; - clearSelection() { - window.getSelection().removeAllRanges() - window.parent.getSelection().removeAllRanges() - } + const getNodeUpTime = () => { + parentEpml + .request("apiCall", { + url: `/admin/uptime`, + }) + .then((res) => { + this.upTime = ""; + setTimeout(() => { + this.upTime = convertMsToTime(res); + }, 1); + }); - isEmptyArray(arr) { - if (!arr) return true; - return arr.length === 0; - } + setTimeout(getNodeUpTime, this.config.user.nodeSettings.pingInterval); + }; + + const updatePeers = () => { + parentEpml + .request("apiCall", { + url: `/peers`, + }) + .then((res) => { + setTimeout(() => { + this.peers = res; + }, 1); + }); + + setTimeout(updatePeers, this.config.user.nodeSettings.pingInterval); + }; + + const getNodeConfig = () => { + parentEpml.request("getNodeConfig").then((res) => { + setTimeout(() => { + this.nodeConfig = res; + }, 1); + let myNode = window.parent.reduxStore.getState().app.nodeConfig + .knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + this.nodeDomain = myNode.domain + ":" + myNode.port; + }); + + setTimeout(getNodeConfig, 1000); + }; + + let configLoaded = false; + parentEpml.ready().then(() => { + parentEpml.subscribe("config", async c => { + if (!configLoaded) { + setTimeout(getNodeUpTime, 1); + setTimeout(updatePeers, 1); + setTimeout(this.updateMintingAccounts, 1); + setTimeout(getNodeConfig, 1); + configLoaded = true; + } + this.config = JSON.parse(c); + }) + parentEpml.subscribe('copy_menu_switch', async value => { + if (value === 'false' && window.getSelection().toString().length !== 0) this.clearSelection(); + }) + }); + parentEpml.imReady(); + } + + getApiKey() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + let apiKey = myNode.apiKey; + return apiKey; + } + + clearSelection() { + window.getSelection().removeAllRanges() + window.parent.getSelection().removeAllRanges() + } + + isEmptyArray(arr) { + if (!arr) return true; + return arr.length === 0; + } } window.customElements.define("node-management", NodeManagement); diff --git a/qortal-ui-plugins/plugins/core/puzzles/index.html b/qortal-ui-plugins/plugins/core/puzzles/index.html index e328bade..1b4000b5 100644 --- a/qortal-ui-plugins/plugins/core/puzzles/index.html +++ b/qortal-ui-plugins/plugins/core/puzzles/index.html @@ -32,14 +32,14 @@ body { margin: 0; font-family: "Roboto", sans-serif; - background: #fff; + background-color: #fff; } - + diff --git a/qortal-ui-plugins/plugins/core/puzzles/puzzles.src.js b/qortal-ui-plugins/plugins/core/puzzles/puzzles.src.js index 19d59a30..88038230 100644 --- a/qortal-ui-plugins/plugins/core/puzzles/puzzles.src.js +++ b/qortal-ui-plugins/plugins/core/puzzles/puzzles.src.js @@ -6,37 +6,36 @@ import { Epml } from '../../../epml.js' import nacl from '../../../../qortal-ui-crypto/api/deps/nacl-fast.js' import Base58 from '../../../../qortal-ui-crypto/api/deps/Base58.js' import publicKeyToAddress from '../../../../qortal-ui-crypto/api/wallet/publicKeyToAddress.js' - import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-textfield' import '@material/mwc-dialog' import '@material/mwc-slider' - import '@polymer/paper-spinner/paper-spinner-lite.js' -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) + const DEFAULT_FEE = 0.001 const PAYMENT_TX_TYPE = 2 class Puzzles extends LitElement { - static get properties() { - return { - loading: { type: Boolean }, - invalid: { type: Boolean }, - puzzles: { type: Array }, - solved: { type: Object }, - selectedAddress: { type: Object }, - selectedPuzzle: { type: Object }, - error: { type: Boolean }, - message: { type: String } - } - } + static get properties() { + return { + loading: { type: Boolean }, + invalid: { type: Boolean }, + puzzles: { type: Array }, + solved: { type: Object }, + selectedAddress: { type: Object }, + selectedPuzzle: { type: Object }, + error: { type: Boolean }, + message: { type: String } + } + } - static get styles() { - return css` + static get styles() { + return css` * { --mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-secondary: var(--mdc-theme-primary); @@ -65,48 +64,48 @@ class Puzzles extends LitElement { font-size: smaller; } ` - } + } - constructor() { - super() - this.loading = false - this.invalid = true - this.puzzles = [] - this.solved = {} - this.selectedAddress = {} - this.selectedPuzzle = {} - this.error = false - this.message = '' - } + constructor() { + super() + this.loading = false + this.invalid = true + this.puzzles = [] + this.solved = {} + this.selectedAddress = {} + this.selectedPuzzle = {} + this.error = false + this.message = '' + } - render() { - return html` + render() { + return html`

Puzzles

- - - { - if (data.item.isSolved) { - render(html`SOLVED by ${data.item.winner}`, root) - } else { - render(html`${data.item.reward} QORT`, root) - } - }}> +
+ + { + if (data.item.isSolved) { + render(html`SOLVED by ${data.item.winner}`, root) + } else { + render(html`${data.item.reward} QORT`, root) + } + }}> { - if (data.item.isSolved) { - render(html``, root) - } else { - render(html` this.guessPuzzle(data.item)}>queueGuess`, root) - } - }}> - + if (data.item.isSolved) { + render(html``, root) + } else { + render(html` this.guessPuzzle(data.item)}>queueGuess`, root) + } + }}> + - +
Enter your guess to solve this puzzle and win ${this.selectedPuzzle.reward} QORT:

Name: ${this.selectedPuzzle.name}
@@ -122,7 +121,8 @@ class Puzzles extends LitElement { + alt="Claiming puzzle reward"> + ${this.message} @@ -145,317 +145,317 @@ class Puzzles extends LitElement {
` - } + } - firstUpdated() { - window.addEventListener("contextmenu", (event) => { - event.preventDefault(); - this._textMenu(event) - }); + firstUpdated() { + window.addEventListener("contextmenu", (event) => { + event.preventDefault(); + this._textMenu(event) + }); - window.addEventListener("click", () => { - parentEpml.request('closeCopyTextMenu', null) - }); + window.addEventListener("click", () => { + parentEpml.request('closeCopyTextMenu', null) + }); - window.onkeyup = (e) => { - if (e.keyCode === 27) { - parentEpml.request('closeCopyTextMenu', null) - } - } + window.onkeyup = (e) => { + if (e.keyCode === 27) { + parentEpml.request('closeCopyTextMenu', null) + } + } - const textBox = this.shadowRoot.getElementById("puzzleGuess") + const textBox = this.shadowRoot.getElementById("puzzleGuess") - // keep track of input validity so we can enabled/disable submit button - textBox.validityTransform = (newValue, nativeValidity) => { - this.invalid = !nativeValidity.valid - return nativeValidity - } + // keep track of input validity so we can enabled/disable submit button + textBox.validityTransform = (newValue, nativeValidity) => { + this.invalid = !nativeValidity.valid + return nativeValidity + } - const getPuzzleGroupMembers = async () => { - return await parentEpml.request('apiCall', { - url: `/groups/members/165` - }) - } + const getPuzzleGroupMembers = async () => { + return await parentEpml.request('apiCall', { + url: `/groups/members/165` + }) + } - const getBalance = async(address) => { - return await parentEpml.request('apiCall', { - url: `/addresses/balance/${address}` - }) - } + const getBalance = async (address) => { + return await parentEpml.request('apiCall', { + url: `/addresses/balance/${address}` + }) + } - const getName = async(memberAddress) => { - let _names = await parentEpml.request('apiCall', { - url: `/names/address/${memberAddress}` - }) + const getName = async (memberAddress) => { + let _names = await parentEpml.request('apiCall', { + url: `/names/address/${memberAddress}` + }) - if (_names.length === 0) return ""; + if (_names.length === 0) return ""; - return _names[0].name - } + return _names[0].name + } - const getNameInfo = async(name) => { - // We have to explicitly encode '#' to stop them being interpreted as in-page references - name = name.replaceAll('#', '%23') + const getNameInfo = async (name) => { + // We have to explicitly encode '#' to stop them being interpreted as in-page references + name = name.replaceAll('#', '%23') - return await parentEpml.request('apiCall', { - url: `/names/${name}` - }) - } + return await parentEpml.request('apiCall', { + url: `/names/${name}` + }) + } - const getFirstOutgoingPayment = async(sender) => { - let _payments = await parentEpml.request('apiCall', { - url: `/transactions/search?confirmationStatus=CONFIRMED&limit=20&txType=PAYMENT&address=${sender}` - }) + const getFirstOutgoingPayment = async (sender) => { + let _payments = await parentEpml.request('apiCall', { + url: `/transactions/search?confirmationStatus=CONFIRMED&limit=20&txType=PAYMENT&address=${sender}` + }) - return _payments.find(payment => payment.creatorAddress === sender) - } + return _payments.find(payment => payment.creatorAddress === sender) + } - const updatePuzzles = async () => { - let _puzzleGroupMembers = await getPuzzleGroupMembers() + const updatePuzzles = async () => { + let _puzzleGroupMembers = await getPuzzleGroupMembers() - let _puzzles = [] + let _puzzles = [] - await Promise.all(_puzzleGroupMembers.members - .sort((a, b) => b.joined - a.joined) - .map(async (member) => { - let _puzzleAddress = member.member + await Promise.all(_puzzleGroupMembers.members + .sort((a, b) => b.joined - a.joined) + .map(async (member) => { + let _puzzleAddress = member.member - if (member.isAdmin) return + if (member.isAdmin) return - // Already solved? No need to refresh info - if (this.solved[_puzzleAddress]) { - _puzzles.push(this.solved[_puzzleAddress]) - return - } + // Already solved? No need to refresh info + if (this.solved[_puzzleAddress]) { + _puzzles.push(this.solved[_puzzleAddress]) + return + } - let _name = await getName(_puzzleAddress) - // No name??? - if (_name === "") return + let _name = await getName(_puzzleAddress) + // No name??? + if (_name === "") return - let _reward = await getBalance(_puzzleAddress) - let _isSolved = _reward < 1.0; - let _nameInfo = await getNameInfo(_name) + let _reward = await getBalance(_puzzleAddress) + let _isSolved = _reward < 1.0; + let _nameInfo = await getNameInfo(_name) - let _nameData = JSON.parse(_nameInfo.data) + let _nameData = JSON.parse(_nameInfo.data) - let _puzzle = { - reward: _reward, - address: _puzzleAddress, - name: _name, - description: _nameData.description, - isSolved: _isSolved - } + let _puzzle = { + reward: _reward, + address: _puzzleAddress, + name: _name, + description: _nameData.description, + isSolved: _isSolved + } - if (!_isSolved && _nameData.clue) - _puzzle.clue = _nameData.clue; + if (!_isSolved && _nameData.clue) + _puzzle.clue = _nameData.clue; - if (_isSolved) { - // Info on winner - let _payment = await getFirstOutgoingPayment(_puzzleAddress) - _puzzle.winner = _payment.recipient - // Does winner have a name? - let _winnerName = await getName(_puzzle.winner) - if (_winnerName) _puzzle.winner = _winnerName - // Add to 'solved' map to prevent info refresh as it'll never change - this.solved[_puzzleAddress] = _puzzle - } + if (_isSolved) { + // Info on winner + let _payment = await getFirstOutgoingPayment(_puzzleAddress) + _puzzle.winner = _payment.recipient + // Does winner have a name? + let _winnerName = await getName(_puzzle.winner) + if (_winnerName) _puzzle.winner = _winnerName + // Add to 'solved' map to prevent info refresh as it'll never change + this.solved[_puzzleAddress] = _puzzle + } - _puzzles.push(_puzzle); - })) + _puzzles.push(_puzzle); + })) - this.puzzles = _puzzles; + this.puzzles = _puzzles; - setTimeout(updatePuzzles, 20000) - } + setTimeout(updatePuzzles, 20000) + } - let configLoaded = false + let configLoaded = false - parentEpml.ready().then(() => { - parentEpml.subscribe('selected_address', async selectedAddress => { - this.selectedAddress = {} - selectedAddress = JSON.parse(selectedAddress) - if (!selectedAddress || Object.entries(selectedAddress).length === 0) return - this.selectedAddress = selectedAddress - }) + parentEpml.ready().then(() => { + parentEpml.subscribe('selected_address', async selectedAddress => { + this.selectedAddress = {} + selectedAddress = JSON.parse(selectedAddress) + if (!selectedAddress || Object.entries(selectedAddress).length === 0) return + this.selectedAddress = selectedAddress + }) - parentEpml.subscribe('config', c => { - if (!configLoaded) { - setTimeout(updatePuzzles, 1) - configLoaded = true - } - this.config = JSON.parse(c) - }) + parentEpml.subscribe('config', c => { + if (!configLoaded) { + setTimeout(updatePuzzles, 1) + configLoaded = true + } + this.config = JSON.parse(c) + }) - parentEpml.subscribe('copy_menu_switch', async value => { - if (value === 'false' && window.getSelection().toString().length !== 0) { - this.clearSelection() - } - }) + parentEpml.subscribe('copy_menu_switch', async value => { + if (value === 'false' && window.getSelection().toString().length !== 0) { + this.clearSelection() + } + }) - parentEpml.subscribe('frame_paste_menu_switch', async res => { - res = JSON.parse(res) + parentEpml.subscribe('frame_paste_menu_switch', async res => { + res = JSON.parse(res) - if (res.isOpen === false && this.isPasteMenuOpen === true) { - this.pasteToTextBox(textBox) - this.isPasteMenuOpen = false - } - }) - }) + if (res.isOpen === false && this.isPasteMenuOpen === true) { + this.pasteToTextBox(textBox) + this.isPasteMenuOpen = false + } + }) + }) - parentEpml.imReady() + parentEpml.imReady() - textBox.addEventListener('contextmenu', (event) => { - const getSelectedText = () => { - var text = ""; + textBox.addEventListener('contextmenu', (event) => { + const getSelectedText = () => { + var text = ""; - if (typeof window.getSelection != "undefined") { - text = window.getSelection().toString(); - } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { - text = this.shadowRoot.selection.createRange().text; - } + if (typeof window.getSelection != "undefined") { + text = window.getSelection().toString(); + } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { + text = this.shadowRoot.selection.createRange().text; + } - return text; - } + return text; + } - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText(); + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText(); - if (selectedText && typeof selectedText === 'string') { - // ... - } else { - this.pasteMenu(event) - this.isPasteMenuOpen = true + if (selectedText && typeof selectedText === 'string') { + // ... + } else { + this.pasteMenu(event) + this.isPasteMenuOpen = true - // Prevent Default and Stop Event Bubbling - event.preventDefault() - event.stopPropagation() - } - } + // Prevent Default and Stop Event Bubbling + event.preventDefault() + event.stopPropagation() + } + } - checkSelectedTextAndShowMenu() - }) - } + checkSelectedTextAndShowMenu() + }) + } - async guessPuzzle(puzzle) { - this.selectedPuzzle = puzzle - this.shadowRoot.getElementById("puzzleGuess").value = '' - this.shadowRoot.getElementById("puzzleGuess").checkValidity() - this.message = '' - this.invalid = true + async guessPuzzle(puzzle) { + this.selectedPuzzle = puzzle + this.shadowRoot.getElementById("puzzleGuess").value = '' + this.shadowRoot.getElementById("puzzleGuess").checkValidity() + this.message = '' + this.invalid = true - this.shadowRoot.querySelector('#puzzleGuessDialog').show() - } + this.shadowRoot.querySelector('#puzzleGuessDialog').show() + } - async submitPuzzleGuess(e) { - this.loading = true - this.error = false + async submitPuzzleGuess(e) { + this.loading = true + this.error = false - // Check for valid guess - const guess = this.shadowRoot.getElementById("puzzleGuess").value + // Check for valid guess + const guess = this.shadowRoot.getElementById("puzzleGuess").value - let _rawGuess = Base58.decode(guess) - let _keyPair = nacl.sign.keyPair.fromSeed(_rawGuess) + let _rawGuess = Base58.decode(guess) + let _keyPair = nacl.sign.keyPair.fromSeed(_rawGuess) - let _guessAddress = publicKeyToAddress(_keyPair.publicKey) + let _guessAddress = publicKeyToAddress(_keyPair.publicKey) - console.log("Guess '" + _guessAddress + "' vs puzzle's address '" + this.selectedPuzzle.address + "'") - if (_guessAddress !== this.selectedPuzzle.address) { - this.error = true - this.message = 'Guess incorrect!' - this.loading = false - return - } + console.log("Guess '" + _guessAddress + "' vs puzzle's address '" + this.selectedPuzzle.address + "'") + if (_guessAddress !== this.selectedPuzzle.address) { + this.error = true + this.message = 'Guess incorrect!' + this.loading = false + return + } - // Get Last Ref - const getLastRef = async (address) => { - let myRef = await parentEpml.request('apiCall', { - url: `/addresses/lastreference/${address}` - }) - return myRef - } + // Get Last Ref + const getLastRef = async (address) => { + let myRef = await parentEpml.request('apiCall', { + url: `/addresses/lastreference/${address}` + }) + return myRef + } - let lastRef = await getLastRef(_guessAddress) - let amount = this.selectedPuzzle.reward - DEFAULT_FEE; - let recipientAddress = this.selectedAddress.address - let txnParams = { - recipient: recipientAddress, - amount: amount, - lastReference: lastRef, - fee: DEFAULT_FEE - } + let lastRef = await getLastRef(_guessAddress) + let amount = this.selectedPuzzle.reward - DEFAULT_FEE; + let recipientAddress = this.selectedAddress.address + let txnParams = { + recipient: recipientAddress, + amount: amount, + lastReference: lastRef, + fee: DEFAULT_FEE + } - // Mostly copied from qortal-ui-core/src/plugins/routes.js - let txnResponse = await parentEpml.request('standaloneTransaction', { - type: 2, - keyPair: { - publicKey: _keyPair.publicKey, - privateKey: _keyPair.secretKey - }, - params: txnParams - }) + // Mostly copied from qortal-ui-core/src/plugins/routes.js + let txnResponse = await parentEpml.request('standaloneTransaction', { + type: 2, + keyPair: { + publicKey: _keyPair.publicKey, + privateKey: _keyPair.secretKey + }, + params: txnParams + }) - if (txnResponse.success) { - this.message = 'Reward claim submitted - check wallet for reward!' - } else { - this.error = true - if (txnResponse.data) { - this.message = "Error while claiming reward: " + txnResponse.data.message - } else { - this.message = "Error while claiming reward: " + txnResponse.message - } - } + if (txnResponse.success) { + this.message = 'Reward claim submitted - check wallet for reward!' + } else { + this.error = true + if (txnResponse.data) { + this.message = "Error while claiming reward: " + txnResponse.data.message + } else { + this.message = "Error while claiming reward: " + txnResponse.message + } + } - this.loading = false - } + this.loading = false + } - pasteToTextBox(textBox) { - // Return focus to the window - window.focus() + pasteToTextBox(textBox) { + // Return focus to the window + window.focus() - navigator.clipboard.readText().then(clipboardText => { + navigator.clipboard.readText().then(clipboardText => { - textBox.value += clipboardText - textBox.focus() - }); - } + textBox.value += clipboardText + textBox.focus() + }); + } - pasteMenu(event) { - let eventObject = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } - parentEpml.request('openFramePasteMenu', eventObject) - } + pasteMenu(event) { + let eventObject = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } + parentEpml.request('openFramePasteMenu', eventObject) + } - _textMenu(event) { - const getSelectedText = () => { - var text = ""; - if (typeof window.getSelection != "undefined") { - text = window.getSelection().toString(); - } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { - text = this.shadowRoot.selection.createRange().text; - } - return text; - } + _textMenu(event) { + const getSelectedText = () => { + var text = ""; + if (typeof window.getSelection != "undefined") { + text = window.getSelection().toString(); + } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") { + text = this.shadowRoot.selection.createRange().text; + } + return text; + } - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText(); - if (selectedText && typeof selectedText === 'string') { - let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } - let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } - parentEpml.request('openCopyTextMenu', textMenuObject) - } - } + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText(); + if (selectedText && typeof selectedText === 'string') { + let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } + let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } + parentEpml.request('openCopyTextMenu', textMenuObject) + } + } - checkSelectedTextAndShowMenu() - } + checkSelectedTextAndShowMenu() + } - isEmptyArray(arr) { - if (!arr) { return true } - return arr.length === 0 - } + isEmptyArray(arr) { + if (!arr) { return true } + return arr.length === 0 + } - clearSelection() { - window.getSelection().removeAllRanges() - window.parent.getSelection().removeAllRanges() - } + clearSelection() { + window.getSelection().removeAllRanges() + window.parent.getSelection().removeAllRanges() + } } window.customElements.define('puzzles-info', Puzzles) diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js index 630d8b38..38c921e1 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js @@ -12,23 +12,23 @@ import '@polymer/paper-progress/paper-progress.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class WebBrowser extends LitElement { - static get properties() { - return { - url: { type: String }, - name: { type: String }, - service: { type: String }, - identifier: { type: String }, - followedNames: { type: Array }, - blockedNames: { type: Array }, - } - } + static get properties() { + return { + url: { type: String }, + name: { type: String }, + service: { type: String }, + identifier: { type: String }, + followedNames: { type: Array }, + blockedNames: { type: Array } + } + } - static get observers() { - return ['_kmxKeyUp(amount)'] - } + static get observers() { + return ['_kmxKeyUp(amount)'] + } - static get styles() { - return css` + static get styles() { + return css` * { --mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-secondary: var(--mdc-theme-primary); @@ -40,8 +40,6 @@ class WebBrowser extends LitElement { } #websitesWrapper .buttons { - /* --paper-button-ink-color: var(--paper-green-500); - color: var(--paper-green-500); */ width: auto !important; } @@ -94,10 +92,10 @@ class WebBrowser extends LitElement { } ` - } + } - render() { - return html` + render() { + return html`
@@ -118,9 +116,9 @@ class WebBrowser extends LitElement {
` - } + } - renderFollowUnfollowButton() { + renderFollowUnfollowButton() { // Only show the follow/unfollow button if we have permission to modify the list on this node if (this.followedNames == null || !Array.isArray(this.followedNames)) { return html`` @@ -153,50 +151,50 @@ class WebBrowser extends LitElement { } - // Navigation + // Navigation - goBack() { - window.history.back(); + goBack() { + window.history.back(); } - goForward() { - window.history.forward(); + goForward() { + window.history.forward(); } - refresh() { - window.location.reload(); - } - - goBackToList() { - window.location="../index.html"; + refresh() { + window.location.reload(); } - follow() { - this.followName(this.name); + goBackToList() { + window.location = "../index.html"; } - unfollow() { - this.unfollowName(this.name); + follow() { + this.followName(this.name); } - block() { - this.blockName(this.name); + unfollow() { + this.unfollowName(this.name); } - unblock() { - this.unblockName(this.name); + block() { + this.blockName(this.name); } - delete() { - this.deleteCurrentResource(); + unblock() { + this.unblockName(this.name); + } + + delete() { + this.deleteCurrentResource(); } - async followName(name) { + async followName(name) { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}`, @@ -211,7 +209,7 @@ class WebBrowser extends LitElement { // Successfully followed - add to local list // Remove it first by filtering the list - doing it this way ensures the UI updates // immediately, as apposed to only adding if it doesn't already exist - this.followedNames = this.followedNames.filter(item => item != name); + this.followedNames = this.followedNames.filter(item => item != name); this.followedNames.push(name) } else { @@ -225,7 +223,7 @@ class WebBrowser extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}`, @@ -238,7 +236,7 @@ class WebBrowser extends LitElement { if (ret === true) { // Successfully unfollowed - remove from local list - this.followedNames = this.followedNames.filter(item => item != name); + this.followedNames = this.followedNames.filter(item => item != name); } else { parentEpml.request('showSnackBar', 'Error occurred when trying to unfollow this registered name. Please try again') @@ -251,7 +249,7 @@ class WebBrowser extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, @@ -266,7 +264,7 @@ class WebBrowser extends LitElement { // Successfully blocked - add to local list // Remove it first by filtering the list - doing it this way ensures the UI updates // immediately, as apposed to only adding if it doesn't already exist - this.blockedNames = this.blockedNames.filter(item => item != name); + this.blockedNames = this.blockedNames.filter(item => item != name); this.blockedNames.push(name) } else { @@ -280,7 +278,7 @@ class WebBrowser extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, @@ -293,7 +291,7 @@ class WebBrowser extends LitElement { if (ret === true) { // Successfully unblocked - remove from local list - this.blockedNames = this.blockedNames.filter(item => item != name); + this.blockedNames = this.blockedNames.filter(item => item != name); } else { parentEpml.request('showSnackBar', 'Error occurred when trying to unblock this registered name. Please try again') @@ -302,14 +300,14 @@ class WebBrowser extends LitElement { return ret } - async deleteCurrentResource() { - if (this.followedNames.indexOf(this.name) != -1) { + async deleteCurrentResource() { + if (this.followedNames.indexOf(this.name) != -1) { // Following name - so deleting won't work - parentEpml.request('showSnackBar', "Can't delete data from followed names. Please unfollow first."); - return; + parentEpml.request('showSnackBar', "Can't delete data from followed names. Please unfollow first."); + return; } - let identifier = this.identifier == null ? "default" : resource.identifier; + let identifier = this.identifier == null ? "default" : resource.identifier; let ret = await parentEpml.request('apiCall', { url: `/arbitrary/resource/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`, @@ -328,52 +326,51 @@ class WebBrowser extends LitElement { - // Helper Functions (Re-Used in Most part of the UI ) + // Helper Functions (Re-Used in Most part of the UI ) - textColor(color) { - return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' - } + textColor(color) { + return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' + } - _textMenu(event) { - const getSelectedText = () => { - var text = '' - if (typeof window.getSelection != 'undefined') { - text = window.getSelection().toString() - } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { - text = this.shadowRoot.selection.createRange().text - } - return text - } + _textMenu(event) { + const getSelectedText = () => { + var text = '' + if (typeof window.getSelection != 'undefined') { + text = window.getSelection().toString() + } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { + text = this.shadowRoot.selection.createRange().text + } + return text + } - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText() - if (selectedText && typeof selectedText === 'string') { - let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText() + if (selectedText && typeof selectedText === 'string') { + let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } - let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } + let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } - parentEpml.request('openCopyTextMenu', textMenuObject) - } - } + parentEpml.request('openCopyTextMenu', textMenuObject) + } + } - checkSelectedTextAndShowMenu() - } + checkSelectedTextAndShowMenu() + } - constructor() { - super() - this.url = 'about:blank' + constructor() { + super() + this.url = 'about:blank' - const urlParams = new URLSearchParams(window.location.search); - this.name = urlParams.get('name'); - this.service = urlParams.get('service'); - this.identifier = null; // FUTURE: add support for identifiers - - this.followedNames = [] + const urlParams = new URLSearchParams(window.location.search); + this.name = urlParams.get('name'); + this.service = urlParams.get('service'); + // FUTURE: add support for identifiers + this.identifier = null; + this.followedNames = [] this.blockedNames = [] - const getFollowedNames = async () => { - // this.followedNames = [] + const getFollowedNames = async () => { let followedNames = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}` @@ -384,7 +381,6 @@ class WebBrowser extends LitElement { } const getBlockedNames = async () => { - // this.blockedNames = [] let blockedNames = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}` @@ -394,28 +390,28 @@ class WebBrowser extends LitElement { setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval) } - const render = () => { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port - this.url = `${nodeUrl}/render/${this.service}/${this.name}`; + const render = () => { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + this.url = `${nodeUrl}/render/${this.service}/${this.name}`; } - const authorizeAndRender = () => { + const authorizeAndRender = () => { parentEpml.request('apiCall', { url: `/render/authorize/${this.name}?apiKey=${this.getApiKey()}`, - method: "POST" + method: "POST" }).then(res => { - console.log(res) - if (res.error) { - // Authorization problem - API key incorrect? - } - else { - render() - } + console.log(res) + if (res.error) { + // Authorization problem - API key incorrect? + } + else { + render() + } }) } - let configLoaded = false + let configLoaded = false parentEpml.ready().then(() => { parentEpml.subscribe('selected_address', async selectedAddress => { this.selectedAddress = {} @@ -424,10 +420,10 @@ class WebBrowser extends LitElement { this.selectedAddress = selectedAddress }) parentEpml.subscribe('config', c => { - this.config = JSON.parse(c) + this.config = JSON.parse(c) if (!configLoaded) { authorizeAndRender() - setTimeout(getFollowedNames, 1) + setTimeout(getFollowedNames, 1) setTimeout(getBlockedNames, 1) configLoaded = true } @@ -440,36 +436,36 @@ class WebBrowser extends LitElement { } }) }) - } + } - firstUpdated() { + firstUpdated() { - window.addEventListener('contextmenu', (event) => { - event.preventDefault() - this._textMenu(event) - }) + window.addEventListener('contextmenu', (event) => { + event.preventDefault() + this._textMenu(event) + }) - window.addEventListener('click', () => { - parentEpml.request('closeCopyTextMenu', null) - }) + window.addEventListener('click', () => { + parentEpml.request('closeCopyTextMenu', null) + }) - window.onkeyup = (e) => { - if (e.keyCode === 27) { - parentEpml.request('closeCopyTextMenu', null) - } - } - } + window.onkeyup = (e) => { + if (e.keyCode === 27) { + parentEpml.request('closeCopyTextMenu', null) + } + } + } - getApiKey() { + getApiKey() { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; let apiKey = myNode.apiKey; return apiKey; } - clearSelection() { - window.getSelection().removeAllRanges() - window.parent.getSelection().removeAllRanges() - } + clearSelection() { + window.getSelection().removeAllRanges() + window.parent.getSelection().removeAllRanges() + } } window.customElements.define('web-browser', WebBrowser) diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/index.html b/qortal-ui-plugins/plugins/core/qdn/browser/index.html index d8a117b9..ee932db3 100644 --- a/qortal-ui-plugins/plugins/core/qdn/browser/index.html +++ b/qortal-ui-plugins/plugins/core/qdn/browser/index.html @@ -32,6 +32,7 @@ body { margin: 0; font-family: "Roboto", sans-serif; + background-color: #fff; } diff --git a/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js b/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js index 33b7e0ab..65511611 100644 --- a/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/data-management/data-management.src.js @@ -4,9 +4,8 @@ import { Epml } from '../../../../epml' import '@material/mwc-icon' import '@material/mwc-button' - -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -147,7 +146,7 @@ class DataManagement extends LitElement {

Data hosted by this node

- + { diff --git a/qortal-ui-plugins/plugins/core/qdn/index.html b/qortal-ui-plugins/plugins/core/qdn/index.html index c9192227..b989fca7 100644 --- a/qortal-ui-plugins/plugins/core/qdn/index.html +++ b/qortal-ui-plugins/plugins/core/qdn/index.html @@ -39,7 +39,6 @@ - diff --git a/qortal-ui-plugins/plugins/core/qdn/publish/index.html b/qortal-ui-plugins/plugins/core/qdn/publish/index.html index 484d8dca..41c23a29 100644 --- a/qortal-ui-plugins/plugins/core/qdn/publish/index.html +++ b/qortal-ui-plugins/plugins/core/qdn/publish/index.html @@ -32,6 +32,7 @@ body { margin: 0; font-family: "Roboto", sans-serif; + background-color: #fff; } diff --git a/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js b/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js index 337a4ba5..4287831f 100644 --- a/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js @@ -12,39 +12,37 @@ import '@polymer/paper-progress/paper-progress.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class PublishData extends LitElement { - static get properties() { - return { - name: { type: String }, - service: { type: String }, - identifier: { type: String }, - category: { type: String }, - uploadType: { type: String }, - showName: { type: Boolean }, - showService: { type: Boolean }, - showIdentifier: { type: Boolean }, - serviceLowercase: { type: String }, - names: { type: Array }, - registeredName: { type: String }, - selectedName: { type: String }, - path: { type: String }, - portForwardingEnabled: { type: Boolean }, - //selectedAddress: { type: Object }, + static get properties() { + return { + name: { type: String }, + service: { type: String }, + identifier: { type: String }, + category: { type: String }, + uploadType: { type: String }, + showName: { type: Boolean }, + showService: { type: Boolean }, + showIdentifier: { type: Boolean }, + serviceLowercase: { type: String }, + names: { type: Array }, + registeredName: { type: String }, + selectedName: { type: String }, + path: { type: String }, + portForwardingEnabled: { type: Boolean }, + amount: { type: Number }, + generalMessage: { type: String }, + successMessage: { type: String }, + errorMessage: { type: String }, + loading: { type: Boolean }, + btnDisable: { type: Boolean } + } + } - amount: { type: Number }, - generalMessage: { type: String }, - successMessage: { type: String }, - errorMessage: { type: String }, - loading: { type: Boolean }, - btnDisable: { type: Boolean }, - } - } + static get observers() { + return ['_kmxKeyUp(amount)'] + } - static get observers() { - return ['_kmxKeyUp(amount)'] - } - - static get styles() { - return css` + static get styles() { + return css` * { --mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-secondary: var(--mdc-theme-primary); @@ -56,8 +54,6 @@ class PublishData extends LitElement { } #publishWrapper .buttons { - /* --paper-button-ink-color: var(--paper-green-500); - color: var(--paper-green-500); */ width: auto !important; } @@ -88,10 +84,10 @@ class PublishData extends LitElement { width: 30px; } ` - } + } - render() { - return html` + render() { + return html`
@@ -131,330 +127,330 @@ class PublishData extends LitElement {
` - } + } - // Navigation + // Navigation - goBack() { - window.history.back(); + goBack() { + window.history.back(); } - renderUploadField() { - if (this.uploadType === "file") { - return html`

+ renderUploadField() { + if (this.uploadType === "file") { + return html`

`; - } - else if (this.uploadType === "zip") { - return html`

+ } + else if (this.uploadType === "zip") { + return html`

Select zip file containing static content:

`; - } - else { - return html`

+ } + else { + return html`

`; - } - } + } + } - doPublish(e) { - let registeredName = this.shadowRoot.getElementById('registeredName').value - let service = this.shadowRoot.getElementById('service').value - let identifier = this.shadowRoot.getElementById('identifier').value + doPublish(e) { + let registeredName = this.shadowRoot.getElementById('registeredName').value + let service = this.shadowRoot.getElementById('service').value + let identifier = this.shadowRoot.getElementById('identifier').value - // If name is hidden, use the value passed in via the name parameter - if (!this.showName) { - registeredName = this.name - } + // If name is hidden, use the value passed in via the name parameter + if (!this.showName) { + registeredName = this.name + } - let file; - let path; + let file; + let path; - if (this.uploadType === "file" || this.uploadType === "zip") { - file = this.shadowRoot.getElementById('file').files[0] - } - else if (this.uploadType === "path") { - path = this.shadowRoot.getElementById('path').value - } + if (this.uploadType === "file" || this.uploadType === "zip") { + file = this.shadowRoot.getElementById('file').files[0] + } + else if (this.uploadType === "path") { + path = this.shadowRoot.getElementById('path').value + } - this.generalMessage = '' - this.successMessage = '' - this.errorMessage = '' + this.generalMessage = '' + this.successMessage = '' + this.errorMessage = '' - if (registeredName === '') { - this.showName = true - parentEpml.request('showSnackBar', 'Please select a registered name to publish data for') - } - else if (this.uploadType === "file" && file == null) { - parentEpml.request('showSnackBar', 'Please select a file to host') - } - else if (this.uploadType === "zip" && file == null) { - parentEpml.request('showSnackBar', 'Please select a zip file to host') - } - else if (this.uploadType === "path" && path === '') { - parentEpml.request('showSnackBar', 'Please enter the directory path containing the static content') - } - else if (service === '') { - parentEpml.request('showSnackBar', 'Please enter a service name') - } - else { - this.publishData(registeredName, path, file, service, identifier) - } - } + if (registeredName === '') { + this.showName = true + parentEpml.request('showSnackBar', 'Please select a registered name to publish data for') + } + else if (this.uploadType === "file" && file == null) { + parentEpml.request('showSnackBar', 'Please select a file to host') + } + else if (this.uploadType === "zip" && file == null) { + parentEpml.request('showSnackBar', 'Please select a zip file to host') + } + else if (this.uploadType === "path" && path === '') { + parentEpml.request('showSnackBar', 'Please enter the directory path containing the static content') + } + else if (service === '') { + parentEpml.request('showSnackBar', 'Please enter a service name') + } + else { + this.publishData(registeredName, path, file, service, identifier) + } + } - async publishData(registeredName, path, file, service, identifier) { - this.loading = true - this.btnDisable = true + async publishData(registeredName, path, file, service, identifier) { + this.loading = true + this.btnDisable = true - const validateName = async (receiverName) => { - let nameRes = await parentEpml.request('apiCall', { - type: 'api', - url: `/names/${receiverName}`, - }) + const validateName = async (receiverName) => { + let nameRes = await parentEpml.request('apiCall', { + type: 'api', + url: `/names/${receiverName}`, + }) - return nameRes - } + return nameRes + } - const showError = async (errorMessage) => { - this.loading = false - this.btnDisable = false - this.generalMessage = '' - this.successMessage = '' - console.error(errorMessage) - } + const showError = async (errorMessage) => { + this.loading = false + this.btnDisable = false + this.generalMessage = '' + this.successMessage = '' + console.error(errorMessage) + } - const validate = async () => { - let validNameRes = await validateName(registeredName) - if (validNameRes.error) { - this.errorMessage = "Error: " + validNameRes.message - showError(this.errorMessage) - throw new Error(this.errorMessage); - } + const validate = async () => { + let validNameRes = await validateName(registeredName) + if (validNameRes.error) { + this.errorMessage = "Error: " + validNameRes.message + showError(this.errorMessage) + throw new Error(this.errorMessage); + } - this.generalMessage = "Processing data... this can take some time..."; + this.generalMessage = "Processing data... this can take some time..."; - let transactionBytes = await uploadData(registeredName, path, file) - if (transactionBytes.error) { - this.errorMessage = "Error: " + transactionBytes.message - showError(this.errorMessage) - throw new Error(this.errorMessage); - } - else if (transactionBytes.includes("Error 500 Internal Server Error")) { - this.errorMessage = "Internal Server Error when publishing data" - showError(this.errorMessage) - throw new Error(this.errorMessage); - } + let transactionBytes = await uploadData(registeredName, path, file) + if (transactionBytes.error) { + this.errorMessage = "Error: " + transactionBytes.message + showError(this.errorMessage) + throw new Error(this.errorMessage); + } + else if (transactionBytes.includes("Error 500 Internal Server Error")) { + this.errorMessage = "Internal Server Error when publishing data" + showError(this.errorMessage) + throw new Error(this.errorMessage); + } - this.generalMessage = "Computing proof of work... this can take some time..."; + this.generalMessage = "Computing proof of work... this can take some time..."; - let signAndProcessRes = await signAndProcess(transactionBytes) - if (signAndProcessRes.error) { - this.errorMessage = "Error: " + signAndProcessRes.message - showError(this.errorMessage) - throw new Error(this.errorMessage); - } + let signAndProcessRes = await signAndProcess(transactionBytes) + if (signAndProcessRes.error) { + this.errorMessage = "Error: " + signAndProcessRes.message + showError(this.errorMessage) + throw new Error(this.errorMessage); + } - this.btnDisable = false - this.loading = false - this.errorMessage = '' - this.generalMessage = '' - this.successMessage = 'Transaction successful!' - } + this.btnDisable = false + this.loading = false + this.errorMessage = '' + this.generalMessage = '' + this.successMessage = 'Transaction successful!' + } - const uploadData = async (registeredName, path, file) => { - let postBody = path - let urlSuffix = "" - if (file != null) { + const uploadData = async (registeredName, path, file) => { + let postBody = path + let urlSuffix = "" + if (file != null) { - // If we're sending zipped data, make sure to use the /zip version of the POST /arbitrary/* API - if (this.uploadType === "zip") { - urlSuffix = "/zip" - } - // If we're sending file data, use the /base64 version of the POST /arbitrary/* API - else if (this.uploadType === "file") { - urlSuffix = "/base64" - } + // If we're sending zipped data, make sure to use the /zip version of the POST /arbitrary/* API + if (this.uploadType === "zip") { + urlSuffix = "/zip" + } + // If we're sending file data, use the /base64 version of the POST /arbitrary/* API + else if (this.uploadType === "file") { + urlSuffix = "/base64" + } - // Base64 encode the file to work around compatibility issues between javascript and java byte arrays - let fileBuffer = new Uint8Array(await file.arrayBuffer()) - postBody = Buffer.from(fileBuffer).toString('base64'); - } + // Base64 encode the file to work around compatibility issues between javascript and java byte arrays + let fileBuffer = new Uint8Array(await file.arrayBuffer()) + postBody = Buffer.from(fileBuffer).toString('base64'); + } - let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}` - if (identifier != null && identifier.trim().length > 0) { - uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}` - } + let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}` + if (identifier != null && identifier.trim().length > 0) { + uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}` + } - let uploadDataRes = await parentEpml.request('apiCall', { - type: 'api', - method: 'POST', - url: `${uploadDataUrl}?apiKey=${this.getApiKey()}`, - body: `${postBody}`, - }) + let uploadDataRes = await parentEpml.request('apiCall', { + type: 'api', + method: 'POST', + url: `${uploadDataUrl}?apiKey=${this.getApiKey()}`, + body: `${postBody}`, + }) - return uploadDataRes - } + return uploadDataRes + } - const convertBytesForSigning = async (transactionBytesBase58) => { - let convertedBytes = await parentEpml.request('apiCall', { - type: 'api', - method: 'POST', - url: `/transactions/convert`, - body: `${transactionBytesBase58}`, - }) + const convertBytesForSigning = async (transactionBytesBase58) => { + let convertedBytes = await parentEpml.request('apiCall', { + type: 'api', + method: 'POST', + url: `/transactions/convert`, + body: `${transactionBytesBase58}`, + }) - return convertedBytes - } + return convertedBytes + } - const signAndProcess = async (transactionBytesBase58) => { - let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58) - if (convertedBytesBase58.error) { - this.errorMessage = "Error: " + convertedBytesBase58.message - showError(this.errorMessage) - throw new Error(this.errorMessage); - } - - const convertedBytes = window.parent.Base58.decode(convertedBytesBase58); - const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; }); + const signAndProcess = async (transactionBytesBase58) => { + let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58) + if (convertedBytesBase58.error) { + this.errorMessage = "Error: " + convertedBytesBase58.message + showError(this.errorMessage) + throw new Error(this.errorMessage); + } + + const convertedBytes = window.parent.Base58.decode(convertedBytesBase58); + const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; }); const convertedBytesArray = new Uint8Array(_convertedBytesArray) const convertedBytesHash = new window.parent.Sha256().process(convertedBytesArray).finish().result - const hashPtr = window.parent.sbrk(32, window.parent.heap); - const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32); + const hashPtr = window.parent.sbrk(32, window.parent.heap); + const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32); hashAry.set(convertedBytesHash); const difficulty = 14; const workBufferLength = 8 * 1024 * 1024; const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap); - this.errorMessage = ''; - this.successMessage = ''; - let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty) + this.errorMessage = ''; + this.successMessage = ''; + let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty) - let response = await parentEpml.request('sign_arbitrary', { + let response = await parentEpml.request('sign_arbitrary', { nonce: this.selectedAddress.nonce, arbitraryBytesBase58: transactionBytesBase58, - arbitraryBytesForSigningBase58: convertedBytesBase58, + arbitraryBytesForSigningBase58: convertedBytesBase58, arbitraryNonce: nonce }) - let myResponse = { error: '' } - if (response === false) { - myResponse.error = "Unable to sign and process transaction" - } - else { - myResponse = response - } + let myResponse = { error: '' } + if (response === false) { + myResponse.error = "Unable to sign and process transaction" + } + else { + myResponse = response + } - return myResponse - } + return myResponse + } - validate() - } + validate() + } - // Helper Functions (Re-Used in Most part of the UI ) + // Helper Functions (Re-Used in Most part of the UI ) - textColor(color) { - return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' - } + textColor(color) { + return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' + } - _textMenu(event) { - const getSelectedText = () => { - var text = '' - if (typeof window.getSelection != 'undefined') { - text = window.getSelection().toString() - } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { - text = this.shadowRoot.selection.createRange().text - } - return text - } + _textMenu(event) { + const getSelectedText = () => { + var text = '' + if (typeof window.getSelection != 'undefined') { + text = window.getSelection().toString() + } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { + text = this.shadowRoot.selection.createRange().text + } + return text + } - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText() - if (selectedText && typeof selectedText === 'string') { - let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText() + if (selectedText && typeof selectedText === 'string') { + let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } - let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } + let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } - parentEpml.request('openCopyTextMenu', textMenuObject) - } - } + parentEpml.request('openCopyTextMenu', textMenuObject) + } + } - checkSelectedTextAndShowMenu() - } + checkSelectedTextAndShowMenu() + } - constructor() { - super() + constructor() { + super() - this.showName = false; - this.showService = false - this.showIdentifier = false + this.showName = false; + this.showService = false + this.showIdentifier = false - const urlParams = new URLSearchParams(window.location.search) - this.name = urlParams.get('name') - this.service = urlParams.get('service') - this.identifier = urlParams.get('identifier') - this.category = urlParams.get('category') - this.uploadType = urlParams.get('uploadType') !== "null" ? urlParams.get('uploadType') : "file" + const urlParams = new URLSearchParams(window.location.search) + this.name = urlParams.get('name') + this.service = urlParams.get('service') + this.identifier = urlParams.get('identifier') + this.category = urlParams.get('category') + this.uploadType = urlParams.get('uploadType') !== "null" ? urlParams.get('uploadType') : "file" - if (urlParams.get('showName') === "true") { - this.showName = true - } - if (urlParams.get('showService') === "true") { - this.showService = true - } - if (urlParams.get('showIdentifier') === "true") { - this.showIdentifier = true - } - - if (this.identifier != null) { - if (this.identifier === "null" || this.identifier.trim().length == 0) { - this.identifier = null - } - } + if (urlParams.get('showName') === "true") { + this.showName = true + } + if (urlParams.get('showService') === "true") { + this.showService = true + } + if (urlParams.get('showIdentifier') === "true") { + this.showIdentifier = true + } - this.portForwardingEnabled = true // Default to true so the message doesn't appear and disappear quickly - this.names = [] - this.registeredName = '' - this.selectedName = 'invalid' - this.path = '' - //this.selectedAddress = {} - this.successMessage = '' - this.generalMessage = '' - this.errorMessage = '' - this.loading = false - this.btnDisable = false + if (this.identifier != null) { + if (this.identifier === "null" || this.identifier.trim().length == 0) { + this.identifier = null + } + } - const fetchNames = () => { + // Default to true so the message doesn't appear and disappear quickly + this.portForwardingEnabled = true + this.names = [] + this.registeredName = '' + this.selectedName = 'invalid' + this.path = '' + this.successMessage = '' + this.generalMessage = '' + this.errorMessage = '' + this.loading = false + this.btnDisable = false + + const fetchNames = () => { parentEpml.request('apiCall', { url: `/names/address/${this.selectedAddress.address}?limit=0&reverse=true` }).then(res => { setTimeout(() => { - this.names = res - this.registeredName = res[0].name; - }, 1) + this.names = res + this.registeredName = res[0].name; + }, 1) }) setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval) } - const fetchPeersSummary = () => { + const fetchPeersSummary = () => { parentEpml.request('apiCall', { url: `/peers/summary` }).then(res => { setTimeout(() => { - this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0); - }, 1) + this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0); + }, 1) }) setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval) } - let configLoaded = false + let configLoaded = false parentEpml.ready().then(() => { parentEpml.subscribe('selected_address', async selectedAddress => { this.selectedAddress = {} @@ -465,7 +461,7 @@ class PublishData extends LitElement { parentEpml.subscribe('config', c => { if (!configLoaded) { setTimeout(fetchNames, 1) - setTimeout(fetchPeersSummary, 1) + setTimeout(fetchPeersSummary, 1) configLoaded = true } this.config = JSON.parse(c) @@ -478,41 +474,41 @@ class PublishData extends LitElement { } }) }) - } + } - firstUpdated() { + firstUpdated() { - window.addEventListener('contextmenu', (event) => { - event.preventDefault() - this._textMenu(event) - }) + window.addEventListener('contextmenu', (event) => { + event.preventDefault() + this._textMenu(event) + }) - window.addEventListener('click', () => { - parentEpml.request('closeCopyTextMenu', null) - }) + window.addEventListener('click', () => { + parentEpml.request('closeCopyTextMenu', null) + }) - window.onkeyup = (e) => { - if (e.keyCode === 27) { - parentEpml.request('closeCopyTextMenu', null) - } - } - } + window.onkeyup = (e) => { + if (e.keyCode === 27) { + parentEpml.request('closeCopyTextMenu', null) + } + } + } - selectName(e) { - const name = this.shadowRoot.getElementById('registeredName').innerHTML - this.selectedName = name - } + selectName(e) { + const name = this.shadowRoot.getElementById('registeredName').innerHTML + this.selectedName = name + } - getApiKey() { + getApiKey() { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; let apiKey = myNode.apiKey; return apiKey; } - clearSelection() { - window.getSelection().removeAllRanges() - window.parent.getSelection().removeAllRanges() - } + clearSelection() { + window.getSelection().removeAllRanges() + window.parent.getSelection().removeAllRanges() + } } window.customElements.define('publish-data', PublishData) diff --git a/qortal-ui-plugins/plugins/core/qdn/websites.src.js b/qortal-ui-plugins/plugins/core/qdn/websites.src.js index 60dc9502..cba3c62b 100644 --- a/qortal-ui-plugins/plugins/core/qdn/websites.src.js +++ b/qortal-ui-plugins/plugins/core/qdn/websites.src.js @@ -5,9 +5,8 @@ import { Epml } from '../../../epml.js' import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-textfield' - -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -15,14 +14,14 @@ class Websites extends LitElement { static get properties() { return { service: { type: String }, - identifier: { type: String }, + identifier: { type: String }, loading: { type: Boolean }, resources: { type: Array }, followedNames: { type: Array }, blockedNames: { type: Array }, relayMode: { type: Boolean }, selectedAddress: { type: Object }, - searchName: { type: String }, + searchName: { type: String }, searchResources: { type: Array }, searchFollowedNames: { type: Array }, searchBlockedNames: { type: Array } @@ -159,7 +158,7 @@ class Websites extends LitElement { constructor() { super() this.service = "WEBSITE" - this.identifier = null + this.identifier = null this.selectedAddress = {} this.resources = [] this.followedNames = [] @@ -185,15 +184,15 @@ class Websites extends LitElement {   
Search

- + { - render(html`${this.renderSearchAvatar(data.item)}`, root) + render(html`${this.renderSearchAvatar(data.item)}`, root) }}> { render(html`${this.renderSearchName(data.item)}`, root) }}> { - render(html`${this.renderSearchStatus(data.item)}`, root) + render(html`${this.renderSearchStatus(data.item)}`, root) }}> { render(html`${this.renderSearchSize(data.item)}`, root) @@ -205,10 +204,12 @@ class Websites extends LitElement { render(html`${this.renderSearchBlockUnblockButton(data.item)}`, root); }}>
+
+

Websites

- + { - render(html`${this.renderAvatar(data.item)}`, root) + render(html`${this.renderAvatar(data.item)}`, root) }}> { render(html`${this.renderName(data.item)}`, root) @@ -246,7 +247,7 @@ class Websites extends LitElement { }) this.followedNames = followedNames - setTimeout(getFollowedNames, this.config.user.nodeSettings.pingInterval) + setTimeout(getFollowedNames, 60000) } const getBlockedNames = async () => { @@ -255,7 +256,7 @@ class Websites extends LitElement { }) this.blockedNames = blockedNames - setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval) + setTimeout(getBlockedNames, 60000) } const getSearchFollowedNames = async () => { @@ -264,7 +265,7 @@ class Websites extends LitElement { }) this.searchFollowedNames = searchFollowedNames - setTimeout(getSearchFollowedNames, this.config.user.nodeSettings.pingInterval) + setTimeout(getSearchFollowedNames, 60000) } const getSearchBlockedNames = async () => { @@ -273,7 +274,7 @@ class Websites extends LitElement { }) this.searchBlockedNames = searchBlockedNames - setTimeout(getSearchBlockedNames, this.config.user.nodeSettings.pingInterval) + setTimeout(getSearchBlockedNames, 60000) } const getRelayMode = async () => { @@ -282,7 +283,7 @@ class Websites extends LitElement { }) this.relayMode = relayMode; - setTimeout(getRelayMode, this.config.user.nodeSettings.pingInterval) + setTimeout(getRelayMode, 60000) } @@ -318,7 +319,7 @@ class Websites extends LitElement { setTimeout(getSearchFollowedNames, 1) setTimeout(getSearchBlockedNames, 1) setTimeout(getRelayMode, 1) - setInterval(this.getArbitraryResources, 120 * 1000) + setInterval(this.getArbitraryResources, 120000) configLoaded = true } this.config = JSON.parse(c) @@ -419,13 +420,13 @@ class Websites extends LitElement { } doSearch(e) { - this.searchResult() + this.searchResult() } async searchResult() { let searchName = this.shadowRoot.getElementById('searchName').value if (searchName.length === 0) { - parentEpml.request('showSnackBar', 'Name Can Not Be Empty!') + parentEpml.request('showSnackBar', 'Name Can Not Be Empty!') } else { let searchResources = await parentEpml.request('apiCall', { url: `/arbitrary/resources/search?service=${this.service}&query=${searchName}&default=true&limit=5&reverse=false&includestatus=true` @@ -481,7 +482,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}`, method: 'POST', @@ -491,7 +492,7 @@ class Websites extends LitElement { body: `${namesJsonString}` }) if (ret === true) { - this.searchFollowedNames = this.searchFollowedNames.filter(item => item != name); + this.searchFollowedNames = this.searchFollowedNames.filter(item => item != name); this.searchFollowedNames.push(name) } else { @@ -505,7 +506,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}`, method: 'DELETE', @@ -515,7 +516,7 @@ class Websites extends LitElement { body: `${namesJsonString}` }) if (ret === true) { - this.searchFollowedNames = this.searchFollowedNames.filter(item => item != name); + this.searchFollowedNames = this.searchFollowedNames.filter(item => item != name); } else { parentEpml.request('showSnackBar', 'Error occurred when trying to unfollow this registered name. Please try again') @@ -541,7 +542,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, method: 'POST', @@ -551,7 +552,7 @@ class Websites extends LitElement { body: `${namesJsonString}` }) if (ret === true) { - this.searchBlockedNames = this.searchBlockedNames.filter(item => item != name); + this.searchBlockedNames = this.searchBlockedNames.filter(item => item != name); this.searchBlockedNames.push(name) } else { @@ -565,7 +566,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, method: 'DELETE', @@ -575,7 +576,7 @@ class Websites extends LitElement { body: `${namesJsonString}` }) if (ret === true) { - this.searchBlockedNames = this.searchBlockedNames.filter(item => item != name); + this.searchBlockedNames = this.searchBlockedNames.filter(item => item != name); } else { parentEpml.request('showSnackBar', 'Error occurred when trying to unblock this registered name. Please try again') @@ -619,7 +620,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}`, @@ -634,7 +635,7 @@ class Websites extends LitElement { // Successfully followed - add to local list // Remove it first by filtering the list - doing it this way ensures the UI updates // immediately, as apposed to only adding if it doesn't already exist - this.followedNames = this.followedNames.filter(item => item != name); + this.followedNames = this.followedNames.filter(item => item != name); this.followedNames.push(name) } else { @@ -649,7 +650,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/followedNames?apiKey=${this.getApiKey()}`, @@ -662,7 +663,7 @@ class Websites extends LitElement { if (ret === true) { // Successfully unfollowed - remove from local list - this.followedNames = this.followedNames.filter(item => item != name); + this.followedNames = this.followedNames.filter(item => item != name); } else { parentEpml.request('showSnackBar', 'Error occurred when trying to unfollow this registered name. Please try again') @@ -676,7 +677,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, @@ -691,7 +692,7 @@ class Websites extends LitElement { // Successfully blocked - add to local list // Remove it first by filtering the list - doing it this way ensures the UI updates // immediately, as apposed to only adding if it doesn't already exist - this.blockedNames = this.blockedNames.filter(item => item != name); + this.blockedNames = this.blockedNames.filter(item => item != name); this.blockedNames.push(name) } else { @@ -706,7 +707,7 @@ class Websites extends LitElement { let items = [ name ] - let namesJsonString = JSON.stringify({"items": items}) + let namesJsonString = JSON.stringify({ "items": items }) let ret = await parentEpml.request('apiCall', { url: `/lists/blockedNames?apiKey=${this.getApiKey()}`, @@ -719,7 +720,7 @@ class Websites extends LitElement { if (ret === true) { // Successfully unblocked - remove from local list - this.blockedNames = this.blockedNames.filter(item => item != name); + this.blockedNames = this.blockedNames.filter(item => item != name); } else { parentEpml.request('showSnackBar', 'Error occurred when trying to unblock this registered name. Please try again') @@ -796,7 +797,7 @@ class Websites extends LitElement { if (bytes == 0) return '0 bytes'; var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; - } + } _textMenu(event) { diff --git a/qortal-ui-plugins/plugins/core/reward-share/index.html b/qortal-ui-plugins/plugins/core/reward-share/index.html index 72f42a9d..f0c83c3b 100644 --- a/qortal-ui-plugins/plugins/core/reward-share/index.html +++ b/qortal-ui-plugins/plugins/core/reward-share/index.html @@ -32,14 +32,14 @@ body { margin: 0; font-family: "Roboto", sans-serif; - background: #fff; + background-color: #fff; } - + \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/reward-share/reward-share.src.js b/qortal-ui-plugins/plugins/core/reward-share/reward-share.src.js index 276e5221..c608f584 100644 --- a/qortal-ui-plugins/plugins/core/reward-share/reward-share.src.js +++ b/qortal-ui-plugins/plugins/core/reward-share/reward-share.src.js @@ -7,10 +7,9 @@ import '@material/mwc-button' import '@material/mwc-textfield' import '@material/mwc-dialog' import '@material/mwc-slider' - import '@polymer/paper-spinner/paper-spinner-lite.js' -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -43,6 +42,12 @@ class RewardShare extends LitElement { padding: 12px 24px; } + .divCard { + border: 1px solid #eee; + padding: 1em; + box-shadow: 0 .3px 1px 0 rgba(0,0,0,0.14), 0 1px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20); + } + h2 { margin:0; } @@ -73,18 +78,21 @@ class RewardShare extends LitElement { return html`
-

Rewardshares involving this account

+

Rewardshares

this.shadowRoot.querySelector('#createRewardShareDialog').show()}>addCreate reward share
- - - - - { - render(html`${this.renderRemoveRewardShareButton(data.item)}`, root) - }}> - +
+

Rewardshares Involving In This Account

+ + + + + { + render(html`${this.renderRemoveRewardShareButton(data.item)}`, root) + }}> + +
Level 1 - 4 can create a Self Share and Level 5 or above can create a Reward Share!
@@ -248,7 +256,7 @@ class RewardShare extends LitElement { const recipientPublicKey = this.shadowRoot.getElementById("recipientPublicKey").value const percentageShare = this.shadowRoot.getElementById("rewardSharePercentageSlider").value - // Check for valid...^ + // Check for valid... this.createRewardShareLoading = true let recipientAddress = window.parent.base58PublicKeyToAddress(recipientPublicKey) @@ -339,8 +347,8 @@ class RewardShare extends LitElement { this.error = true this.message = `CANNOT CREATE SELF SHARE! at level ${accountDetails.level}` } - } else { //Check for creating reward shares - + } else { + //Check for creating reward shares if (accountDetails.level >= 5) { this.error = false @@ -402,7 +410,7 @@ class RewardShare extends LitElement { async removeRewardShare(rewardShareObject) { const myPercentageShare = -1 - // Check for valid...^ + // Check for valid... this.removeRewardShareLoading = true // Get Last Ref diff --git a/qortal-ui-plugins/plugins/core/send-coin/index.html b/qortal-ui-plugins/plugins/core/send-coin/index.html index 01fb5b1a..ad6aebd3 100644 --- a/qortal-ui-plugins/plugins/core/send-coin/index.html +++ b/qortal-ui-plugins/plugins/core/send-coin/index.html @@ -32,6 +32,7 @@ body { margin: 0; font-family: "Roboto", sans-serif; + background-color: #fff; } diff --git a/qortal-ui-plugins/plugins/core/send-coin/send-coin.src.js b/qortal-ui-plugins/plugins/core/send-coin/send-coin.src.js index d8daff12..64b402aa 100644 --- a/qortal-ui-plugins/plugins/core/send-coin/send-coin.src.js +++ b/qortal-ui-plugins/plugins/core/send-coin/send-coin.src.js @@ -12,33 +12,33 @@ import '@polymer/paper-progress/paper-progress.js' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) class SendMoneyPage extends LitElement { - static get properties() { - return { - addresses: { type: Array }, - amount: { type: Number }, - errorMessage: { type: String }, - sendMoneyLoading: { type: Boolean }, - btnDisable: { type: Boolean }, - data: { type: Object }, - selectedAddress: { type: Object }, - recipient: { type: String }, - isValidAmount: { type: Boolean }, - balance: { type: Number }, - qortBalance: { type: Number }, - btcBalance: { type: Number }, - ltcBalance: { type: Number }, - dogeBalance: { type: Number }, - selectedCoin: { type: String }, - satFeePerByte: { type: Number } - } - } + static get properties() { + return { + addresses: { type: Array }, + amount: { type: Number }, + errorMessage: { type: String }, + sendMoneyLoading: { type: Boolean }, + btnDisable: { type: Boolean }, + data: { type: Object }, + selectedAddress: { type: Object }, + recipient: { type: String }, + isValidAmount: { type: Boolean }, + balance: { type: Number }, + qortBalance: { type: Number }, + btcBalance: { type: Number }, + ltcBalance: { type: Number }, + dogeBalance: { type: Number }, + selectedCoin: { type: String }, + satFeePerByte: { type: Number } + } + } - static get observers() { - return ['_kmxKeyUp(amount)'] - } + static get observers() { + return ['_kmxKeyUp(amount)'] + } - static get styles() { - return css` + static get styles() { + return css` * { --mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-secondary: var(--mdc-theme-primary); @@ -77,7 +77,6 @@ class SendMoneyPage extends LitElement { .address-icon { border-radius: 50%; border: 5px solid; - /*border-left: 4px solid;*/ padding: 8px; } @@ -133,67 +132,67 @@ class SendMoneyPage extends LitElement { --paper-progress-active-color: var(--mdc-theme-primary); } ` - } + } - constructor() { - super() - this.recipient = '' - this.errorMessage = '' - this.sendMoneyLoading = false - this.btnDisable = false - this.selectedAddress = {} - this.amount = 0 - this.satFeePerByte = 100000 // TODO: Set to 0.001 QORT (100000 in sats) - this.btcSatMinFee = 20 - this.btcSatMaxFee = 150 - this.btcDefaultFee = 100 // 0.000001 BTC per byte - this.ltcSatMinFee = 10 - this.ltcSatMaxFee = 100 - this.ltcDefaultFee = 30 // 0.0000003 LTC per byte - this.dogeSatMinFee = 100 - this.dogeSatMaxFee = 10000 - this.dogeDefaultFee = 1000 // 0.00001 DOGE per byte - this.isValidAmount = false - this.qortBalance = 0 - this.btcBalance = 0 - this.ltcBalance = 0 - this.dogeBalance = 0 - this.selectedCoin = 'invalid' + constructor() { + super() + this.recipient = '' + this.errorMessage = '' + this.sendMoneyLoading = false + this.btnDisable = false + this.selectedAddress = {} + this.amount = 0 + this.satFeePerByte = 100000 // TODO: Set to 0.001 QORT (100000 in sats) + this.btcSatMinFee = 20 + this.btcSatMaxFee = 150 + this.btcDefaultFee = 100 // 0.000001 BTC per byte + this.ltcSatMinFee = 10 + this.ltcSatMaxFee = 100 + this.ltcDefaultFee = 30 // 0.0000003 LTC per byte + this.dogeSatMinFee = 100 + this.dogeSatMaxFee = 10000 + this.dogeDefaultFee = 1000 // 0.00001 DOGE per byte + this.isValidAmount = false + this.qortBalance = 0 + this.btcBalance = 0 + this.ltcBalance = 0 + this.dogeBalance = 0 + this.selectedCoin = 'invalid' - let configLoaded = false - parentEpml.ready().then(() => { - parentEpml.subscribe('selected_address', async (selectedAddress) => { - this.selectedAddress = {} - selectedAddress = JSON.parse(selectedAddress) - if (!selectedAddress || Object.entries(selectedAddress).length === 0) return - this.selectedAddress = selectedAddress - const addr = selectedAddress.address + let configLoaded = false + parentEpml.ready().then(() => { + parentEpml.subscribe('selected_address', async (selectedAddress) => { + this.selectedAddress = {} + selectedAddress = JSON.parse(selectedAddress) + if (!selectedAddress || Object.entries(selectedAddress).length === 0) return + this.selectedAddress = selectedAddress + const addr = selectedAddress.address - this.updateAccountBalance() - }) - parentEpml.subscribe('config', (c) => { - if (!configLoaded) { - configLoaded = true - } - this.config = JSON.parse(c) - }) - parentEpml.subscribe('copy_menu_switch', async (value) => { - if (value === 'false' && window.getSelection().toString().length !== 0) { - this.clearSelection() - } - }) - parentEpml.subscribe('frame_paste_menu_switch', async (res) => { - res = JSON.parse(res) - if (res.isOpen === false && this.isPasteMenuOpen === true) { - this.pasteToTextBox(res.elementId) - this.isPasteMenuOpen = false - } - }) - }) - } + this.updateAccountBalance() + }) + parentEpml.subscribe('config', (c) => { + if (!configLoaded) { + configLoaded = true + } + this.config = JSON.parse(c) + }) + parentEpml.subscribe('copy_menu_switch', async (value) => { + if (value === 'false' && window.getSelection().toString().length !== 0) { + this.clearSelection() + } + }) + parentEpml.subscribe('frame_paste_menu_switch', async (res) => { + res = JSON.parse(res) + if (res.isOpen === false && this.isPasteMenuOpen === true) { + this.pasteToTextBox(res.elementId) + this.isPasteMenuOpen = false + } + }) + }) + } - render() { - return html` + render() { + return html`
@@ -220,7 +219,7 @@ class SendMoneyPage extends LitElement { id="amountInput" required label="Amount (QORT)" - @input="${(e) => {this._checkAmount(e)}}" + @input="${(e) => { this._checkAmount(e) }}" type="number" auto-validate="false" value="${this.amount}" @@ -259,588 +258,588 @@ class SendMoneyPage extends LitElement {
` - } - - firstUpdated() { - // Get BTC Balance - this.updateBTCAccountBalance() - - // Get LTC Balance - this.updateLTCAccountBalance() - - // Get DOGE Balance - this.updateDOGEAccountBalance() - - window.addEventListener('contextmenu', (event) => { - event.preventDefault() - this._textMenu(event) - }) - - window.addEventListener('click', () => { - parentEpml.request('closeCopyTextMenu', null) - }) - - window.onkeyup = (e) => { - if (e.keyCode === 27) { - parentEpml.request('closeCopyTextMenu', null) - } - } - - // TODO: Rewrite the context menu event listener to support more elements (for now, I'll do write everything out manually ) - this.shadowRoot.getElementById('amountInput').addEventListener('contextmenu', (event) => { - const getSelectedText = () => { - var text = '' - if (typeof window.getSelection != 'undefined') { - text = window.getSelection().toString() - } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { - text = this.shadowRoot.selection.createRange().text - } - return text - } - - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText() - if (selectedText && typeof selectedText === 'string') { - } else { - this.pasteMenu(event, 'amountInput') - this.isPasteMenuOpen = true - - // Prevent Default and Stop Event Bubbling - event.preventDefault() - event.stopPropagation() - } - } - checkSelectedTextAndShowMenu() - }) - - this.shadowRoot.getElementById('recipient').addEventListener('contextmenu', (event) => { - const getSelectedText = () => { - var text = '' - if (typeof window.getSelection != 'undefined') { - text = window.getSelection().toString() - } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { - text = this.shadowRoot.selection.createRange().text - } - return text - } - - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText() - if (selectedText && typeof selectedText === 'string') { - } else { - this.pasteMenu(event, 'recipient') - this.isPasteMenuOpen = true - - // Prevent Default and Stop Event Bubbling - event.preventDefault() - event.stopPropagation() - } - } - checkSelectedTextAndShowMenu() - }) - } - - _floor(num) { - return Math.floor(num) - } - - // Helper Functions (Re-Used in Most part of the UI ) - - /** - * Check and Validate Amount Helper Function - * @param { Event } e - * - * @description Gets called oninput in an input element - */ - - _checkAmount(e) { - const targetAmount = e.target.value - const target = e.target - - if (targetAmount.length === 0) { - this.isValidAmount = false - this.btnDisable = true - - // Quick Hack to lose and regain focus inorder to display error message without user having to click outside the input field - e.target.blur() - e.target.focus() - - e.target.invalid = true - e.target.validationMessage = 'Invalid Amount!' - } else { - this.btnDisable = false - } - - e.target.blur() - e.target.focus() - - e.target.validityTransform = (newValue, nativeValidity) => { - if (newValue.includes('-') === true) { - this.btnDisable = true - target.validationMessage = 'Invalid Amount!' - - return { - valid: false, - } - } else if (!nativeValidity.valid) { - if (newValue.includes('.') === true) { - let myAmount = newValue.split('.') - if (myAmount[1].length > 8) { - this.btnDisable = true - target.validationMessage = 'Invalid Amount!' - } else { - return { - valid: true, - } - } - } - } else { - this.btnDisable = false - } - } - } - - textColor(color) { - return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' - } - - pasteToTextBox(elementId) { - // Return focus to the window - window.focus() - - navigator.clipboard.readText().then((clipboardText) => { - let element = this.shadowRoot.getElementById(elementId) - element.value += clipboardText - element.focus() - }) - } - - pasteMenu(event, elementId) { - let eventObject = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY, elementId } - parentEpml.request('openFramePasteMenu', eventObject) - } - - doSend(e) { - if (this.selectedCoin === 'invalid') { - parentEpml.request('showSnackBar', 'Invalid Selection!') - } else if (this.selectedCoin === 'qort') { - this.sendQort() - } else if (this.selectedCoin === 'btc') { - this.sendBtc() - } else if (this.selectedCoin === 'ltc') { - this.sendLtc() - } else if (this.selectedCoin === 'doge') { - this.sendDoge() - } - } - - async sendQort() { - const amount = this.shadowRoot.getElementById('amountInput').value - let recipient = this.shadowRoot.getElementById('recipient').value - - this.sendMoneyLoading = true - this.btnDisable = true - - if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.balance)) { - this.sendMoneyLoading = false - this.btnDisable = false - - parentEpml.request('showSnackBar', 'Insufficient Funds!') - return false - } - - if (parseFloat(amount) <= 0) { - this.sendMoneyLoading = false - this.btnDisable = false - - parentEpml.request('showSnackBar', 'Invalid Amount!') - return false - } - - if (recipient.length === 0) { - this.sendMoneyLoading = false - this.btnDisable = false - - parentEpml.request('showSnackBar', 'Receiver cannot be empty!') - return false - } - - const getLastRef = async () => { - let myRef = await parentEpml.request('apiCall', { - type: 'api', - url: `/addresses/lastreference/${this.selectedAddress.address}`, - }) - return myRef - } - - const validateName = async (receiverName) => { - let myRes - let myNameRes = await parentEpml.request('apiCall', { - type: 'api', - url: `/names/${receiverName}`, - }) - - if (myNameRes.error === 401) { - myRes = false - } else { - myRes = myNameRes - } - - return myRes - } - - const validateAddress = async (receiverAddress) => { - let myAddress = await window.parent.validateAddress(receiverAddress) - return myAddress - } - - const validateReceiver = async (recipient) => { - let lastRef = await getLastRef() - let isAddress - - try { - isAddress = await validateAddress(recipient) - } catch (err) { - isAddress = false - } - - if (isAddress) { - let myTransaction = await makeTransactionRequest(recipient, lastRef) - getTxnRequestResponse(myTransaction) - } else { - let myNameRes = await validateName(recipient) - if (myNameRes !== false) { - let myNameAddress = myNameRes.owner - let myTransaction = await makeTransactionRequest(myNameAddress, lastRef) - getTxnRequestResponse(myTransaction) - } else { - console.error('INVALID_RECEIVER') - this.errorMessage = 'INVALID_RECEIVER' - this.sendMoneyLoading = false - this.btnDisable = false - } - } - } - - const makeTransactionRequest = async (receiver, lastRef) => { - let myReceiver = receiver - let mylastRef = lastRef - - let myTxnrequest = await parentEpml.request('transaction', { - type: 2, - nonce: this.selectedAddress.nonce, - params: { - recipient: myReceiver, - amount: amount, - lastReference: mylastRef, - fee: 0.001, - }, - }) - - return myTxnrequest - } - - const getTxnRequestResponse = (txnResponse) => { - if (txnResponse.success === false && txnResponse.message) { - this.errorMessage = txnResponse.message - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(txnResponse) - } else if (txnResponse.success === true && !txnResponse.data.error) { - this.shadowRoot.getElementById('amountInput').value = '' - this.shadowRoot.getElementById('recipient').value = '' - this.errorMessage = '' - this.recipient = '' - this.amount = 0 - this.successMessage = 'Transaction Successful!' - this.sendMoneyLoading = false - this.btnDisable = false - } else { - this.errorMessage = txnResponse.data.message - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(txnResponse) - } - } - - validateReceiver(recipient) - } - - async sendBtc() { - const amount = this.shadowRoot.getElementById('amountInput').value - let recipient = this.shadowRoot.getElementById('recipient').value - const xprv58 = this.selectedAddress.btcWallet.derivedMasterPrivateKey - - this.sendMoneyLoading = true - this.btnDisable = true - - const makeRequest = async () => { - const opts = { - xprv58: xprv58, - receivingAddress: recipient, - bitcoinAmount: amount, - feePerByte: (this.satFeePerByte / 1e8).toFixed(8), - } - const response = await parentEpml.request('sendBtc', opts) - return response - } - - const manageResponse = (response) => { - if (response.length === 64) { - this.shadowRoot.getElementById('amountInput').value = 0 - this.shadowRoot.getElementById('recipient').value = '' - this.errorMessage = '' - this.recipient = '' - this.amount = 0 - this.successMessage = 'Transaction Successful!' - this.sendMoneyLoading = false - this.btnDisable = false - } else if (response === false) { - this.errorMessage = 'Transaction Failed!' - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(txnResponse) - } else { - this.errorMessage = response.message - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(response) - } - } - - // Call makeRequest - const res = await makeRequest() - manageResponse(res) - } - - async sendLtc() { - const amount = this.shadowRoot.getElementById('amountInput').value - let recipient = this.shadowRoot.getElementById('recipient').value - const xprv58 = this.selectedAddress.ltcWallet.derivedMasterPrivateKey - - this.sendMoneyLoading = true - this.btnDisable = true - - const makeRequest = async () => { - const opts = { - xprv58: xprv58, - receivingAddress: recipient, - litecoinAmount: amount, - feePerByte: (this.satFeePerByte / 1e8).toFixed(8), - } - const response = await parentEpml.request('sendLtc', opts) - return response - } - - const manageResponse = (response) => { - if (response.length === 64) { - this.shadowRoot.getElementById('amountInput').value = 0 - this.shadowRoot.getElementById('recipient').value = '' - this.errorMessage = '' - this.recipient = '' - this.amount = 0 - this.successMessage = 'Transaction Successful!' - this.sendMoneyLoading = false - this.btnDisable = false - } else if (response === false) { - this.errorMessage = 'Transaction Failed!' - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(txnResponse) - } else { - this.errorMessage = response.message - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(response) - } - } - - // Call makeRequest - const res = await makeRequest() - manageResponse(res) - } - - async sendDoge() { - const amount = this.shadowRoot.getElementById('amountInput').value - let recipient = this.shadowRoot.getElementById('recipient').value - const xprv58 = this.selectedAddress.dogeWallet.derivedMasterPrivateKey - - this.sendMoneyLoading = true - this.btnDisable = true - - const makeRequest = async () => { - const opts = { - xprv58: xprv58, - receivingAddress: recipient, - dogecoinAmount: amount, - feePerByte: (this.satFeePerByte / 1e8).toFixed(8), - } - const response = await parentEpml.request('sendDoge', opts) - return response - } - - const manageResponse = (response) => { - if (response.length === 64) { - this.shadowRoot.getElementById('amountInput').value = 0 - this.shadowRoot.getElementById('recipient').value = '' - this.errorMessage = '' - this.recipient = '' - this.amount = 0 - this.successMessage = 'Transaction Successful!' - this.sendMoneyLoading = false - this.btnDisable = false - } else if (response === false) { - this.errorMessage = 'Transaction Failed!' - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(txnResponse) - } else { - this.errorMessage = response.message - this.sendMoneyLoading = false - this.btnDisable = false - throw new Error(response) - } - } - - // Call makeRequest - const res = await makeRequest() - manageResponse(res) - } - - _textMenu(event) { - const getSelectedText = () => { - var text = '' - if (typeof window.getSelection != 'undefined') { - text = window.getSelection().toString() - } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { - text = this.shadowRoot.selection.createRange().text - } - return text - } - - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText() - if (selectedText && typeof selectedText === 'string') { - let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } - - let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } - - parentEpml.request('openCopyTextMenu', textMenuObject) - } - } - - checkSelectedTextAndShowMenu() - } - - updateAccountBalance() { - clearTimeout(this.updateAccountBalanceTimeout) - parentEpml - .request('apiCall', { - url: `/addresses/balance/${this.selectedAddress.address}?apiKey=${this.getApiKey()}`, - }) - .then((res) => { - this.qortBalance = res - this.updateAccountBalanceTimeout = setTimeout(() => this.updateAccountBalance(), 4000) - }) - } - - selectCoin(e) { - const coinType = this.shadowRoot.getElementById('coinType').value - this.selectedCoin = coinType - - this.amount = 0 - this.recipient = '' - this.shadowRoot.getElementById('amountInput').value = 0 - this.shadowRoot.getElementById('recipient').value = '' - this.successMessage = '' - this.errorMessage = '' - - if (coinType === 'qort') { - this.shadowRoot.getElementById('balance').textContent = `${this.qortBalance} QORT` - this.shadowRoot.getElementById('address').textContent = this.selectedAddress.address - this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' - this.shadowRoot.getElementById('amountInput').label = 'Amount (QORT)' - this.shadowRoot.getElementById('recipient').label = 'To (address or name)' - this.satFeePerByte = 100000 - } else if (coinType === 'btc') { - this.shadowRoot.getElementById('balance').textContent = `${this.btcBalance} BTC` - this.shadowRoot.getElementById('address').textContent = this.selectedAddress.btcWallet.address - this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' - this.shadowRoot.getElementById('amountInput').label = 'Amount (BTC)' - this.shadowRoot.getElementById('recipient').label = 'To (BTC address)' - this.shadowRoot.getElementById('feeSlider').min = this.btcSatMinFee - this.shadowRoot.getElementById('feeSlider').max = this.btcSatMaxFee - this.satFeePerByte = this.btcDefaultFee - } else if (coinType === 'ltc') { - this.shadowRoot.getElementById('balance').textContent = `${this.ltcBalance} LTC` - this.shadowRoot.getElementById('address').textContent = this.selectedAddress.ltcWallet.address - this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' - this.shadowRoot.getElementById('amountInput').label = 'Amount (LTC)' - this.shadowRoot.getElementById('recipient').label = 'To (LTC address)' - this.shadowRoot.getElementById('feeSlider').min = this.ltcSatMinFee - this.shadowRoot.getElementById('feeSlider').max = this.ltcSatMaxFee - this.satFeePerByte = this.ltcDefaultFee - } else if (coinType === 'doge') { - this.shadowRoot.getElementById('balance').textContent = `${this.dogeBalance} DOGE` - this.shadowRoot.getElementById('address').textContent = this.selectedAddress.dogeWallet.address - this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' - this.shadowRoot.getElementById('amountInput').label = 'Amount (DOGE)' - this.shadowRoot.getElementById('recipient').label = 'To (DOGE address)' - this.shadowRoot.getElementById('feeSlider').min = this.dogeSatMinFee - this.shadowRoot.getElementById('feeSlider').max = this.dogeSatMaxFee - this.satFeePerByte = this.dogeDefaultFee - } else { - this.selectedCoin = 'invalid' - } - } - - updateBTCAccountBalance() { - parentEpml - .request('apiCall', { - url: `/crosschain/btc/walletbalance?apiKey=${this.getApiKey()}`, - method: 'POST', - body: window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey, - }) - .then((res) => { - if (isNaN(Number(res))) { - parentEpml.request('showSnackBar', 'Failed to Fetch BTC Balance. Try again!') - } else { - this.btcBalance = (Number(res) / 1e8).toFixed(8) - } - }) - } - - updateLTCAccountBalance() { - parentEpml - .request('apiCall', { - url: `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`, - method: 'POST', - body: window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey, - }) - .then((res) => { - if (isNaN(Number(res))) { - parentEpml.request('showSnackBar', 'Failed to Fetch LTC Balance. Try again!') - } else { - this.ltcBalance = (Number(res) / 1e8).toFixed(8) - } - }) - } - - updateDOGEAccountBalance() { - parentEpml - .request('apiCall', { - url: `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`, - method: 'POST', - body: window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey, - }) - .then((res) => { - if (isNaN(Number(res))) { - parentEpml.request('showSnackBar', 'Failed to Fetch DOGE Balance. Try again!') - } else { - this.dogeBalance = (Number(res) / 1e8).toFixed(8) - } - }) - } + } + + firstUpdated() { + // Get BTC Balance + this.updateBTCAccountBalance() + + // Get LTC Balance + this.updateLTCAccountBalance() + + // Get DOGE Balance + this.updateDOGEAccountBalance() + + window.addEventListener('contextmenu', (event) => { + event.preventDefault() + this._textMenu(event) + }) + + window.addEventListener('click', () => { + parentEpml.request('closeCopyTextMenu', null) + }) + + window.onkeyup = (e) => { + if (e.keyCode === 27) { + parentEpml.request('closeCopyTextMenu', null) + } + } + + // TODO: Rewrite the context menu event listener to support more elements (for now, I'll do write everything out manually ) + this.shadowRoot.getElementById('amountInput').addEventListener('contextmenu', (event) => { + const getSelectedText = () => { + var text = '' + if (typeof window.getSelection != 'undefined') { + text = window.getSelection().toString() + } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { + text = this.shadowRoot.selection.createRange().text + } + return text + } + + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText() + if (selectedText && typeof selectedText === 'string') { + } else { + this.pasteMenu(event, 'amountInput') + this.isPasteMenuOpen = true + + // Prevent Default and Stop Event Bubbling + event.preventDefault() + event.stopPropagation() + } + } + checkSelectedTextAndShowMenu() + }) + + this.shadowRoot.getElementById('recipient').addEventListener('contextmenu', (event) => { + const getSelectedText = () => { + var text = '' + if (typeof window.getSelection != 'undefined') { + text = window.getSelection().toString() + } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { + text = this.shadowRoot.selection.createRange().text + } + return text + } + + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText() + if (selectedText && typeof selectedText === 'string') { + } else { + this.pasteMenu(event, 'recipient') + this.isPasteMenuOpen = true + + // Prevent Default and Stop Event Bubbling + event.preventDefault() + event.stopPropagation() + } + } + checkSelectedTextAndShowMenu() + }) + } + + _floor(num) { + return Math.floor(num) + } + + // Helper Functions (Re-Used in Most part of the UI ) + + /** + * Check and Validate Amount Helper Function + * @param { Event } e + * + * @description Gets called oninput in an input element + */ + + _checkAmount(e) { + const targetAmount = e.target.value + const target = e.target + + if (targetAmount.length === 0) { + this.isValidAmount = false + this.btnDisable = true + + // Quick Hack to lose and regain focus inorder to display error message without user having to click outside the input field + e.target.blur() + e.target.focus() + + e.target.invalid = true + e.target.validationMessage = 'Invalid Amount!' + } else { + this.btnDisable = false + } + + e.target.blur() + e.target.focus() + + e.target.validityTransform = (newValue, nativeValidity) => { + if (newValue.includes('-') === true) { + this.btnDisable = true + target.validationMessage = 'Invalid Amount!' + + return { + valid: false, + } + } else if (!nativeValidity.valid) { + if (newValue.includes('.') === true) { + let myAmount = newValue.split('.') + if (myAmount[1].length > 8) { + this.btnDisable = true + target.validationMessage = 'Invalid Amount!' + } else { + return { + valid: true, + } + } + } + } else { + this.btnDisable = false + } + } + } + + textColor(color) { + return color == 'light' ? 'rgba(255,255,255,0.7)' : 'rgba(0,0,0,0.87)' + } + + pasteToTextBox(elementId) { + // Return focus to the window + window.focus() + + navigator.clipboard.readText().then((clipboardText) => { + let element = this.shadowRoot.getElementById(elementId) + element.value += clipboardText + element.focus() + }) + } + + pasteMenu(event, elementId) { + let eventObject = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY, elementId } + parentEpml.request('openFramePasteMenu', eventObject) + } + + doSend(e) { + if (this.selectedCoin === 'invalid') { + parentEpml.request('showSnackBar', 'Invalid Selection!') + } else if (this.selectedCoin === 'qort') { + this.sendQort() + } else if (this.selectedCoin === 'btc') { + this.sendBtc() + } else if (this.selectedCoin === 'ltc') { + this.sendLtc() + } else if (this.selectedCoin === 'doge') { + this.sendDoge() + } + } + + async sendQort() { + const amount = this.shadowRoot.getElementById('amountInput').value + let recipient = this.shadowRoot.getElementById('recipient').value + + this.sendMoneyLoading = true + this.btnDisable = true + + if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.balance)) { + this.sendMoneyLoading = false + this.btnDisable = false + + parentEpml.request('showSnackBar', 'Insufficient Funds!') + return false + } + + if (parseFloat(amount) <= 0) { + this.sendMoneyLoading = false + this.btnDisable = false + + parentEpml.request('showSnackBar', 'Invalid Amount!') + return false + } + + if (recipient.length === 0) { + this.sendMoneyLoading = false + this.btnDisable = false + + parentEpml.request('showSnackBar', 'Receiver cannot be empty!') + return false + } + + const getLastRef = async () => { + let myRef = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/lastreference/${this.selectedAddress.address}`, + }) + return myRef + } + + const validateName = async (receiverName) => { + let myRes + let myNameRes = await parentEpml.request('apiCall', { + type: 'api', + url: `/names/${receiverName}`, + }) + + if (myNameRes.error === 401) { + myRes = false + } else { + myRes = myNameRes + } + + return myRes + } + + const validateAddress = async (receiverAddress) => { + let myAddress = await window.parent.validateAddress(receiverAddress) + return myAddress + } + + const validateReceiver = async (recipient) => { + let lastRef = await getLastRef() + let isAddress + + try { + isAddress = await validateAddress(recipient) + } catch (err) { + isAddress = false + } + + if (isAddress) { + let myTransaction = await makeTransactionRequest(recipient, lastRef) + getTxnRequestResponse(myTransaction) + } else { + let myNameRes = await validateName(recipient) + if (myNameRes !== false) { + let myNameAddress = myNameRes.owner + let myTransaction = await makeTransactionRequest(myNameAddress, lastRef) + getTxnRequestResponse(myTransaction) + } else { + console.error('INVALID_RECEIVER') + this.errorMessage = 'INVALID_RECEIVER' + this.sendMoneyLoading = false + this.btnDisable = false + } + } + } + + const makeTransactionRequest = async (receiver, lastRef) => { + let myReceiver = receiver + let mylastRef = lastRef + + let myTxnrequest = await parentEpml.request('transaction', { + type: 2, + nonce: this.selectedAddress.nonce, + params: { + recipient: myReceiver, + amount: amount, + lastReference: mylastRef, + fee: 0.001, + }, + }) + + return myTxnrequest + } + + const getTxnRequestResponse = (txnResponse) => { + if (txnResponse.success === false && txnResponse.message) { + this.errorMessage = txnResponse.message + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else if (txnResponse.success === true && !txnResponse.data.error) { + this.shadowRoot.getElementById('amountInput').value = '' + this.shadowRoot.getElementById('recipient').value = '' + this.errorMessage = '' + this.recipient = '' + this.amount = 0 + this.successMessage = 'Transaction Successful!' + this.sendMoneyLoading = false + this.btnDisable = false + } else { + this.errorMessage = txnResponse.data.message + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } + } + + validateReceiver(recipient) + } + + async sendBtc() { + const amount = this.shadowRoot.getElementById('amountInput').value + let recipient = this.shadowRoot.getElementById('recipient').value + const xprv58 = this.selectedAddress.btcWallet.derivedMasterPrivateKey + + this.sendMoneyLoading = true + this.btnDisable = true + + const makeRequest = async () => { + const opts = { + xprv58: xprv58, + receivingAddress: recipient, + bitcoinAmount: amount, + feePerByte: (this.satFeePerByte / 1e8).toFixed(8), + } + const response = await parentEpml.request('sendBtc', opts) + return response + } + + const manageResponse = (response) => { + if (response.length === 64) { + this.shadowRoot.getElementById('amountInput').value = 0 + this.shadowRoot.getElementById('recipient').value = '' + this.errorMessage = '' + this.recipient = '' + this.amount = 0 + this.successMessage = 'Transaction Successful!' + this.sendMoneyLoading = false + this.btnDisable = false + } else if (response === false) { + this.errorMessage = 'Transaction Failed!' + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else { + this.errorMessage = response.message + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(response) + } + } + + // Call makeRequest + const res = await makeRequest() + manageResponse(res) + } + + async sendLtc() { + const amount = this.shadowRoot.getElementById('amountInput').value + let recipient = this.shadowRoot.getElementById('recipient').value + const xprv58 = this.selectedAddress.ltcWallet.derivedMasterPrivateKey + + this.sendMoneyLoading = true + this.btnDisable = true + + const makeRequest = async () => { + const opts = { + xprv58: xprv58, + receivingAddress: recipient, + litecoinAmount: amount, + feePerByte: (this.satFeePerByte / 1e8).toFixed(8), + } + const response = await parentEpml.request('sendLtc', opts) + return response + } + + const manageResponse = (response) => { + if (response.length === 64) { + this.shadowRoot.getElementById('amountInput').value = 0 + this.shadowRoot.getElementById('recipient').value = '' + this.errorMessage = '' + this.recipient = '' + this.amount = 0 + this.successMessage = 'Transaction Successful!' + this.sendMoneyLoading = false + this.btnDisable = false + } else if (response === false) { + this.errorMessage = 'Transaction Failed!' + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else { + this.errorMessage = response.message + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(response) + } + } + + // Call makeRequest + const res = await makeRequest() + manageResponse(res) + } + + async sendDoge() { + const amount = this.shadowRoot.getElementById('amountInput').value + let recipient = this.shadowRoot.getElementById('recipient').value + const xprv58 = this.selectedAddress.dogeWallet.derivedMasterPrivateKey + + this.sendMoneyLoading = true + this.btnDisable = true + + const makeRequest = async () => { + const opts = { + xprv58: xprv58, + receivingAddress: recipient, + dogecoinAmount: amount, + feePerByte: (this.satFeePerByte / 1e8).toFixed(8), + } + const response = await parentEpml.request('sendDoge', opts) + return response + } + + const manageResponse = (response) => { + if (response.length === 64) { + this.shadowRoot.getElementById('amountInput').value = 0 + this.shadowRoot.getElementById('recipient').value = '' + this.errorMessage = '' + this.recipient = '' + this.amount = 0 + this.successMessage = 'Transaction Successful!' + this.sendMoneyLoading = false + this.btnDisable = false + } else if (response === false) { + this.errorMessage = 'Transaction Failed!' + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(txnResponse) + } else { + this.errorMessage = response.message + this.sendMoneyLoading = false + this.btnDisable = false + throw new Error(response) + } + } + + // Call makeRequest + const res = await makeRequest() + manageResponse(res) + } + + _textMenu(event) { + const getSelectedText = () => { + var text = '' + if (typeof window.getSelection != 'undefined') { + text = window.getSelection().toString() + } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { + text = this.shadowRoot.selection.createRange().text + } + return text + } + + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText() + if (selectedText && typeof selectedText === 'string') { + let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY } + + let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true } + + parentEpml.request('openCopyTextMenu', textMenuObject) + } + } + + checkSelectedTextAndShowMenu() + } + + updateAccountBalance() { + clearTimeout(this.updateAccountBalanceTimeout) + parentEpml + .request('apiCall', { + url: `/addresses/balance/${this.selectedAddress.address}?apiKey=${this.getApiKey()}`, + }) + .then((res) => { + this.qortBalance = res + this.updateAccountBalanceTimeout = setTimeout(() => this.updateAccountBalance(), 4000) + }) + } + + selectCoin(e) { + const coinType = this.shadowRoot.getElementById('coinType').value + this.selectedCoin = coinType + + this.amount = 0 + this.recipient = '' + this.shadowRoot.getElementById('amountInput').value = 0 + this.shadowRoot.getElementById('recipient').value = '' + this.successMessage = '' + this.errorMessage = '' + + if (coinType === 'qort') { + this.shadowRoot.getElementById('balance').textContent = `${this.qortBalance} QORT` + this.shadowRoot.getElementById('address').textContent = this.selectedAddress.address + this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' + this.shadowRoot.getElementById('amountInput').label = 'Amount (QORT)' + this.shadowRoot.getElementById('recipient').label = 'To (address or name)' + this.satFeePerByte = 100000 + } else if (coinType === 'btc') { + this.shadowRoot.getElementById('balance').textContent = `${this.btcBalance} BTC` + this.shadowRoot.getElementById('address').textContent = this.selectedAddress.btcWallet.address + this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' + this.shadowRoot.getElementById('amountInput').label = 'Amount (BTC)' + this.shadowRoot.getElementById('recipient').label = 'To (BTC address)' + this.shadowRoot.getElementById('feeSlider').min = this.btcSatMinFee + this.shadowRoot.getElementById('feeSlider').max = this.btcSatMaxFee + this.satFeePerByte = this.btcDefaultFee + } else if (coinType === 'ltc') { + this.shadowRoot.getElementById('balance').textContent = `${this.ltcBalance} LTC` + this.shadowRoot.getElementById('address').textContent = this.selectedAddress.ltcWallet.address + this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' + this.shadowRoot.getElementById('amountInput').label = 'Amount (LTC)' + this.shadowRoot.getElementById('recipient').label = 'To (LTC address)' + this.shadowRoot.getElementById('feeSlider').min = this.ltcSatMinFee + this.shadowRoot.getElementById('feeSlider').max = this.ltcSatMaxFee + this.satFeePerByte = this.ltcDefaultFee + } else if (coinType === 'doge') { + this.shadowRoot.getElementById('balance').textContent = `${this.dogeBalance} DOGE` + this.shadowRoot.getElementById('address').textContent = this.selectedAddress.dogeWallet.address + this.shadowRoot.querySelector('.selectedBalance').style.display = 'block' + this.shadowRoot.getElementById('amountInput').label = 'Amount (DOGE)' + this.shadowRoot.getElementById('recipient').label = 'To (DOGE address)' + this.shadowRoot.getElementById('feeSlider').min = this.dogeSatMinFee + this.shadowRoot.getElementById('feeSlider').max = this.dogeSatMaxFee + this.satFeePerByte = this.dogeDefaultFee + } else { + this.selectedCoin = 'invalid' + } + } + + updateBTCAccountBalance() { + parentEpml + .request('apiCall', { + url: `/crosschain/btc/walletbalance?apiKey=${this.getApiKey()}`, + method: 'POST', + body: window.parent.reduxStore.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey, + }) + .then((res) => { + if (isNaN(Number(res))) { + parentEpml.request('showSnackBar', 'Failed to Fetch BTC Balance. Try again!') + } else { + this.btcBalance = (Number(res) / 1e8).toFixed(8) + } + }) + } + + updateLTCAccountBalance() { + parentEpml + .request('apiCall', { + url: `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`, + method: 'POST', + body: window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey, + }) + .then((res) => { + if (isNaN(Number(res))) { + parentEpml.request('showSnackBar', 'Failed to Fetch LTC Balance. Try again!') + } else { + this.ltcBalance = (Number(res) / 1e8).toFixed(8) + } + }) + } + + updateDOGEAccountBalance() { + parentEpml + .request('apiCall', { + url: `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`, + method: 'POST', + body: window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey, + }) + .then((res) => { + if (isNaN(Number(res))) { + parentEpml.request('showSnackBar', 'Failed to Fetch DOGE Balance. Try again!') + } else { + this.dogeBalance = (Number(res) / 1e8).toFixed(8) + } + }) + } getApiKey() { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; diff --git a/qortal-ui-plugins/plugins/core/streams/AddressWatcher.js b/qortal-ui-plugins/plugins/core/streams/AddressWatcher.js index 6859acd0..ac3fbf7c 100644 --- a/qortal-ui-plugins/plugins/core/streams/AddressWatcher.js +++ b/qortal-ui-plugins/plugins/core/streams/AddressWatcher.js @@ -15,20 +15,20 @@ blockTests.push((block, addr) => { }) export class AddressWatcher { - constructor (addresses) { + constructor(addresses) { addresses = addresses || [] this.reset() addresses.forEach(addr => this.addAddress(addr)) } - reset () { + reset() { this._addresses = {} this._addressStreams = {} } // Adds an address to watch - addAddress (address) { + addAddress(address) { const addr = address.address this._addresses[addr] = address @@ -37,7 +37,7 @@ export class AddressWatcher { this.updateAddress(addr) } - async testBlock (block) { + async testBlock(block) { const pendingUpdateAddresses = [] const transactions = await parentEpml.request('apiCall', { url: `/transactions/block/${block.signature}` }) transactions.forEach(transaction => { @@ -57,7 +57,7 @@ export class AddressWatcher { pendingUpdateAddresses.forEach(addr => this.updateAddress(addr)) } - async updateAddress (addr) { + async updateAddress(addr) { let addressRequest = await parentEpml.request('apiCall', { type: 'explorer', data: { diff --git a/qortal-ui-plugins/plugins/core/streams/UnconfirmedTransactionWatcher.js b/qortal-ui-plugins/plugins/core/streams/UnconfirmedTransactionWatcher.js index 82590548..1d95cafd 100644 --- a/qortal-ui-plugins/plugins/core/streams/UnconfirmedTransactionWatcher.js +++ b/qortal-ui-plugins/plugins/core/streams/UnconfirmedTransactionWatcher.js @@ -1,7 +1,7 @@ import { parentEpml } from '../connect.js' export class UnconfirmedTransactionWatcher { - constructor () { + constructor() { this._unconfirmedTransactionStreams = {} this.reset() // Sets defaults @@ -10,13 +10,13 @@ export class UnconfirmedTransactionWatcher { }, 10 * 1000) } - reset () { + reset() { this._addresses = {} this._addressesUnconfirmedTransactions = {} } // Adds an address to watch - addAddress (address) { + addAddress(address) { const addr = address.address this._addresses[addr] = address this._addressesUnconfirmedTransactions[addr] = [] @@ -24,13 +24,13 @@ export class UnconfirmedTransactionWatcher { this._unconfirmedTransactionStreams[addr] = new EpmlStream(`unconfirmedOfAddress/${addr}`, () => this._addressesUnconfirmedTransactions[addr]) } - check () { + check() { const c = this._addressTransactionCheck() .then(() => setTimeout(() => this.check(), 5000)) .catch(() => setTimeout(() => this.check(), 5000)) } - async _addressTransactionCheck () { + async _addressTransactionCheck() { return Promise.all(Object.keys(this._addresses).map(addr => { return parentEpml.request('apiCall', { type: 'api', diff --git a/qortal-ui-plugins/plugins/core/trade-portal/index.html b/qortal-ui-plugins/plugins/core/trade-portal/index.html index 18ec05f4..c888e7e1 100644 --- a/qortal-ui-plugins/plugins/core/trade-portal/index.html +++ b/qortal-ui-plugins/plugins/core/trade-portal/index.html @@ -3,7 +3,6 @@ - - + \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js index 398356f5..336ad4ca 100644 --- a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js +++ b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js @@ -1,46 +1,46 @@ -import { LitElement, html, css } from 'lit'; -import { render } from 'lit/html.js'; -import { Epml } from '../../../epml.js'; +import { LitElement, html, css } from 'lit' +import { render } from 'lit/html.js' +import { Epml } from '../../../epml.js' -import '@material/mwc-button'; -import '@material/mwc-textfield'; -import '@material/mwc-icon-button'; -import '@material/mwc-dialog'; -import '@material/mwc-tab-bar'; -import '@material/mwc-tab'; -import '@material/mwc-list/mwc-list-item'; -import '@material/mwc-select'; -import '@polymer/paper-spinner/paper-spinner-lite.js'; -import '@vaadin/vaadin-grid/vaadin-grid.js'; -import '@vaadin/vaadin-grid/vaadin-grid-sorter'; -import '@vaadin/vaadin-grid/theme/material/all-imports.js'; +import '@material/mwc-button' +import '@material/mwc-textfield' +import '@material/mwc-icon-button' +import '@material/mwc-dialog' +import '@material/mwc-tab-bar' +import '@material/mwc-tab' +import '@material/mwc-list/mwc-list-item' +import '@material/mwc-select' +import '@polymer/paper-spinner/paper-spinner-lite.js' +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/vaadin-grid-sorter' +import '@vaadin/grid/theme/material/all-imports.js' -const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); +const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) let workers = new Map(); class TradePortal extends LitElement { - static get properties() { - return { - selectedAddress: { type: Object }, - config: { type: Object }, - listedCoins: { type: Map }, - sellBtnDisable: { type: Boolean }, - isSellLoading: { type: Boolean }, - isBuyLoading: { type: Boolean }, - buyBtnDisable: { type: Boolean }, - initialAmount: { type: Number }, - cancelBtnDisable: { type: Boolean }, - cancelStuckOfferBtnDisable: { type: Boolean }, - selectedCoin: { type: String }, - isLoadingHistoricTrades: { type: Boolean }, - isLoadingOpenTrades: { type: Boolean }, - isLoadingMyOpenOrders: { type: Boolean }, - } - } + static get properties() { + return { + selectedAddress: { type: Object }, + config: { type: Object }, + listedCoins: { type: Map }, + sellBtnDisable: { type: Boolean }, + isSellLoading: { type: Boolean }, + isBuyLoading: { type: Boolean }, + buyBtnDisable: { type: Boolean }, + initialAmount: { type: Number }, + cancelBtnDisable: { type: Boolean }, + cancelStuckOfferBtnDisable: { type: Boolean }, + selectedCoin: { type: String }, + isLoadingHistoricTrades: { type: Boolean }, + isLoadingOpenTrades: { type: Boolean }, + isLoadingMyOpenOrders: { type: Boolean } + } + } - static get styles() { - return css` + static get styles() { + return css` * { --mdc-theme-primary: rgb(3, 169, 244); --mdc-theme-secondary: var(--mdc-theme-primary); @@ -363,82 +363,82 @@ class TradePortal extends LitElement { } `; - } + } - constructor() { - super() - let qortal = { - name: "QORTAL", - balance: "0", - coinCode: "QORT", - } + constructor() { + super() + let qortal = { + name: "QORTAL", + balance: "0", + coinCode: "QORT", + } - let litecoin = { - name: "LITECOIN", - balance: "0", - coinCode: "LTC", - openOrders: [], - openFilteredOrders: [], - historicTrades: [], - myOrders: [], - myHistoricTrades: [], - myOfferingOrders: [], - openTradeOrders: null, - tradeOffersSocketCounter: 1 - } + let litecoin = { + name: "LITECOIN", + balance: "0", + coinCode: "LTC", + openOrders: [], + openFilteredOrders: [], + historicTrades: [], + myOrders: [], + myHistoricTrades: [], + myOfferingOrders: [], + openTradeOrders: null, + tradeOffersSocketCounter: 1 + } - let dogecoin = { - name: "DOGECOIN", - balance: "0", - coinCode: "DOGE", - openOrders: [], - openFilteredOrders: [], - historicTrades: [], - myOrders: [], - myHistoricTrades: [], - myOfferingOrders: [], - openTradeOrders: null, - tradeOffersSocketCounter: 1 - } + let dogecoin = { + name: "DOGECOIN", + balance: "0", + coinCode: "DOGE", + openOrders: [], + openFilteredOrders: [], + historicTrades: [], + myOrders: [], + myHistoricTrades: [], + myOfferingOrders: [], + openTradeOrders: null, + tradeOffersSocketCounter: 1 + } - this.listedCoins = new Map() - this.listedCoins.set("QORTAL", qortal) - this.listedCoins.set("LITECOIN", litecoin) - this.listedCoins.set("DOGECOIN", dogecoin) + this.listedCoins = new Map() + this.listedCoins.set("QORTAL", qortal) + this.listedCoins.set("LITECOIN", litecoin) + this.listedCoins.set("DOGECOIN", dogecoin) - workers.set("QORTAL", { - tradesConnectedWorker: null, - handleStuckTradesConnectedWorker: null - }) + workers.set("QORTAL", { + tradesConnectedWorker: null, + handleStuckTradesConnectedWorker: null + }) - workers.set("LITECOIN", { - tradesConnectedWorker: null, - handleStuckTradesConnectedWorker: null - }) + workers.set("LITECOIN", { + tradesConnectedWorker: null, + handleStuckTradesConnectedWorker: null + }) - workers.set("DOGECOIN", { - tradesConnectedWorker: null, - handleStuckTradesConnectedWorker: null - }) + workers.set("DOGECOIN", { + tradesConnectedWorker: null, + handleStuckTradesConnectedWorker: null + }) - this.selectedCoin = "LITECOIN" - this.selectedAddress = {} - this.config = {} - this.sellBtnDisable = false - this.isSellLoading = false - this.buyBtnDisable = true - this.isBuyLoading = false - this.initialAmount = 0 - this.cancelBtnDisable = false - this.cancelStuckOfferBtnDisable = false - this.isLoadingHistoricTrades = true - this.isLoadingOpenTrades = true - this.isLoadingMyOpenOrders = false - } + this.selectedCoin = "LITECOIN" + this.selectedAddress = {} + this.config = {} + this.sellBtnDisable = false + this.isSellLoading = false + this.buyBtnDisable = true + this.isBuyLoading = false + this.initialAmount = 0 + this.cancelBtnDisable = false + this.cancelStuckOfferBtnDisable = false + this.isLoadingHistoricTrades = true + this.isLoadingOpenTrades = true + this.isLoadingMyOpenOrders = false + } - // TODO: Move each template to a separate components! Maybe - historicTradesTemplate() { - return html` + // TODO: Move each template to a separate components! Maybe + historicTradesTemplate() { + return html`
HISTORIC MARKET TRADES
@@ -451,9 +451,9 @@ class TradePortal extends LitElement { resizable header="Price (${this.listedCoins.get(this.selectedCoin).coinCode})" .renderer=${(root, column, data) => { - const price = this.round(parseFloat(data.item.foreignAmount) / parseFloat(data.item.qortAmount)) - render(html`${price}`, root) - }} + const price = this.round(parseFloat(data.item.foreignAmount) / parseFloat(data.item.qortAmount)) + render(html`${price}`, root) + }} > { - render(html` ${data.item.foreignAmount} `, root) - }} + render(html` ${data.item.foreignAmount} `, root) + }} > @@ -470,10 +470,10 @@ class TradePortal extends LitElement {
`; - } + } - openTradesTemplate() { - return html` + openTradesTemplate() { + return html`
OPEN MARKET SELL ORDERS
@@ -487,8 +487,8 @@ class TradePortal extends LitElement { id="qortAmountColumn" path="qortAmount" .renderer=${(root, column, data) => { - render(html` ${this.round(data.item.qortAmount)} `, root) - }} + render(html` ${this.round(data.item.qortAmount)} `, root) + }} > { - render(html` ${this.round(data.item.price)} `, root) - }} + render(html` ${this.round(data.item.price)} `, root) + }} > { - render(html` ${data.item.foreignAmount} `, root) - }} + render(html` ${data.item.foreignAmount} `, root) + }} > { - render(html` ${data.item.qortalCreator} `, root) - }} + render(html` ${data.item.qortalCreator} `, root) + }} > @@ -525,10 +525,10 @@ class TradePortal extends LitElement {
`; - } + } - openMarketTemplate() { - return html` + openMarketTemplate() { + return html`
@@ -610,7 +610,7 @@ class TradePortal extends LitElement { id="sellAmountInput" required label="Amount (QORT)" placeholder="0.0000" - @input="${(e) => {this._checkSellAmount(e)}}" + @input="${(e) => { this._checkSellAmount(e) }}" type="number" auto-validate="false" outlined value="${this.initialAmount}" @@ -623,7 +623,7 @@ class TradePortal extends LitElement { id="sellPriceInput" required label="Price Ea. (${this.listedCoins.get(this.selectedCoin).coinCode})" placeholder="0.0000" - @input="${(e) => {this._checkSellAmount(e)}}" + @input="${(e) => { this._checkSellAmount(e) }}" type="number" auto-validate="false" outlined value="${this.initialAmount}" @@ -657,10 +657,10 @@ class TradePortal extends LitElement {
`; - } + } - myOpenOrdersTemplate() { - return html` + myOpenOrdersTemplate() { + return html`
MY ORDERS this.showStuckOrdersDialog()}>
@@ -672,9 +672,9 @@ class TradePortal extends LitElement { resizable header="Date" .renderer=${(root, column, data) => { - const dateString = new Date(data.item.timestamp).toLocaleString() - render(html`${dateString}`, root) - }} + const dateString = new Date(data.item.timestamp).toLocaleString() + render(html`${dateString}`, root) + }} > { - render(html` ${data.item._tradeState} `, root) - }} + render(html` ${data.item._tradeState} `, root) + }} > { - const price = this.round(parseFloat(data.item.foreignAmount) / parseFloat(data.item.qortAmount)) - render(html`${price}`, root) - }} + const price = this.round(parseFloat(data.item.foreignAmount) / parseFloat(data.item.qortAmount)) + render(html`${price}`, root) + }} > { - render(html`${this.renderCancelButton(data.item)}`, root) - }} + render(html`${this.renderCancelButton(data.item)}`, root) + }} > @@ -722,10 +722,10 @@ class TradePortal extends LitElement {
`; - } + } - myHistoricTradesTemplate() { - return html` + myHistoricTradesTemplate() { + return html`
MY TRADE HISTORY
@@ -736,9 +736,9 @@ class TradePortal extends LitElement { resizable header="Date" .renderer=${(root, column, data) => { - const dateString = new Date(data.item.timestamp).toLocaleString() - render(html`${dateString}`, root) - }} + const dateString = new Date(data.item.timestamp).toLocaleString() + render(html`${dateString}`, root) + }} > { - if (data.item.mode === 'SOLD') return render(html` ${data.item.mode} `, root) - if (data.item.mode === 'BOUGHT') return render(html` ${data.item.mode} `, root) - return render(html` ${data.item.mode} `, root) - }} + if (data.item.mode === 'SOLD') return render(html` ${data.item.mode} `, root) + if (data.item.mode === 'BOUGHT') return render(html` ${data.item.mode} `, root) + return render(html` ${data.item.mode} `, root) + }} > { - const price = this.round(parseFloat(data.item.foreignAmount) / parseFloat(data.item.qortAmount)) - render(html`${price}`, root) - }} + const price = this.round(parseFloat(data.item.foreignAmount) / parseFloat(data.item.qortAmount)) + render(html`${price}`, root) + }} > { - render(html` ${data.item.foreignAmount} `, root) - }} + render(html` ${data.item.foreignAmount} `, root) + }} > @@ -782,10 +782,10 @@ class TradePortal extends LitElement {
`; - } + } - render() { - return html` + render() { + return html`

Qortal Trade Portal -  

@@ -823,1275 +823,1275 @@ class TradePortal extends LitElement { Close `; - } + } - firstUpdated() { - let _this = this - + firstUpdated() { + let _this = this + + this.updateWalletBalance() + + setTimeout(() => { + this.displayTabContent('buy') + }, 0) + + // Set Trade Panes + this._openOrdersGrid = this.shadowRoot.getElementById('openOrdersGrid') + this._openOrdersGrid.querySelector('#priceColumn').headerRenderer = function (root) { + root.innerHTML = 'Price (' + _this.listedCoins.get(_this.selectedCoin).coinCode + ')' + } + + this._openOrdersGrid.querySelector('#qortAmountColumn').headerRenderer = function (root) { + root.innerHTML = 'Amount (QORT)' + } + + this._myOrdersGrid = this.shadowRoot.getElementById('myOrdersGrid') + this._historicTradesGrid = this.shadowRoot.getElementById('historicTradesGrid') + this._myHistoricTradesGrid = this.shadowRoot.getElementById('myHistoricTradesGrid') + this._stuckOrdersGrid = this.shadowRoot.getElementById('stuckOrdersGrid') + + this.getOpenOrdersGrid() + + window.addEventListener( + 'contextmenu', + (event) => { + event.preventDefault() + this._textMenu(event) + }, + { passive: true } + ) + + window.addEventListener( + 'click', + () => { + parentEpml.request('closeCopyTextMenu', null) + }, + { passive: true } + ) + + window.onkeyup = (e) => { + if (e.keyCode === 27) parentEpml.request('closeCopyTextMenu', null) + } + + let configLoaded = false + + parentEpml.ready().then(() => { + parentEpml.subscribe('selected_address', async (selectedAddress) => { + this.selectedAddress = {} + selectedAddress = JSON.parse(selectedAddress) + if (!selectedAddress || Object.entries(selectedAddress).length === 0) return + this.selectedAddress = selectedAddress + this.updateAccountBalance() + }) + + parentEpml.subscribe('config', (c) => { + if (!configLoaded) configLoaded = true + this.config = JSON.parse(c) + }) + + parentEpml.subscribe('copy_menu_switch', async (value) => { + if (value === 'false' && window.getSelection().toString().length !== 0) this.clearSelection() + }) + + let coinSelectionMenu = this.shadowRoot.getElementById("coinSelectionMenu") + + coinSelectionMenu.addEventListener('change', function () { + _this.setForeignCoin(coinSelectionMenu.value) + }) + + _this.setForeignCoin(coinSelectionMenu.value) + }) + parentEpml.imReady() + + // Set Last Seen column's title on OpenOrders grid + setTimeout(() => this.shadowRoot.querySelector('[slot="vaadin-grid-cell-content-3"]').setAttribute('title', 'Last Seen'), 3000) + } + + updateWalletBalance() { + let _url = `` + let _body = null + + switch (this.selectedCoin) { + case 'LITECOIN': + _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}` + _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey + break + case 'DOGECOIN': + _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}` + _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey + break + default: + break + } + + parentEpml.request('apiCall', { + url: _url, + method: 'POST', + body: _body, + }) + .then((res) => { + if (isNaN(Number(res))) { + parentEpml.request('showSnackBar', 'Failed to Fetch Balance. Try again!') + } else { + this.listedCoins.get(this.selectedCoin).balance = (Number(res) / 1e8).toFixed(8) + } + }) + } + + setForeignCoin(coin) { + let _this = this + this.selectedCoin = coin + this.isLoadingHistoricTrades = true + this.isLoadingOpenTrades = true + this.createConnection() + this._openOrdersGrid.querySelector('#priceColumn').headerRenderer = function (root) { + root.innerHTML = 'Price (' + _this.listedCoins.get(_this.selectedCoin).coinCode + ')' + } + this.clearSellForm() + this.clearBuyForm() + this.updateWalletBalance() + } + + displayTabContent(tab) { + const tabBuyContent = this.shadowRoot.getElementById('tab-buy-content') + const tabSellContent = this.shadowRoot.getElementById('tab-sell-content') + tabBuyContent.style.display = (tab === 'buy') ? 'block' : 'none' + tabSellContent.style.display = (tab === 'sell') ? 'block' : 'none' + } + + reRenderHistoricTrades() { + this.requestUpdate() + this.isLoadingHistoricTrades = false + } + + reRenderOpenFilteredOrders() { + this.requestUpdate() + this.isLoadingOpenTrades = false + } + + reRenderMyOpenOrders() { + this.requestUpdate() + this.isLoadingMyOpenOrders = false + } + + fillBuyForm(sellerRequest) { + this.shadowRoot.getElementById('buyAmountInput').value = parseFloat(sellerRequest.qortAmount) + this.shadowRoot.getElementById('buyPriceInput').value = this.round(parseFloat(sellerRequest.foreignAmount) / parseFloat(sellerRequest.qortAmount)) + this.shadowRoot.getElementById('buyTotalInput').value = parseFloat(sellerRequest.foreignAmount) + this.shadowRoot.getElementById('qortalAtAddress').value = sellerRequest.qortalAtAddress + this.buyBtnDisable = false + } + + getOpenOrdersGrid() { + const myGrid = this.shadowRoot.querySelector('#openOrdersGrid') + myGrid.addEventListener( + 'click', (e) => { + let myItem = myGrid.getEventContext(e).item + if (myItem !== undefined && myItem.qortalCreator !== this.selectedAddress.address) { + this.fillBuyForm(myItem) + } + }, + { passive: true } + ) + } + + processOfferingTrade(offer) { + const offerItem = { + ...offer, + qortAmount: parseFloat(offer.qortAmount), + price: parseFloat(offer.foreignAmount) / parseFloat(offer.qortAmount), + } + const addOffer = () => { + this.listedCoins.get(this.selectedCoin).openOrders.unshift(offerItem) + } + const initOffer = () => { + this.listedCoins.get(this.selectedCoin).openOrders.push(offerItem) + } + this.listedCoins.get(this.selectedCoin).openOrders.length === 0 ? initOffer() : addOffer() + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null + } + + processRedeemedTrade(offer) { + // If trade is mine, add it to my historic trades and also add it to historic trades + if (offer.qortalCreator === this.selectedAddress.address) { + // Check and Update Wallet Balance + if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { this.updateWalletBalance() - - setTimeout(() => { - this.displayTabContent('buy') - }, 0) - - // Set Trade Panes - this._openOrdersGrid = this.shadowRoot.getElementById('openOrdersGrid') - this._openOrdersGrid.querySelector('#priceColumn').headerRenderer = function (root) { - root.innerHTML = 'Price (' + _this.listedCoins.get(_this.selectedCoin).coinCode + ')' - } - - this._openOrdersGrid.querySelector('#qortAmountColumn').headerRenderer = function (root) { - root.innerHTML = 'Amount (QORT)' - } - - this._myOrdersGrid = this.shadowRoot.getElementById('myOrdersGrid') - this._historicTradesGrid = this.shadowRoot.getElementById('historicTradesGrid') - this._myHistoricTradesGrid = this.shadowRoot.getElementById('myHistoricTradesGrid') - this._stuckOrdersGrid = this.shadowRoot.getElementById('stuckOrdersGrid') - - this.getOpenOrdersGrid() - - window.addEventListener( - 'contextmenu', - (event) => { - event.preventDefault() - this._textMenu(event) - }, - { passive: true } - ) - - window.addEventListener( - 'click', - () => { - parentEpml.request('closeCopyTextMenu', null) - }, - { passive: true } - ) - - window.onkeyup = (e) => { - if (e.keyCode === 27) parentEpml.request('closeCopyTextMenu', null) - } - - let configLoaded = false - - parentEpml.ready().then(() => { - parentEpml.subscribe('selected_address', async (selectedAddress) => { - this.selectedAddress = {} - selectedAddress = JSON.parse(selectedAddress) - if (!selectedAddress || Object.entries(selectedAddress).length === 0) return - this.selectedAddress = selectedAddress - this.updateAccountBalance() - }) - - parentEpml.subscribe('config', (c) => { - if (!configLoaded) configLoaded = true - this.config = JSON.parse(c) - }) - - parentEpml.subscribe('copy_menu_switch', async (value) => { - if (value === 'false' && window.getSelection().toString().length !== 0) this.clearSelection() - }) - - let coinSelectionMenu = this.shadowRoot.getElementById("coinSelectionMenu") - - coinSelectionMenu.addEventListener('change', function () { - _this.setForeignCoin(coinSelectionMenu.value) - }) - - _this.setForeignCoin(coinSelectionMenu.value) - }) - parentEpml.imReady() - - // Set Last Seen column's title on OpenOrders grid - setTimeout(() => this.shadowRoot.querySelector('[slot="vaadin-grid-cell-content-3"]').setAttribute('title', 'Last Seen'), 3000) - } - - updateWalletBalance() { - let _url = `` - let _body = null - - switch (this.selectedCoin) { - case 'LITECOIN': - _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}` - _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey - break - case 'DOGECOIN': - _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}` - _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey - break - default: - break - } - - parentEpml.request('apiCall', { - url: _url, - method: 'POST', - body: _body, - }) - .then((res) => { - if (isNaN(Number(res))) { - parentEpml.request('showSnackBar', 'Failed to Fetch Balance. Try again!') - } else { - this.listedCoins.get(this.selectedCoin).balance = (Number(res) / 1e8).toFixed(8) - } - }) - } - - setForeignCoin(coin) { - let _this = this - this.selectedCoin = coin - this.isLoadingHistoricTrades = true - this.isLoadingOpenTrades = true - this.createConnection() - this._openOrdersGrid.querySelector('#priceColumn').headerRenderer = function (root) { - root.innerHTML = 'Price (' + _this.listedCoins.get(_this.selectedCoin).coinCode + ')' - } - this.clearSellForm() - this.clearBuyForm() - this.updateWalletBalance() - } - - displayTabContent(tab) { - const tabBuyContent = this.shadowRoot.getElementById('tab-buy-content') - const tabSellContent = this.shadowRoot.getElementById('tab-sell-content') - tabBuyContent.style.display = (tab === 'buy') ? 'block' : 'none' - tabSellContent.style.display = (tab === 'sell') ? 'block' : 'none' - } - - reRenderHistoricTrades() { - this.requestUpdate() - this.isLoadingHistoricTrades = false - } - - reRenderOpenFilteredOrders() { - this.requestUpdate() - this.isLoadingOpenTrades = false - } - - reRenderMyOpenOrders() { - this.requestUpdate() - this.isLoadingMyOpenOrders = false - } - - fillBuyForm(sellerRequest) { - this.shadowRoot.getElementById('buyAmountInput').value = parseFloat(sellerRequest.qortAmount) - this.shadowRoot.getElementById('buyPriceInput').value = this.round(parseFloat(sellerRequest.foreignAmount) / parseFloat(sellerRequest.qortAmount)) - this.shadowRoot.getElementById('buyTotalInput').value = parseFloat(sellerRequest.foreignAmount) - this.shadowRoot.getElementById('qortalAtAddress').value = sellerRequest.qortalAtAddress - this.buyBtnDisable = false - } - - getOpenOrdersGrid() { - const myGrid = this.shadowRoot.querySelector('#openOrdersGrid') - myGrid.addEventListener( - 'click', (e) => { - let myItem = myGrid.getEventContext(e).item - if (myItem !== undefined && myItem.qortalCreator !== this.selectedAddress.address) { - this.fillBuyForm(myItem) - } - }, - { passive: true } - ) - } - - processOfferingTrade(offer) { - const offerItem = { - ...offer, - qortAmount: parseFloat(offer.qortAmount), - price: parseFloat(offer.foreignAmount) / parseFloat(offer.qortAmount), - } - const addOffer = () => { - this.listedCoins.get(this.selectedCoin).openOrders.unshift(offerItem) - } - const initOffer = () => { - this.listedCoins.get(this.selectedCoin).openOrders.push(offerItem) - } - this.listedCoins.get(this.selectedCoin).openOrders.length === 0 ? initOffer() : addOffer() - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null - } - - processRedeemedTrade(offer) { - // If trade is mine, add it to my historic trades and also add it to historic trades - if (offer.qortalCreator === this.selectedAddress.address) { - // Check and Update Wallet Balance - if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { - this.updateWalletBalance() - } - const offerItem = { - ...offer, - mode: 'SOLD', - } - // Add to my historic trades - this._myHistoricTradesGrid.items.unshift(offerItem) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null - } else if (offer.partnerQortalReceivingAddress === this.selectedAddress.address) { - // Check and Update Wallet Balance - if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { - this.updateWalletBalance() - } - const offerItem = { - ...offer, - mode: 'BOUGHT', - } - // Add to my historic trades - this._myHistoricTradesGrid.items.unshift(offerItem) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null - } - // Add to historic trades - const addNewHistoricTrade = () => { - this._historicTradesGrid.items.unshift(offer) - this._historicTradesGrid.clearCache() - } - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? addNewHistoricTrade() : null - } - - processTradingTrade(offer) { - // Remove from open market orders - if (offer.qortalCreator === this.selectedAddress.address && this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { - // Check and Update Wallet Balance - this.updateWalletBalance() - } - this._openOrdersGrid.items.forEach((item, index) => { - if (item.qortalAtAddress === offer.qortalAtAddress) { - this._openOrdersGrid.items.splice(index, 1) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null - } - }) - this.listedCoins.get(this.selectedCoin).openOrders = this.listedCoins.get(this.selectedCoin).openOrders.filter((order) => order.qortalAtAddress !== offer.qortalAtAddress) - } - - processRefundedTrade(offer) { - if (offer.qortalCreator === this.selectedAddress.address) { - // Check and Update Wallet Balance - if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { - this.updateWalletBalance() - } - // Add to my historic trades - this._myHistoricTradesGrid.items.unshift(offer) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null - } - } - - processCancelledTrade(offer) { - if (offer.qortalCreator === this.selectedAddress.address) { - // Check and Update Wallet Balance - if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { - this.updateWalletBalance() - } - // Add to my historic trades - this._myHistoricTradesGrid.items.unshift(offer) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null - } - this._openOrdersGrid.items.forEach((item, index) => { - if (item.qortalAtAddress === offer.qortalAtAddress) { - this._openOrdersGrid.items.splice(index, 1) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null - } - }) - this.listedCoins.get(this.selectedCoin).openOrders = this.listedCoins.get(this.selectedCoin).openOrders.filter((order) => order.qortalAtAddress !== offer.qortalAtAddress) - this._stuckOrdersGrid.items.forEach((item, index) => { - if (item.qortalAtAddress === offer.qortalAtAddress) { - this._stuckOrdersGrid.items.splice(index, 1) - this._stuckOrdersGrid.clearCache() - } - }) - } - - /** - * TRADE OFFER STATES or MODE - * - OFFERING - * - REDEEMED - * - TRADING - * - REFUNDED - * - CANCELLED - */ - - processTradeOffers(offers) { - offers.forEach((offer) => { - if (offer.mode === 'OFFERING') { - this.processOfferingTrade(offer) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null - } else if (offer.mode === 'REDEEMED') { - this.processRedeemedTrade(offer) - } else if (offer.mode === 'TRADING') { - this.processTradingTrade(offer) - } else if (offer.mode === 'REFUNDED') { - this.processRefundedTrade(offer) - } else if (offer.mode === 'CANCELLED') { - this.processCancelledTrade(offer) - } - }) - } - - /** - * TradeBot Note by cat - * - * trade-bot entry states: - * - when you do /crosschain/tradebot/create, - * - it returns unsigned DEPLOY_AT for you to sign & broadcast - * - so initial trade-bot state is BOB_WAITING_FOR_AT_CONFIRM, because trade-bot is waiting for UI to sign & broadcast txn and for that txn to be confirmed into a block - * - once that happens & Bob's trade-bot notices that DEPLOY_AT has confirmed (and hence AT created and running), then it switches to BOB_WAITING_FOR_MESSAGE - * - which is Bob's trade-bot waiting for a message from Alice's trade-bot telling it (Bob's trade-bot) that Alice's trade-bot has funded P2SH-A and some other details - * - when that message is sent, Bob's trade-bot processes that message and sends its own message to the AT (which switches it to TRADING mode) - * - but the next state for Bob's trade-bot is to wait for Alice to spot AT is locked to her and for her to fund P2SH-B, hence BOB_WAITING_FOR_P2SH_B - * - at this point, Bob's trade-bot finds P2SH-B on the litecoin blockchain and can send secret-B to P2SH-B - * - when this happens, Alice uses secret-B and secret-A to redeem the QORT from the AT, so until Alice does this, Bob's trade-bot state is BOB_WAITING_FOR_AT_REDEEM - * - after Alice redeems QORT from AT, Bob can extract secret-A and capture the actual LTC funds from P2SH-A to his own litecoin account and hence his trade-bot moves to BOB_DONE - * - if anything goes wrong then refunds occur and Bob's trade-bot ends up at BOB_REFUNDED instead - * - I think you can probably guess the corresponding meaning of states for Alice's point of view, but if not I can go through those too? - * - Alice calls /crosschain/tradebot/respond which funds P2SH-A - * - so her trade-bot waits for that to appear in litecoin blockchain, so until then is ALICE_WAITING_FOR_P2SH_A - * - once the P2SH-A funding confirms, Alice's trade-bot can MESSAGE Bob's trade-bot with the details and changes to ALICE_WAITING_FOR_AT_LOCK - * - Bob's AT should then lock to trading with Alice (via those MESSAGEs above) and Alice's trade-bot notices this, (minimally) funds P2SH-B and waits until Bob 'spends' P2SH-B, hence ALICE_WATCH_P2SH_B - * - if Bob spends P2SH-B, then Alice can send secret-B and secret-A to the AT, claim the QORT and she's ALICE_DONE - * - if something goes wrong then her trade-bot needs to refund P2SH-B (if applicable) first (ALICE_REFUNDING_B) - * - and when that's done refund P2SH-A (ALICE_REFUNDING_A) - * - and when that's done her trade-bot ends up at ALICE_REFUNDED - * - * (PHEW) - */ - - processTradeBotStates(tradeStates) { - - /** - * BitcoinACCTv1 TRADEBOT STATES - * - BOB_WAITING_FOR_AT_CONFIRM - * - BOB_WAITING_FOR_MESSAGE - * - BOB_WAITING_FOR_P2SH_B - * - BOB_WAITING_FOR_AT_REDEEM - * - BOB_DONE - * - BOB_REFUNDED - * - ALICE_WAITING_FOR_P2SH_A - * - ALICE_WAITING_FOR_AT_LOCK - * - ALICE_WATCH_P2SH_B - * - ALICE_DONE - * - ALICE_REFUNDING_B - * - ALICE_REFUNDING_A - * - ALICE_REFUNDED - * - * @param {[{}]} states - */ - - const BitcoinACCTv1 = (states) => { - // Reverse the states - states.reverse() - states.forEach((state) => { - if (state.creatorAddress === this.selectedAddress.address) { - if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { - this.changeTradeBotState(state, 'PENDING') - } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { - this.changeTradeBotState(state, 'LISTED') - } else if (state.tradeState == 'BOB_WAITING_FOR_P2SH_B') { - this.changeTradeBotState(state, 'TRADING') - } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { - this.changeTradeBotState(state, 'REDEEMING') - } else if (state.tradeState == 'BOB_DONE') { - this.handleCompletedState(state) - } else if (state.tradeState == 'BOB_REFUNDED') { - this.handleCompletedState(state) - } else if (state.tradeState == 'ALICE_WAITING_FOR_P2SH_A') { - this.changeTradeBotState(state, 'PENDING') - } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { - this.changeTradeBotState(state, 'TRADING') - } else if (state.tradeState == 'ALICE_WATCH_P2SH_B') { - this.changeTradeBotState(state, 'TRADING') - } else if (state.tradeState == 'ALICE_DONE') { - this.handleCompletedState(state) - } else if (state.tradeState == 'ALICE_REFUNDING_B') { - this.changeTradeBotState(state, 'REFUNDING') - } else if (state.tradeState == 'ALICE_REFUNDING_A') { - this.changeTradeBotState(state, 'REFUNDING') - } else if (state.tradeState == 'ALICE_REFUNDED') { - this.handleCompletedState(state) - } - } - }) - } - - /** - * LitecoinACCTv1 TRADEBOT STATES - * - BOB_WAITING_FOR_AT_CONFIRM - * - BOB_WAITING_FOR_MESSAGE - * - BOB_WAITING_FOR_AT_REDEEM - * - BOB_DONE - * - BOB_REFUNDED - * - ALICE_WAITING_FOR_AT_LOCK - * - ALICE_DONE - * - ALICE_REFUNDING_A - * - ALICE_REFUNDED - * - * @param {[{}]} states - */ - - const LitecoinACCTv1 = (states) => { - // Reverse the states - states.reverse() - states.forEach((state) => { - if (state.creatorAddress === this.selectedAddress.address) { - if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { - this.changeTradeBotState(state, 'PENDING') - } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { - this.changeTradeBotState(state, 'LISTED') - } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { - this.changeTradeBotState(state, 'TRADING') - } else if (state.tradeState == 'BOB_DONE') { - this.handleCompletedState(state) - } else if (state.tradeState == 'BOB_REFUNDED') { - this.handleCompletedState(state) - } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { - this.changeTradeBotState(state, 'BUYING') - } else if (state.tradeState == 'ALICE_DONE') { - this.handleCompletedState(state) - } else if (state.tradeState == 'ALICE_REFUNDING_A') { - this.changeTradeBotState(state, 'REFUNDING') - } else if (state.tradeState == 'ALICE_REFUNDED') { - this.handleCompletedState(state) - } - } - }) - } - - /** - * DogecoinACCTv1 TRADEBOT STATES - * - BOB_WAITING_FOR_AT_CONFIRM - * - BOB_WAITING_FOR_MESSAGE - * - BOB_WAITING_FOR_AT_REDEEM - * - BOB_DONE - * - BOB_REFUNDED - * - ALICE_WAITING_FOR_AT_LOCK - * - ALICE_DONE - * - ALICE_REFUNDING_A - * - ALICE_REFUNDED - * - * @param {[{}]} states - */ - - const DogecoinACCTv1 = (states) => { - // Reverse the states - states.reverse() - states.forEach((state) => { - if (state.creatorAddress === this.selectedAddress.address) { - if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { - this.changeTradeBotState(state, 'PENDING') - } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { - this.changeTradeBotState(state, 'LISTED') - } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { - this.changeTradeBotState(state, 'TRADING') - } else if (state.tradeState == 'BOB_DONE') { - this.handleCompletedState(state) - } else if (state.tradeState == 'BOB_REFUNDED') { - this.handleCompletedState(state) - } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { - this.changeTradeBotState(state, 'BUYING') - } else if (state.tradeState == 'ALICE_DONE') { - this.handleCompletedState(state) - } else if (state.tradeState == 'ALICE_REFUNDING_A') { - this.changeTradeBotState(state, 'REFUNDING') - } else if (state.tradeState == 'ALICE_REFUNDED') { - this.handleCompletedState(state) - } - } - }) - } - - switch (this.selectedCoin) { - case 'BITCOIN': - BitcoinACCTv1(tradeStates) - break - case 'LITECOIN': - LitecoinACCTv1(tradeStates) - break - case 'DOGECOIN': - DogecoinACCTv1(tradeStates) - break - default: - break - } - - // Fill Historic Trades and Filter Stuck Trades - if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter === 1) { - setTimeout(() => this.filterStuckTrades(tradeStates), 50) - } - } - - changeTradeBotState(state, tradeState) { - // Set Loading state - this.isLoadingMyOpenOrders = true - const stateItem = { - ...state, - _tradeState: tradeState, - } - const item = this._myOrdersGrid.querySelector(`#${state.atAddress}`) - const addStateItem = () => { - this.reRenderMyOpenOrders() - this._myOrdersGrid.items.unshift(stateItem) - this._myOrdersGrid.clearCache() - } - const updateStateItem = () => { - this._myOrdersGrid.items.forEach((item, index) => { - if (item.atAddress === state.atAddress) { - this._myOrdersGrid.items.splice(index, 1) - this._myOrdersGrid.items.unshift(stateItem) - this._myOrdersGrid.clearCache() - } - }) - } - item ? updateStateItem() : addStateItem() - } - - // ONLY USE FOR BOB_DONE, BOB_REFUNDED, ALICE_DONE, ALICE_REFUNDED - handleCompletedState(state) { - this._myOrdersGrid.items.forEach((item, index) => { - if (item.atAddress === state.atAddress) { - this._myOrdersGrid.items.splice(index, 1) - this._myOrdersGrid.clearCache() - } - }) - } - - initSocket() { - let _relatedCoin = "" - let presenceTxns = null - let offeringTrades = null - let filteredOffers = [] - - self.addEventListener('message', function (event) { - switch (event.data.type) { - case 'open_orders': - offeringTrades = event.data.content - handleOfferingTrades() - break - case 'set_coin': - _relatedCoin = event.data.content - break - default: - break - } - }) - - const lessThanThirtyMinsAgo = (timestamp) => { - const THIRTYMINS = 1000 * 60 * 30 - const thirtyMinsAgo = Date.now() - THIRTYMINS - return timestamp > thirtyMinsAgo - } - - const processOffersWithPresence = () => { - const waitFor = (ms) => new Promise((r) => setTimeout(r, ms)) - async function asyncForEach(array, callback) { - for (let index = 0; index < array.length; index++) { - await callback(array[index], index, array) - } - } - const startOfferPresenceMapping = async () => { - await asyncForEach(presenceTxns, async (presence) => { - await waitFor(5) - let offerIndex = offeringTrades.findIndex((offeringTrade) => offeringTrade.qortalCreatorTradeAddress === presence.address) - offerIndex !== -1 ? (offeringTrades[offerIndex].lastSeen = presence.timestamp) : null - }) - filteredOffers = offeringTrades.filter((offeringTrade) => lessThanThirtyMinsAgo(offeringTrade.lastSeen)) - self.postMessage({ type: 'PRESENCE', data: { offers: offeringTrades, filteredOffers: filteredOffers, relatedCoin: _relatedCoin } }) - filteredOffers = [] - } - startOfferPresenceMapping() - } - - const handleOfferingTrades = () => { - if (presenceTxns === null) return - processOffersWithPresence() - } - - const handlePresence = () => { - if (offeringTrades === null) return - processOffersWithPresence() - } - - const initTradeOffersWebSocket = (restarted = false) => { - let tradeOffersSocketCounter = 0 - let socketTimeout - let socketLink = `ws://NODEURL/websockets/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN&includeHistoric=true` - const socket = new WebSocket(socketLink) - // Open Connection - socket.onopen = () => { - setTimeout(pingSocket, 50) - tradeOffersSocketCounter += 1 - } - // Message Event - socket.onmessage = (e) => { - e.relatedCoin = _relatedCoin - self.postMessage({ - type: 'TRADE_OFFERS', - data: e.data, - counter: tradeOffersSocketCounter, - isRestarted: restarted, - }) - tradeOffersSocketCounter += 1 - restarted = false - } - // Closed Event - socket.onclose = () => { - clearTimeout(socketTimeout) - // Restart Socket Connection - restartTradeOffersWebSocket() - } - // Error Event - socket.onerror = (e) => { - clearTimeout(socketTimeout) - } - const pingSocket = () => { - socket.send('ping') - socketTimeout = setTimeout(pingSocket, 295000) - } - } - - const initTradeBotWebSocket = (restarted = false) => { - let socketTimeout - let socketLink = `ws://NODEURL/websockets/crosschain/tradebot?foreignBlockchain=FOREIGN_BLOCKCHAIN` - const socket = new WebSocket(socketLink) - // Open Connection - socket.onopen = () => { - setTimeout(pingSocket, 50) - } - // Message Event - socket.onmessage = (e) => { - e.relatedCoin = _relatedCoin - self.postMessage({ - type: 'TRADE_BOT', - data: e.data, - isRestarted: restarted, - }) - restarted = false - } - // Closed Event - socket.onclose = () => { - clearTimeout(socketTimeout) - // Restart Socket Connection - restartTradeBotWebSocket() - } - // Error Event - socket.onerror = (e) => { - clearTimeout(socketTimeout) - } - const pingSocket = () => { - socket.send('ping') - socketTimeout = setTimeout(pingSocket, 295000) - } - } - - const initPresenceWebSocket = (restarted = false) => { - let socketTimeout - let socketLink = `ws://NODEURL/websockets/presence?presenceType=TRADE_BOT` - const socket = new WebSocket(socketLink) - // Open Connection - socket.onopen = () => { - setTimeout(pingSocket, 50) - } - // Message Event - socket.onmessage = (e) => { - presenceTxns = JSON.parse(e.data) - handlePresence() - restarted = false - } - // Closed Event - socket.onclose = () => { - clearTimeout(socketTimeout) - // Restart Socket Connection - restartPresenceWebSocket() - } - // Error Event - socket.onerror = (e) => { - clearTimeout(socketTimeout) - } - const pingSocket = () => { - socket.send('ping') - socketTimeout = setTimeout(pingSocket, 295000) - } - } - - const restartPresenceWebSocket = () => { - setTimeout(() => initPresenceWebSocket(true), 3000) - } - - const restartTradeOffersWebSocket = () => { - setTimeout(() => initTradeOffersWebSocket(true), 3000) - } - - const restartTradeBotWebSocket = () => { - setTimeout(() => initTradeBotWebSocket(true), 3000) - } - - // Start TradeOffersWebSocket - initTradeOffersWebSocket() - - // Start PresenceWebSocket - initPresenceWebSocket() - - // Start TradeBotWebSocket - initTradeBotWebSocket() - } - - async sellAction() { - this.isSellLoading = true - this.sellBtnDisable = true - const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value - const sellTotalInput = this.shadowRoot.getElementById('sellTotalInput').value - const fundingQortAmount = this.round(parseFloat(sellAmountInput) + 0.001) - - const makeRequest = async () => { - let _receivingAddress = null - switch (this.selectedCoin) { - case 'LITECOIN': - _receivingAddress = this.selectedAddress.ltcWallet.address - break - case 'DOGECOIN': - _receivingAddress = this.selectedAddress.dogeWallet.address - break - default: - break - } - const response = await parentEpml.request('tradeBotCreateRequest', { - creatorPublicKey: this.selectedAddress.base58PublicKey, - qortAmount: parseFloat(sellAmountInput), - fundingQortAmount: parseFloat(fundingQortAmount), - foreignBlockchain: this.selectedCoin, - foreignAmount: parseFloat(sellTotalInput), - tradeTimeout: 60, - receivingAddress: _receivingAddress, - }) - return response - } - - const manageResponse = (response) => { - if (response === true) { - this.isSellLoading = false - this.sellBtnDisable = false - this.shadowRoot.getElementById('sellAmountInput').value = this.initialAmount - this.shadowRoot.getElementById('sellPriceInput').value = this.initialAmount - this.shadowRoot.getElementById('sellTotalInput').value = this.initialAmount - } else if (response === false) { - this.isSellLoading = false - this.sellBtnDisable = false - parentEpml.request('showSnackBar', 'Failed to Create Trade. Try again!') - } else { - this.isSellLoading = false - this.sellBtnDisable = false - parentEpml.request('showSnackBar', `Failed to Create Trade. ERROR_CODE: ${response.message}`) - } - } - - if (this.round(parseFloat(fundingQortAmount) + parseFloat(0.002)) > parseFloat(this.listedCoins.get("QORTAL").balance)) { - this.isSellLoading = false - this.sellBtnDisable = false - parentEpml.request('showSnackBar', 'Insufficient Funds!') - return false - } else { - const res = await makeRequest() - manageResponse(res) - } - } - - async buyAction() { - this.isBuyLoading = true - this.buyBtnDisable = true - const qortalAtAddress = this.shadowRoot.getElementById('qortalAtAddress').value - let _foreignKey = "" - - switch (this.selectedCoin) { - case 'LITECOIN': - _foreignKey = this.selectedAddress.ltcWallet.derivedMasterPrivateKey - break - case 'DOGECOIN': - _foreignKey = this.selectedAddress.dogeWallet.derivedMasterPrivateKey - break - default: - break - } - - const makeRequest = async () => { - const response = await parentEpml.request('tradeBotRespondRequest', { - atAddress: qortalAtAddress, - foreignKey: _foreignKey, - receivingAddress: this.selectedAddress.address, - }) - return response - } - - const manageResponse = (response) => { - if (response === true) { - this.isBuyLoading = false - this.buyBtnDisable = true - this.shadowRoot.getElementById('buyAmountInput').value = this.initialAmount - this.shadowRoot.getElementById('buyPriceInput').value = this.initialAmount - this.shadowRoot.getElementById('buyTotalInput').value = this.initialAmount - this.shadowRoot.getElementById('qortalAtAddress').value = '' - parentEpml.request('showSnackBar', 'Buy Request Successful!') - } else if (response === false) { - this.isBuyLoading = false - this.buyBtnDisable = false - parentEpml.request('showSnackBar', 'Buy Request Existing!') - } else { - this.isBuyLoading = false - this.buyBtnDisable = false - parentEpml.request('showSnackBar', `Failed to Create Trade. ERROR_CODE: ${response.message}`) - } - } - - // Call makeRequest - const res = await makeRequest() - manageResponse(res) - } - - async cancelAction(state) { - const button = this.shadowRoot.querySelector(`mwc-button#${state.atAddress}`) - button.innerHTML = `` - this.cancelBtnDisable = true - - const makeRequest = async () => { - const response = await parentEpml.request('deleteTradeOffer', { - creatorPublicKey: this.selectedAddress.base58PublicKey, - atAddress: state.atAddress, - }) - return response - } - - const manageResponse = (response) => { - if (response === true) { - button.remove() - this.cancelBtnDisable = false - parentEpml.request('showSnackBar', 'Trade Cancelling In Progress!') - } else if (response === false) { - button.innerHTML = 'CANCEL' - this.cancelBtnDisable = false - parentEpml.request('showSnackBar', 'Failed to Cancel Trade. Try again!') - } else { - button.innerHTML = 'CANCEL' - this.cancelBtnDisable = false - parentEpml.request('showSnackBar', `Failed to Cancel Trade. ERROR_CODE: ${response.message}`) - } - } - - // Call makeRequest - const res = await makeRequest() - manageResponse(res) - } - - updateAccountBalance() { - clearTimeout(this.updateAccountBalanceTimeout) - parentEpml.request('apiCall', { - url: `/addresses/balance/${this.selectedAddress.address}?apiKey=${this.getApiKey()}`, - }) - .then((res) => { - this.listedCoins.get("QORTAL").balance = res - this.updateAccountBalanceTimeout = setTimeout(() => this.updateAccountBalance(), 10000) - }) - } - - renderCancelButton(stateItem) { - if (stateItem.tradeState === 'BOB_WAITING_FOR_MESSAGE') { - return html` this.cancelAction(stateItem)}>CANCEL` - } else { - return '' - } - } - - showStuckOrdersDialog() { - this.shadowRoot.querySelector('#manageStuckOrdersDialog').show() - } - - async cancelStuckOfferAction(offer) { - this.cancelStuckOfferBtnDisable = true - - const makeRequest = async () => { - const response = await parentEpml.request('deleteTradeOffer', { - creatorPublicKey: this.selectedAddress.base58PublicKey, - atAddress: offer.qortalAtAddress, - }) - return response - } - - const manageResponse = (response) => { - if (response === true) { - this.cancelStuckOfferBtnDisable = false - parentEpml.request('showSnackBar', 'Trade Cancelling In Progress!') - } else if (response === false) { - this.cancelStuckOfferBtnDisable = false - parentEpml.request('showSnackBar', 'Failed to Cancel Trade. Try again!') - } else { - this.cancelStuckOfferBtnDisable = false - parentEpml.request('showSnackBar', `Failed to Cancel Trade. ERROR_CODE: ${response.message}`) - } - } - - // Call makeRequest - const res = await makeRequest() - manageResponse(res) - } - - renderCancelStuckOfferButton(offerItem) { - if (offerItem.mode === 'OFFERING' && offerItem.qortalCreator === this.selectedAddress.address) { - return html` this.cancelStuckOfferAction(offerItem)}>CANCEL` - } else { - return '' - } - } - - // Helper Functions (Re-Used in Most part of the UI ) - _checkSellAmount(e) { - const targetAmount = e.target.value - const target = e.target - - if (targetAmount.length === 0) { - this.isValidAmount = false - this.sellBtnDisable = true - e.target.blur() - e.target.focus() - e.target.invalid = true - } else { - const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value - const sellPriceInput = this.shadowRoot.getElementById('sellPriceInput').value - this.shadowRoot.getElementById('sellTotalInput').value = this.round(parseFloat(sellAmountInput) * parseFloat(sellPriceInput)) - this.sellBtnDisable = false - } - - e.target.blur() - e.target.focus() - - e.target.validityTransform = (newValue, nativeValidity) => { - if (newValue.includes('-') === true) { - this.sellBtnDisable = true - return { - valid: false, - } - } else if (!nativeValidity.valid) { - if (newValue.includes('.') === true) { - let myAmount = newValue.split('.') - if (myAmount[1].length > 8) { - this.sellBtnDisable = true - } else { - const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value - const sellPriceInput = this.shadowRoot.getElementById('sellPriceInput').value - this.shadowRoot.getElementById('sellTotalInput').value = this.round(parseFloat(sellAmountInput) * parseFloat(sellPriceInput)) - this.sellBtnDisable = false - return { - valid: true, - } - } - } - } else { - const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value - const sellPriceInput = this.shadowRoot.getElementById('sellPriceInput').value - this.shadowRoot.getElementById('sellTotalInput').value = this.round(parseFloat(sellAmountInput) * parseFloat(sellPriceInput)) - this.sellBtnDisable = false - } - } - } - - _checkBuyAmount(e) { - const targetAmount = e.target.value - const target = e.target - - if (targetAmount.length === 0) { - this.isValidAmount = false - this.sellBtnDisable = true - e.target.blur() - e.target.focus() - e.target.invalid = true - } else { - this.buyBtnDisable = false - } - - e.target.blur() - e.target.focus() - - e.target.validityTransform = (newValue, nativeValidity) => { - if (newValue.includes('-') === true) { - this.buyBtnDisable = true - return { - valid: false, - } - } else if (!nativeValidity.valid) { - if (newValue.includes('.') === true) { - let myAmount = newValue.split('.') - if (myAmount[1].length > 8) { - this.buyBtnDisable = true - } else { - this.buyBtnDisable = false - return { - valid: true, - } - } - } - } else { - this.buyBtnDisable = false - } - } - } - - getApiKey() { + } + const offerItem = { + ...offer, + mode: 'SOLD', + } + // Add to my historic trades + this._myHistoricTradesGrid.items.unshift(offerItem) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null + } else if (offer.partnerQortalReceivingAddress === this.selectedAddress.address) { + // Check and Update Wallet Balance + if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { + this.updateWalletBalance() + } + const offerItem = { + ...offer, + mode: 'BOUGHT', + } + // Add to my historic trades + this._myHistoricTradesGrid.items.unshift(offerItem) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null + } + // Add to historic trades + const addNewHistoricTrade = () => { + this._historicTradesGrid.items.unshift(offer) + this._historicTradesGrid.clearCache() + } + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? addNewHistoricTrade() : null + } + + processTradingTrade(offer) { + // Remove from open market orders + if (offer.qortalCreator === this.selectedAddress.address && this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { + // Check and Update Wallet Balance + this.updateWalletBalance() + } + this._openOrdersGrid.items.forEach((item, index) => { + if (item.qortalAtAddress === offer.qortalAtAddress) { + this._openOrdersGrid.items.splice(index, 1) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null + } + }) + this.listedCoins.get(this.selectedCoin).openOrders = this.listedCoins.get(this.selectedCoin).openOrders.filter((order) => order.qortalAtAddress !== offer.qortalAtAddress) + } + + processRefundedTrade(offer) { + if (offer.qortalCreator === this.selectedAddress.address) { + // Check and Update Wallet Balance + if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { + this.updateWalletBalance() + } + // Add to my historic trades + this._myHistoricTradesGrid.items.unshift(offer) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null + } + } + + processCancelledTrade(offer) { + if (offer.qortalCreator === this.selectedAddress.address) { + // Check and Update Wallet Balance + if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1) { + this.updateWalletBalance() + } + // Add to my historic trades + this._myHistoricTradesGrid.items.unshift(offer) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._myHistoricTradesGrid.clearCache() : null + } + this._openOrdersGrid.items.forEach((item, index) => { + if (item.qortalAtAddress === offer.qortalAtAddress) { + this._openOrdersGrid.items.splice(index, 1) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null + } + }) + this.listedCoins.get(this.selectedCoin).openOrders = this.listedCoins.get(this.selectedCoin).openOrders.filter((order) => order.qortalAtAddress !== offer.qortalAtAddress) + this._stuckOrdersGrid.items.forEach((item, index) => { + if (item.qortalAtAddress === offer.qortalAtAddress) { + this._stuckOrdersGrid.items.splice(index, 1) + this._stuckOrdersGrid.clearCache() + } + }) + } + + /** + * TRADE OFFER STATES or MODE + * - OFFERING + * - REDEEMED + * - TRADING + * - REFUNDED + * - CANCELLED + */ + + processTradeOffers(offers) { + offers.forEach((offer) => { + if (offer.mode === 'OFFERING') { + this.processOfferingTrade(offer) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter > 1 ? this._openOrdersGrid.clearCache() : null + } else if (offer.mode === 'REDEEMED') { + this.processRedeemedTrade(offer) + } else if (offer.mode === 'TRADING') { + this.processTradingTrade(offer) + } else if (offer.mode === 'REFUNDED') { + this.processRefundedTrade(offer) + } else if (offer.mode === 'CANCELLED') { + this.processCancelledTrade(offer) + } + }) + } + + /** + * TradeBot Note by cat + * + * trade-bot entry states: + * - when you do /crosschain/tradebot/create, + * - it returns unsigned DEPLOY_AT for you to sign & broadcast + * - so initial trade-bot state is BOB_WAITING_FOR_AT_CONFIRM, because trade-bot is waiting for UI to sign & broadcast txn and for that txn to be confirmed into a block + * - once that happens & Bob's trade-bot notices that DEPLOY_AT has confirmed (and hence AT created and running), then it switches to BOB_WAITING_FOR_MESSAGE + * - which is Bob's trade-bot waiting for a message from Alice's trade-bot telling it (Bob's trade-bot) that Alice's trade-bot has funded P2SH-A and some other details + * - when that message is sent, Bob's trade-bot processes that message and sends its own message to the AT (which switches it to TRADING mode) + * - but the next state for Bob's trade-bot is to wait for Alice to spot AT is locked to her and for her to fund P2SH-B, hence BOB_WAITING_FOR_P2SH_B + * - at this point, Bob's trade-bot finds P2SH-B on the litecoin blockchain and can send secret-B to P2SH-B + * - when this happens, Alice uses secret-B and secret-A to redeem the QORT from the AT, so until Alice does this, Bob's trade-bot state is BOB_WAITING_FOR_AT_REDEEM + * - after Alice redeems QORT from AT, Bob can extract secret-A and capture the actual LTC funds from P2SH-A to his own litecoin account and hence his trade-bot moves to BOB_DONE + * - if anything goes wrong then refunds occur and Bob's trade-bot ends up at BOB_REFUNDED instead + * - I think you can probably guess the corresponding meaning of states for Alice's point of view, but if not I can go through those too? + * - Alice calls /crosschain/tradebot/respond which funds P2SH-A + * - so her trade-bot waits for that to appear in litecoin blockchain, so until then is ALICE_WAITING_FOR_P2SH_A + * - once the P2SH-A funding confirms, Alice's trade-bot can MESSAGE Bob's trade-bot with the details and changes to ALICE_WAITING_FOR_AT_LOCK + * - Bob's AT should then lock to trading with Alice (via those MESSAGEs above) and Alice's trade-bot notices this, (minimally) funds P2SH-B and waits until Bob 'spends' P2SH-B, hence ALICE_WATCH_P2SH_B + * - if Bob spends P2SH-B, then Alice can send secret-B and secret-A to the AT, claim the QORT and she's ALICE_DONE + * - if something goes wrong then her trade-bot needs to refund P2SH-B (if applicable) first (ALICE_REFUNDING_B) + * - and when that's done refund P2SH-A (ALICE_REFUNDING_A) + * - and when that's done her trade-bot ends up at ALICE_REFUNDED + * + * (PHEW) + */ + + processTradeBotStates(tradeStates) { + + /** + * BitcoinACCTv1 TRADEBOT STATES + * - BOB_WAITING_FOR_AT_CONFIRM + * - BOB_WAITING_FOR_MESSAGE + * - BOB_WAITING_FOR_P2SH_B + * - BOB_WAITING_FOR_AT_REDEEM + * - BOB_DONE + * - BOB_REFUNDED + * - ALICE_WAITING_FOR_P2SH_A + * - ALICE_WAITING_FOR_AT_LOCK + * - ALICE_WATCH_P2SH_B + * - ALICE_DONE + * - ALICE_REFUNDING_B + * - ALICE_REFUNDING_A + * - ALICE_REFUNDED + * + * @param {[{}]} states + */ + + const BitcoinACCTv1 = (states) => { + // Reverse the states + states.reverse() + states.forEach((state) => { + if (state.creatorAddress === this.selectedAddress.address) { + if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { + this.changeTradeBotState(state, 'PENDING') + } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { + this.changeTradeBotState(state, 'LISTED') + } else if (state.tradeState == 'BOB_WAITING_FOR_P2SH_B') { + this.changeTradeBotState(state, 'TRADING') + } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { + this.changeTradeBotState(state, 'REDEEMING') + } else if (state.tradeState == 'BOB_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'BOB_REFUNDED') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_WAITING_FOR_P2SH_A') { + this.changeTradeBotState(state, 'PENDING') + } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { + this.changeTradeBotState(state, 'TRADING') + } else if (state.tradeState == 'ALICE_WATCH_P2SH_B') { + this.changeTradeBotState(state, 'TRADING') + } else if (state.tradeState == 'ALICE_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_REFUNDING_B') { + this.changeTradeBotState(state, 'REFUNDING') + } else if (state.tradeState == 'ALICE_REFUNDING_A') { + this.changeTradeBotState(state, 'REFUNDING') + } else if (state.tradeState == 'ALICE_REFUNDED') { + this.handleCompletedState(state) + } + } + }) + } + + /** + * LitecoinACCTv1 TRADEBOT STATES + * - BOB_WAITING_FOR_AT_CONFIRM + * - BOB_WAITING_FOR_MESSAGE + * - BOB_WAITING_FOR_AT_REDEEM + * - BOB_DONE + * - BOB_REFUNDED + * - ALICE_WAITING_FOR_AT_LOCK + * - ALICE_DONE + * - ALICE_REFUNDING_A + * - ALICE_REFUNDED + * + * @param {[{}]} states + */ + + const LitecoinACCTv1 = (states) => { + // Reverse the states + states.reverse() + states.forEach((state) => { + if (state.creatorAddress === this.selectedAddress.address) { + if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { + this.changeTradeBotState(state, 'PENDING') + } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { + this.changeTradeBotState(state, 'LISTED') + } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { + this.changeTradeBotState(state, 'TRADING') + } else if (state.tradeState == 'BOB_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'BOB_REFUNDED') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { + this.changeTradeBotState(state, 'BUYING') + } else if (state.tradeState == 'ALICE_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_REFUNDING_A') { + this.changeTradeBotState(state, 'REFUNDING') + } else if (state.tradeState == 'ALICE_REFUNDED') { + this.handleCompletedState(state) + } + } + }) + } + + /** + * DogecoinACCTv1 TRADEBOT STATES + * - BOB_WAITING_FOR_AT_CONFIRM + * - BOB_WAITING_FOR_MESSAGE + * - BOB_WAITING_FOR_AT_REDEEM + * - BOB_DONE + * - BOB_REFUNDED + * - ALICE_WAITING_FOR_AT_LOCK + * - ALICE_DONE + * - ALICE_REFUNDING_A + * - ALICE_REFUNDED + * + * @param {[{}]} states + */ + + const DogecoinACCTv1 = (states) => { + // Reverse the states + states.reverse() + states.forEach((state) => { + if (state.creatorAddress === this.selectedAddress.address) { + if (state.tradeState == 'BOB_WAITING_FOR_AT_CONFIRM') { + this.changeTradeBotState(state, 'PENDING') + } else if (state.tradeState == 'BOB_WAITING_FOR_MESSAGE') { + this.changeTradeBotState(state, 'LISTED') + } else if (state.tradeState == 'BOB_WAITING_FOR_AT_REDEEM') { + this.changeTradeBotState(state, 'TRADING') + } else if (state.tradeState == 'BOB_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'BOB_REFUNDED') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_WAITING_FOR_AT_LOCK') { + this.changeTradeBotState(state, 'BUYING') + } else if (state.tradeState == 'ALICE_DONE') { + this.handleCompletedState(state) + } else if (state.tradeState == 'ALICE_REFUNDING_A') { + this.changeTradeBotState(state, 'REFUNDING') + } else if (state.tradeState == 'ALICE_REFUNDED') { + this.handleCompletedState(state) + } + } + }) + } + + switch (this.selectedCoin) { + case 'BITCOIN': + BitcoinACCTv1(tradeStates) + break + case 'LITECOIN': + LitecoinACCTv1(tradeStates) + break + case 'DOGECOIN': + DogecoinACCTv1(tradeStates) + break + default: + break + } + + // Fill Historic Trades and Filter Stuck Trades + if (this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter === 1) { + setTimeout(() => this.filterStuckTrades(tradeStates), 50) + } + } + + changeTradeBotState(state, tradeState) { + // Set Loading state + this.isLoadingMyOpenOrders = true + const stateItem = { + ...state, + _tradeState: tradeState, + } + const item = this._myOrdersGrid.querySelector(`#${state.atAddress}`) + const addStateItem = () => { + this.reRenderMyOpenOrders() + this._myOrdersGrid.items.unshift(stateItem) + this._myOrdersGrid.clearCache() + } + const updateStateItem = () => { + this._myOrdersGrid.items.forEach((item, index) => { + if (item.atAddress === state.atAddress) { + this._myOrdersGrid.items.splice(index, 1) + this._myOrdersGrid.items.unshift(stateItem) + this._myOrdersGrid.clearCache() + } + }) + } + item ? updateStateItem() : addStateItem() + } + + // ONLY USE FOR BOB_DONE, BOB_REFUNDED, ALICE_DONE, ALICE_REFUNDED + handleCompletedState(state) { + this._myOrdersGrid.items.forEach((item, index) => { + if (item.atAddress === state.atAddress) { + this._myOrdersGrid.items.splice(index, 1) + this._myOrdersGrid.clearCache() + } + }) + } + + initSocket() { + let _relatedCoin = "" + let presenceTxns = null + let offeringTrades = null + let filteredOffers = [] + + self.addEventListener('message', function (event) { + switch (event.data.type) { + case 'open_orders': + offeringTrades = event.data.content + handleOfferingTrades() + break + case 'set_coin': + _relatedCoin = event.data.content + break + default: + break + } + }) + + const lessThanThirtyMinsAgo = (timestamp) => { + const THIRTYMINS = 1000 * 60 * 30 + const thirtyMinsAgo = Date.now() - THIRTYMINS + return timestamp > thirtyMinsAgo + } + + const processOffersWithPresence = () => { + const waitFor = (ms) => new Promise((r) => setTimeout(r, ms)) + async function asyncForEach(array, callback) { + for (let index = 0; index < array.length; index++) { + await callback(array[index], index, array) + } + } + const startOfferPresenceMapping = async () => { + await asyncForEach(presenceTxns, async (presence) => { + await waitFor(5) + let offerIndex = offeringTrades.findIndex((offeringTrade) => offeringTrade.qortalCreatorTradeAddress === presence.address) + offerIndex !== -1 ? (offeringTrades[offerIndex].lastSeen = presence.timestamp) : null + }) + filteredOffers = offeringTrades.filter((offeringTrade) => lessThanThirtyMinsAgo(offeringTrade.lastSeen)) + self.postMessage({ type: 'PRESENCE', data: { offers: offeringTrades, filteredOffers: filteredOffers, relatedCoin: _relatedCoin } }) + filteredOffers = [] + } + startOfferPresenceMapping() + } + + const handleOfferingTrades = () => { + if (presenceTxns === null) return + processOffersWithPresence() + } + + const handlePresence = () => { + if (offeringTrades === null) return + processOffersWithPresence() + } + + const initTradeOffersWebSocket = (restarted = false) => { + let tradeOffersSocketCounter = 0 + let socketTimeout + let socketLink = `ws://NODEURL/websockets/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN&includeHistoric=true` + const socket = new WebSocket(socketLink) + // Open Connection + socket.onopen = () => { + setTimeout(pingSocket, 50) + tradeOffersSocketCounter += 1 + } + // Message Event + socket.onmessage = (e) => { + e.relatedCoin = _relatedCoin + self.postMessage({ + type: 'TRADE_OFFERS', + data: e.data, + counter: tradeOffersSocketCounter, + isRestarted: restarted, + }) + tradeOffersSocketCounter += 1 + restarted = false + } + // Closed Event + socket.onclose = () => { + clearTimeout(socketTimeout) + // Restart Socket Connection + restartTradeOffersWebSocket() + } + // Error Event + socket.onerror = (e) => { + clearTimeout(socketTimeout) + } + const pingSocket = () => { + socket.send('ping') + socketTimeout = setTimeout(pingSocket, 295000) + } + } + + const initTradeBotWebSocket = (restarted = false) => { + let socketTimeout + let socketLink = `ws://NODEURL/websockets/crosschain/tradebot?foreignBlockchain=FOREIGN_BLOCKCHAIN` + const socket = new WebSocket(socketLink) + // Open Connection + socket.onopen = () => { + setTimeout(pingSocket, 50) + } + // Message Event + socket.onmessage = (e) => { + e.relatedCoin = _relatedCoin + self.postMessage({ + type: 'TRADE_BOT', + data: e.data, + isRestarted: restarted, + }) + restarted = false + } + // Closed Event + socket.onclose = () => { + clearTimeout(socketTimeout) + // Restart Socket Connection + restartTradeBotWebSocket() + } + // Error Event + socket.onerror = (e) => { + clearTimeout(socketTimeout) + } + const pingSocket = () => { + socket.send('ping') + socketTimeout = setTimeout(pingSocket, 295000) + } + } + + const initPresenceWebSocket = (restarted = false) => { + let socketTimeout + let socketLink = `ws://NODEURL/websockets/presence?presenceType=TRADE_BOT` + const socket = new WebSocket(socketLink) + // Open Connection + socket.onopen = () => { + setTimeout(pingSocket, 50) + } + // Message Event + socket.onmessage = (e) => { + presenceTxns = JSON.parse(e.data) + handlePresence() + restarted = false + } + // Closed Event + socket.onclose = () => { + clearTimeout(socketTimeout) + // Restart Socket Connection + restartPresenceWebSocket() + } + // Error Event + socket.onerror = (e) => { + clearTimeout(socketTimeout) + } + const pingSocket = () => { + socket.send('ping') + socketTimeout = setTimeout(pingSocket, 295000) + } + } + + const restartPresenceWebSocket = () => { + setTimeout(() => initPresenceWebSocket(true), 3000) + } + + const restartTradeOffersWebSocket = () => { + setTimeout(() => initTradeOffersWebSocket(true), 3000) + } + + const restartTradeBotWebSocket = () => { + setTimeout(() => initTradeBotWebSocket(true), 3000) + } + + // Start TradeOffersWebSocket + initTradeOffersWebSocket() + + // Start PresenceWebSocket + initPresenceWebSocket() + + // Start TradeBotWebSocket + initTradeBotWebSocket() + } + + async sellAction() { + this.isSellLoading = true + this.sellBtnDisable = true + const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value + const sellTotalInput = this.shadowRoot.getElementById('sellTotalInput').value + const fundingQortAmount = this.round(parseFloat(sellAmountInput) + 0.001) + + const makeRequest = async () => { + let _receivingAddress = null + switch (this.selectedCoin) { + case 'LITECOIN': + _receivingAddress = this.selectedAddress.ltcWallet.address + break + case 'DOGECOIN': + _receivingAddress = this.selectedAddress.dogeWallet.address + break + default: + break + } + const response = await parentEpml.request('tradeBotCreateRequest', { + creatorPublicKey: this.selectedAddress.base58PublicKey, + qortAmount: parseFloat(sellAmountInput), + fundingQortAmount: parseFloat(fundingQortAmount), + foreignBlockchain: this.selectedCoin, + foreignAmount: parseFloat(sellTotalInput), + tradeTimeout: 60, + receivingAddress: _receivingAddress, + }) + return response + } + + const manageResponse = (response) => { + if (response === true) { + this.isSellLoading = false + this.sellBtnDisable = false + this.shadowRoot.getElementById('sellAmountInput').value = this.initialAmount + this.shadowRoot.getElementById('sellPriceInput').value = this.initialAmount + this.shadowRoot.getElementById('sellTotalInput').value = this.initialAmount + } else if (response === false) { + this.isSellLoading = false + this.sellBtnDisable = false + parentEpml.request('showSnackBar', 'Failed to Create Trade. Try again!') + } else { + this.isSellLoading = false + this.sellBtnDisable = false + parentEpml.request('showSnackBar', `Failed to Create Trade. ERROR_CODE: ${response.message}`) + } + } + + if (this.round(parseFloat(fundingQortAmount) + parseFloat(0.002)) > parseFloat(this.listedCoins.get("QORTAL").balance)) { + this.isSellLoading = false + this.sellBtnDisable = false + parentEpml.request('showSnackBar', 'Insufficient Funds!') + return false + } else { + const res = await makeRequest() + manageResponse(res) + } + } + + async buyAction() { + this.isBuyLoading = true + this.buyBtnDisable = true + const qortalAtAddress = this.shadowRoot.getElementById('qortalAtAddress').value + let _foreignKey = "" + + switch (this.selectedCoin) { + case 'LITECOIN': + _foreignKey = this.selectedAddress.ltcWallet.derivedMasterPrivateKey + break + case 'DOGECOIN': + _foreignKey = this.selectedAddress.dogeWallet.derivedMasterPrivateKey + break + default: + break + } + + const makeRequest = async () => { + const response = await parentEpml.request('tradeBotRespondRequest', { + atAddress: qortalAtAddress, + foreignKey: _foreignKey, + receivingAddress: this.selectedAddress.address, + }) + return response + } + + const manageResponse = (response) => { + if (response === true) { + this.isBuyLoading = false + this.buyBtnDisable = true + this.shadowRoot.getElementById('buyAmountInput').value = this.initialAmount + this.shadowRoot.getElementById('buyPriceInput').value = this.initialAmount + this.shadowRoot.getElementById('buyTotalInput').value = this.initialAmount + this.shadowRoot.getElementById('qortalAtAddress').value = '' + parentEpml.request('showSnackBar', 'Buy Request Successful!') + } else if (response === false) { + this.isBuyLoading = false + this.buyBtnDisable = false + parentEpml.request('showSnackBar', 'Buy Request Existing!') + } else { + this.isBuyLoading = false + this.buyBtnDisable = false + parentEpml.request('showSnackBar', `Failed to Create Trade. ERROR_CODE: ${response.message}`) + } + } + + // Call makeRequest + const res = await makeRequest() + manageResponse(res) + } + + async cancelAction(state) { + const button = this.shadowRoot.querySelector(`mwc-button#${state.atAddress}`) + button.innerHTML = `` + this.cancelBtnDisable = true + + const makeRequest = async () => { + const response = await parentEpml.request('deleteTradeOffer', { + creatorPublicKey: this.selectedAddress.base58PublicKey, + atAddress: state.atAddress, + }) + return response + } + + const manageResponse = (response) => { + if (response === true) { + button.remove() + this.cancelBtnDisable = false + parentEpml.request('showSnackBar', 'Trade Cancelling In Progress!') + } else if (response === false) { + button.innerHTML = 'CANCEL' + this.cancelBtnDisable = false + parentEpml.request('showSnackBar', 'Failed to Cancel Trade. Try again!') + } else { + button.innerHTML = 'CANCEL' + this.cancelBtnDisable = false + parentEpml.request('showSnackBar', `Failed to Cancel Trade. ERROR_CODE: ${response.message}`) + } + } + + // Call makeRequest + const res = await makeRequest() + manageResponse(res) + } + + updateAccountBalance() { + clearTimeout(this.updateAccountBalanceTimeout) + parentEpml.request('apiCall', { + url: `/addresses/balance/${this.selectedAddress.address}?apiKey=${this.getApiKey()}`, + }) + .then((res) => { + this.listedCoins.get("QORTAL").balance = res + this.updateAccountBalanceTimeout = setTimeout(() => this.updateAccountBalance(), 10000) + }) + } + + renderCancelButton(stateItem) { + if (stateItem.tradeState === 'BOB_WAITING_FOR_MESSAGE') { + return html` this.cancelAction(stateItem)}>CANCEL` + } else { + return '' + } + } + + showStuckOrdersDialog() { + this.shadowRoot.querySelector('#manageStuckOrdersDialog').show() + } + + async cancelStuckOfferAction(offer) { + this.cancelStuckOfferBtnDisable = true + + const makeRequest = async () => { + const response = await parentEpml.request('deleteTradeOffer', { + creatorPublicKey: this.selectedAddress.base58PublicKey, + atAddress: offer.qortalAtAddress, + }) + return response + } + + const manageResponse = (response) => { + if (response === true) { + this.cancelStuckOfferBtnDisable = false + parentEpml.request('showSnackBar', 'Trade Cancelling In Progress!') + } else if (response === false) { + this.cancelStuckOfferBtnDisable = false + parentEpml.request('showSnackBar', 'Failed to Cancel Trade. Try again!') + } else { + this.cancelStuckOfferBtnDisable = false + parentEpml.request('showSnackBar', `Failed to Cancel Trade. ERROR_CODE: ${response.message}`) + } + } + + // Call makeRequest + const res = await makeRequest() + manageResponse(res) + } + + renderCancelStuckOfferButton(offerItem) { + if (offerItem.mode === 'OFFERING' && offerItem.qortalCreator === this.selectedAddress.address) { + return html` this.cancelStuckOfferAction(offerItem)}>CANCEL` + } else { + return '' + } + } + + // Helper Functions (Re-Used in Most part of the UI ) + _checkSellAmount(e) { + const targetAmount = e.target.value + const target = e.target + + if (targetAmount.length === 0) { + this.isValidAmount = false + this.sellBtnDisable = true + e.target.blur() + e.target.focus() + e.target.invalid = true + } else { + const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value + const sellPriceInput = this.shadowRoot.getElementById('sellPriceInput').value + this.shadowRoot.getElementById('sellTotalInput').value = this.round(parseFloat(sellAmountInput) * parseFloat(sellPriceInput)) + this.sellBtnDisable = false + } + + e.target.blur() + e.target.focus() + + e.target.validityTransform = (newValue, nativeValidity) => { + if (newValue.includes('-') === true) { + this.sellBtnDisable = true + return { + valid: false, + } + } else if (!nativeValidity.valid) { + if (newValue.includes('.') === true) { + let myAmount = newValue.split('.') + if (myAmount[1].length > 8) { + this.sellBtnDisable = true + } else { + const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value + const sellPriceInput = this.shadowRoot.getElementById('sellPriceInput').value + this.shadowRoot.getElementById('sellTotalInput').value = this.round(parseFloat(sellAmountInput) * parseFloat(sellPriceInput)) + this.sellBtnDisable = false + return { + valid: true, + } + } + } + } else { + const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value + const sellPriceInput = this.shadowRoot.getElementById('sellPriceInput').value + this.shadowRoot.getElementById('sellTotalInput').value = this.round(parseFloat(sellAmountInput) * parseFloat(sellPriceInput)) + this.sellBtnDisable = false + } + } + } + + _checkBuyAmount(e) { + const targetAmount = e.target.value + const target = e.target + + if (targetAmount.length === 0) { + this.isValidAmount = false + this.sellBtnDisable = true + e.target.blur() + e.target.focus() + e.target.invalid = true + } else { + this.buyBtnDisable = false + } + + e.target.blur() + e.target.focus() + + e.target.validityTransform = (newValue, nativeValidity) => { + if (newValue.includes('-') === true) { + this.buyBtnDisable = true + return { + valid: false, + } + } else if (!nativeValidity.valid) { + if (newValue.includes('.') === true) { + let myAmount = newValue.split('.') + if (myAmount[1].length > 8) { + this.buyBtnDisable = true + } else { + this.buyBtnDisable = false + return { + valid: true, + } + } + } + } else { + this.buyBtnDisable = false + } + } + } + + getApiKey() { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; let apiKey = myNode.apiKey; return apiKey; } - clearSelection() { - window.getSelection().removeAllRanges() - window.parent.getSelection().removeAllRanges() - } + clearSelection() { + window.getSelection().removeAllRanges() + window.parent.getSelection().removeAllRanges() + } - _textMenu(event) { - const getSelectedText = () => { - var text = '' - if (typeof window.getSelection != 'undefined') { - text = window.getSelection().toString() - } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { - text = this.shadowRoot.selection.createRange().text - } - return text - } + _textMenu(event) { + const getSelectedText = () => { + var text = '' + if (typeof window.getSelection != 'undefined') { + text = window.getSelection().toString() + } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') { + text = this.shadowRoot.selection.createRange().text + } + return text + } - const checkSelectedTextAndShowMenu = () => { - let selectedText = getSelectedText() - if (selectedText && typeof selectedText === 'string') { - let _eve = { - pageX: event.pageX, - pageY: event.pageY, - clientX: event.clientX, - clientY: event.clientY, - } - let textMenuObject = { - selectedText: selectedText, - eventObject: _eve, - isFrame: true, - } - parentEpml.request('openCopyTextMenu', textMenuObject) - } - } - checkSelectedTextAndShowMenu() - } + const checkSelectedTextAndShowMenu = () => { + let selectedText = getSelectedText() + if (selectedText && typeof selectedText === 'string') { + let _eve = { + pageX: event.pageX, + pageY: event.pageY, + clientX: event.clientX, + clientY: event.clientY, + } + let textMenuObject = { + selectedText: selectedText, + eventObject: _eve, + isFrame: true, + } + parentEpml.request('openCopyTextMenu', textMenuObject) + } + } + checkSelectedTextAndShowMenu() + } - clearBuyForm() { - this.shadowRoot.getElementById('buyAmountInput').value = this.initialAmount - this.shadowRoot.getElementById('buyPriceInput').value = this.initialAmount - this.shadowRoot.getElementById('buyTotalInput').value = this.initialAmount - this.shadowRoot.getElementById('qortalAtAddress').value = '' - this.buyBtnDisable = true - } + clearBuyForm() { + this.shadowRoot.getElementById('buyAmountInput').value = this.initialAmount + this.shadowRoot.getElementById('buyPriceInput').value = this.initialAmount + this.shadowRoot.getElementById('buyTotalInput').value = this.initialAmount + this.shadowRoot.getElementById('qortalAtAddress').value = '' + this.buyBtnDisable = true + } - clearSellForm() { - this.shadowRoot.getElementById('sellAmountInput').value = this.initialAmount - this.shadowRoot.getElementById('sellPriceInput').value = this.initialAmount - this.shadowRoot.getElementById('sellTotalInput').value = this.initialAmount - } + clearSellForm() { + this.shadowRoot.getElementById('sellAmountInput').value = this.initialAmount + this.shadowRoot.getElementById('sellPriceInput').value = this.initialAmount + this.shadowRoot.getElementById('sellTotalInput').value = this.initialAmount + } - isEmptyArray(arr) { - if (!arr) { - return true - } - return arr.length === 0 - } + isEmptyArray(arr) { + if (!arr) { + return true + } + return arr.length === 0 + } - round(number) { - let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8) - return result - } + round(number) { + let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8) + return result + } - /** - * Inline Worker - Takes in a function and a modifier then returns an instance of a Web Worker - * - * - Modifiers are simply an Array of Object containing placeholders (containers for variables used in the passedFunction ) in the and its values. - * These placeholders gets replaced with it value during instantiation of the function to be used by the Worker. - * - Example of modifiers: const modifiers = [ - * { searchValue: 'SELECTED_ADDRESS', replaceValue: this.selectedAddress.address, }, - * ] - * - * @param {Function} passedFunction - * @param {Array} modifiers - * @returns {Worker} Worker - */ + /** + * Inline Worker - Takes in a function and a modifier then returns an instance of a Web Worker + * + * - Modifiers are simply an Array of Object containing placeholders (containers for variables used in the passedFunction ) in the and its values. + * These placeholders gets replaced with it value during instantiation of the function to be used by the Worker. + * - Example of modifiers: const modifiers = [ + * { searchValue: 'SELECTED_ADDRESS', replaceValue: this.selectedAddress.address, }, + * ] + * + * @param {Function} passedFunction + * @param {Array} modifiers + * @returns {Worker} Worker + */ - inlineWorker(passedFunction, modifiers) { - let parsedFunction = `` + inlineWorker(passedFunction, modifiers) { + let parsedFunction = `` - modifiers.forEach((modifier) => { - let regex = new RegExp(modifier.searchValue, 'g') - parsedFunction = parsedFunction.length === 0 ? `(function ${passedFunction.toString().trim().replace(regex, modifier.replaceValue)})()` : parsedFunction.toString().trim().replace(regex, modifier.replaceValue) - }) + modifiers.forEach((modifier) => { + let regex = new RegExp(modifier.searchValue, 'g') + parsedFunction = parsedFunction.length === 0 ? `(function ${passedFunction.toString().trim().replace(regex, modifier.replaceValue)})()` : parsedFunction.toString().trim().replace(regex, modifier.replaceValue) + }) - const workerUrl = URL.createObjectURL(new Blob([parsedFunction], { type: 'text/javascript' })) - const worker = new Worker(workerUrl) - URL.revokeObjectURL(workerUrl) - return worker - } + const workerUrl = URL.createObjectURL(new Blob([parsedFunction], { type: 'text/javascript' })) + const worker = new Worker(workerUrl) + URL.revokeObjectURL(workerUrl) + return worker + } - clearPaneCache() { - this._openOrdersGrid.clearCache() - this._myHistoricTradesGrid.clearCache() - this._historicTradesGrid.clearCache() - } + clearPaneCache() { + this._openOrdersGrid.clearCache() + this._myHistoricTradesGrid.clearCache() + this._historicTradesGrid.clearCache() + } - createConnection() { - if (workers.get(this.selectedCoin).tradesConnectedWorker !== null) { - this.isLoadingHistoricTrades = false - this.isLoadingOpenTrades = false - return - } + createConnection() { + if (workers.get(this.selectedCoin).tradesConnectedWorker !== null) { + this.isLoadingHistoricTrades = false + this.isLoadingOpenTrades = false + return + } - const handleMessage = (message) => { - switch (message.type) { - case 'TRADE_OFFERS': - if (!message.isRestarted) { - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter = message.counter - this.processTradeOffers(JSON.parse(message.data)) - this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter === 1 ? this.clearPaneCache() : null - workers.get(this.selectedCoin).tradesConnectedWorker.postMessage(this.listedCoins.get(this.selectedCoin).openOrders) - workers.get(this.selectedCoin).tradesConnectedWorker.postMessage({ type: "open_orders", content: this.listedCoins.get(this.selectedCoin).openOrders }) - } - return null - case 'TRADE_BOT': - if (!message.isRestarted) this.processTradeBotStates(JSON.parse(message.data)) - return null - case 'PRESENCE': - this.listedCoins.get(message.data.relatedCoin).openOrders = message.data.offers - this.listedCoins.get(message.data.relatedCoin).openFilteredOrders = message.data.filteredOffers - this.reRenderOpenFilteredOrders() - return null - default: - break - } - } + const handleMessage = (message) => { + switch (message.type) { + case 'TRADE_OFFERS': + if (!message.isRestarted) { + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter = message.counter + this.processTradeOffers(JSON.parse(message.data)) + this.listedCoins.get(this.selectedCoin).tradeOffersSocketCounter === 1 ? this.clearPaneCache() : null + workers.get(this.selectedCoin).tradesConnectedWorker.postMessage(this.listedCoins.get(this.selectedCoin).openOrders) + workers.get(this.selectedCoin).tradesConnectedWorker.postMessage({ type: "open_orders", content: this.listedCoins.get(this.selectedCoin).openOrders }) + } + return null + case 'TRADE_BOT': + if (!message.isRestarted) this.processTradeBotStates(JSON.parse(message.data)) + return null + case 'PRESENCE': + this.listedCoins.get(message.data.relatedCoin).openOrders = message.data.offers + this.listedCoins.get(message.data.relatedCoin).openFilteredOrders = message.data.filteredOffers + this.reRenderOpenFilteredOrders() + return null + default: + break + } + } - let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - let nodeUrl = myNode.domain + ':' + myNode.port + let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + let nodeUrl = myNode.domain + ':' + myNode.port - const modifiers = [ - { searchValue: 'NODEURL', replaceValue: nodeUrl }, - { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin, }, - ] + const modifiers = [ + { searchValue: 'NODEURL', replaceValue: nodeUrl }, + { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin, }, + ] - workers.get(this.selectedCoin).tradesConnectedWorker = this.inlineWorker(this.initSocket, modifiers) + workers.get(this.selectedCoin).tradesConnectedWorker = this.inlineWorker(this.initSocket, modifiers) - workers.get(this.selectedCoin).tradesConnectedWorker.addEventListener( - 'message', - function (event) { - handleMessage(event.data) - }, - { passive: true } - ) + workers.get(this.selectedCoin).tradesConnectedWorker.addEventListener( + 'message', + function (event) { + handleMessage(event.data) + }, + { passive: true } + ) - workers.get(this.selectedCoin).tradesConnectedWorker.postMessage({ type: "set_coin", content: this.selectedCoin }) - } + workers.get(this.selectedCoin).tradesConnectedWorker.postMessage({ type: "set_coin", content: this.selectedCoin }) + } - handleStuckTrades() { - let tradeBotStates = [] + handleStuckTrades() { + let tradeBotStates = [] - self.addEventListener('message', function (event) { - tradeBotStates = event.data - }) + self.addEventListener('message', function (event) { + tradeBotStates = event.data + }) - const getCompletedTrades = async () => { - const url = `http://NODEURL/crosschain/trades?limit=100&reverse=true&foreignBlockchain=FOREIGN_BLOCKCHAIN` - const res = await fetch(url) - const historicTrades = await res.json() - const compareFn = (a, b) => { - return b.tradeTimestamp - a.tradeTimestamp - } - const sortedTrades = historicTrades.sort(compareFn) - self.postMessage({ type: 'HISTORIC_TRADES', data: sortedTrades }) - } + const getCompletedTrades = async () => { + const url = `http://NODEURL/crosschain/trades?limit=100&reverse=true&foreignBlockchain=FOREIGN_BLOCKCHAIN` + const res = await fetch(url) + const historicTrades = await res.json() + const compareFn = (a, b) => { + return b.tradeTimestamp - a.tradeTimestamp + } + const sortedTrades = historicTrades.sort(compareFn) + self.postMessage({ type: 'HISTORIC_TRADES', data: sortedTrades }) + } - const filterStuckOffers = (myOffers) => { - const myTradeBotStates = tradeBotStates.filter((state) => state.creatorAddress === 'SELECTED_ADDRESS') - const stuckOffers = myOffers.filter((myOffer) => { - let value = myTradeBotStates.some((myTradeBotState) => myOffer.qortalAtAddress === myTradeBotState.atAddress) - return !value - }) - return stuckOffers - } + const filterStuckOffers = (myOffers) => { + const myTradeBotStates = tradeBotStates.filter((state) => state.creatorAddress === 'SELECTED_ADDRESS') + const stuckOffers = myOffers.filter((myOffer) => { + let value = myTradeBotStates.some((myTradeBotState) => myOffer.qortalAtAddress === myTradeBotState.atAddress) + return !value + }) + return stuckOffers + } - const getOffers = async () => { - const url = `http://NODEURL/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN` - const res = await fetch(url) - const openTradeOrders = await res.json() - const myOpenTradeOrders = await openTradeOrders.filter((order) => order.mode === 'OFFERING' && order.qortalCreator === 'SELECTED_ADDRESS') - const stuckOffers = filterStuckOffers(myOpenTradeOrders) - self.postMessage({ type: 'STUCK_OFFERS', data: stuckOffers }) - } + const getOffers = async () => { + const url = `http://NODEURL/crosschain/tradeoffers?foreignBlockchain=FOREIGN_BLOCKCHAIN` + const res = await fetch(url) + const openTradeOrders = await res.json() + const myOpenTradeOrders = await openTradeOrders.filter((order) => order.mode === 'OFFERING' && order.qortalCreator === 'SELECTED_ADDRESS') + const stuckOffers = filterStuckOffers(myOpenTradeOrders) + self.postMessage({ type: 'STUCK_OFFERS', data: stuckOffers }) + } - // Get Historic Trades - getCompletedTrades() + // Get Historic Trades + getCompletedTrades() - // Get Offers - getOffers() - } + // Get Offers + getOffers() + } - filterStuckTrades(states) { - if (workers.get(this.selectedCoin).handleStuckTradesConnectedWorker !== null) { - this.isLoadingOpenTrades = false - return - } + filterStuckTrades(states) { + if (workers.get(this.selectedCoin).handleStuckTradesConnectedWorker !== null) { + this.isLoadingOpenTrades = false + return + } - //show the loading on historic trades - this.shadowRoot.getElementById('loadingHistoricTrades').style.display = "block"; - let isHandleTradesDone = false - let isHandleStuckOffersDone = false + //show the loading on historic trades + this.shadowRoot.getElementById('loadingHistoricTrades').style.display = "block"; + let isHandleTradesDone = false + let isHandleStuckOffersDone = false - const handleMessage = (message) => { - switch (message.type) { - case 'HISTORIC_TRADES': - this.listedCoins.get(this.selectedCoin).historicTrades = message.data - this.reRenderHistoricTrades() - isHandleTradesDone = true - break - case 'STUCK_OFFERS': - doStuckOffers(message.data) - isHandleStuckOffersDone = true - break - default: - break - } - if (isHandleTradesDone === true && isHandleStuckOffersDone === true) return workers.get(this.selectedCoin).handleStuckTradesConnectedWorker.terminate() - } + const handleMessage = (message) => { + switch (message.type) { + case 'HISTORIC_TRADES': + this.listedCoins.get(this.selectedCoin).historicTrades = message.data + this.reRenderHistoricTrades() + isHandleTradesDone = true + break + case 'STUCK_OFFERS': + doStuckOffers(message.data) + isHandleStuckOffersDone = true + break + default: + break + } + if (isHandleTradesDone === true && isHandleStuckOffersDone === true) return workers.get(this.selectedCoin).handleStuckTradesConnectedWorker.terminate() + } - const doStuckOffers = (message) => { - const offers = message - const offerItem = (offer) => { - return { - ...offer, - price: this.round(parseFloat(offer.expectedForeignAmount) / parseFloat(offer.qortAmount)), - } - } - const addStuckOrders = (offerItem) => { - if (offerItem.qortalCreator === this.selectedAddress.address) { - this._stuckOrdersGrid.items.unshift(offerItem) - this._stuckOrdersGrid.clearCache() - } - } - const handleOffers = () => { - offers.forEach((offer) => { - addStuckOrders(offerItem(offer)) - }) - } - handleOffers() - } + const doStuckOffers = (message) => { + const offers = message + const offerItem = (offer) => { + return { + ...offer, + price: this.round(parseFloat(offer.expectedForeignAmount) / parseFloat(offer.qortAmount)), + } + } + const addStuckOrders = (offerItem) => { + if (offerItem.qortalCreator === this.selectedAddress.address) { + this._stuckOrdersGrid.items.unshift(offerItem) + this._stuckOrdersGrid.clearCache() + } + } + const handleOffers = () => { + offers.forEach((offer) => { + addStuckOrders(offerItem(offer)) + }) + } + handleOffers() + } - let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] - let nodeUrl = myNode.domain + ':' + myNode.port + let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + let nodeUrl = myNode.domain + ':' + myNode.port - const modifiers = [ - { searchValue: 'NODEURL', replaceValue: nodeUrl }, - { searchValue: 'SELECTED_ADDRESS', replaceValue: this.selectedAddress.address, }, - { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin, }, - ] + const modifiers = [ + { searchValue: 'NODEURL', replaceValue: nodeUrl }, + { searchValue: 'SELECTED_ADDRESS', replaceValue: this.selectedAddress.address, }, + { searchValue: 'FOREIGN_BLOCKCHAIN', replaceValue: this.selectedCoin, }, + ] - workers.get(this.selectedCoin).handleStuckTradesConnectedWorker = this.inlineWorker(this.handleStuckTrades, modifiers) - workers.get(this.selectedCoin).handleStuckTradesConnectedWorker.postMessage(states) - workers.get(this.selectedCoin).handleStuckTradesConnectedWorker.addEventListener( - 'message', - function (event) { - handleMessage(event.data) - }, - { passive: true } - ) - } + workers.get(this.selectedCoin).handleStuckTradesConnectedWorker = this.inlineWorker(this.handleStuckTrades, modifiers) + workers.get(this.selectedCoin).handleStuckTradesConnectedWorker.postMessage(states) + workers.get(this.selectedCoin).handleStuckTradesConnectedWorker.addEventListener( + 'message', + function (event) { + handleMessage(event.data) + }, + { passive: true } + ) + } } window.customElements.define('trade-portal', TradePortal) diff --git a/qortal-ui-plugins/plugins/core/wallet/index.html b/qortal-ui-plugins/plugins/core/wallet/index.html index 0a791185..f45150ec 100644 --- a/qortal-ui-plugins/plugins/core/wallet/index.html +++ b/qortal-ui-plugins/plugins/core/wallet/index.html @@ -1,43 +1,45 @@ - - - - + *::-webkit-scrollbar-thumb { + background-color: var(--thumbBG); + border-radius: 6px; + border: 3px solid var(--scrollbarBG); + } + + html, + body { + margin: 0; + font-family: "Roboto", sans-serif; + background-color: #fff; + } + + + + + + + - - - - diff --git a/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js b/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js index d261be55..4ab57bfc 100644 --- a/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js +++ b/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js @@ -3,37 +3,35 @@ import { render } from 'lit/html.js' import { Epml } from '../../../epml.js' import '../components/ButtonIconCopy' - import '@material/mwc-icon' import '@material/mwc-button' import '@material/mwc-dialog' - import '@polymer/paper-spinner/paper-spinner-lite.js' -import '@vaadin/vaadin-grid/vaadin-grid.js' -import '@vaadin/vaadin-grid/theme/material/all-imports.js' - +import '@vaadin/grid/vaadin-grid.js' +import '@vaadin/grid/theme/material/all-imports.js' import '@github/time-elements' const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) -const coinsNames=['qort','btc','ltc','doge'] + +const coinsNames = ['qort', 'btc', 'ltc', 'doge'] class MultiWallet extends LitElement { - static get properties() { - return { - loading: { type: Boolean }, - transactions: { type: Object }, - lastBlock: { type: Object }, - selectedTransaction: { type: Object }, - isTextMenuOpen: { type: Boolean }, - wallets:{type : Map}, - _selectedWallet:'qort', - balanceString:'Fetching balance ...' - } - } + static get properties() { + return { + loading: { type: Boolean }, + transactions: { type: Object }, + lastBlock: { type: Object }, + selectedTransaction: { type: Object }, + isTextMenuOpen: { type: Boolean }, + wallets: { type: Map }, + _selectedWallet: 'qort', + balanceString: 'Fetching balance ...' + } + } - static get styles() { - return [ - css` + static get styles() { + return [ + css` #pages { display: flex; flex-wrap: wrap; @@ -114,7 +112,6 @@ class MultiWallet extends LitElement { table td, th { white-space: nowrap; - /* padding:10px; */ text-align: left; font-size: 14px; padding: 0 12px; @@ -151,8 +148,6 @@ class MultiWallet extends LitElement { padding: 0; } #transactionList > * { - /* padding-left:24px; - padding-right:24px; */ } .color-in { color: #02977e; @@ -254,7 +249,6 @@ class MultiWallet extends LitElement { border-top: 1px solid #e5e5e5; padding-top: 0px; height: 100%; - /* overflow: auto; */ } .show { @@ -339,7 +333,7 @@ class MultiWallet extends LitElement { background-repeat: no-repeat; background-size: cover; border-radius: 3px; - filter: grayscale(100%); + filter: grayscale(100%); } .currency-box.active .currency-image, .currency-box:hover .currency-image { @@ -473,65 +467,64 @@ class MultiWallet extends LitElement { } } `, - ] - } + ] + } - constructor() { - super() - - this.lastBlock = { - height: 0, - } - + constructor() { + super() - this.selectedTransaction = {} - this.isTextMenuOpen = false - this.loading = true + this.lastBlock = { + height: 0, + } - this.selectWallet = this.selectWallet.bind(this) - this.wallets=new Map() - let coinProp={ - balance:0, - wallet:null, - transactions:[], - fetchingWalletBalance:false, - fetchingWalletTransactions:false - } - coinsNames.forEach((c,i)=>{//reset fetching status, c:coin, i:index - this.wallets.set(c,{...coinProp}) - },this)//thisArg=this + this.selectedTransaction = {} + this.isTextMenuOpen = false + this.loading = true - this.wallets.get('qort').wallet = window.parent.reduxStore.getState().app.selectedAddress - this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet - this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet - this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet + this.selectWallet = this.selectWallet.bind(this) - this._selectedWallet='qort' + this.wallets = new Map() + let coinProp = { + balance: 0, + wallet: null, + transactions: [], + fetchingWalletBalance: false, + fetchingWalletTransactions: false + } + coinsNames.forEach((c, i) => { + this.wallets.set(c, { ...coinProp }) + }, this) - parentEpml.ready().then(() => { - parentEpml.subscribe('selected_address', async (selectedAddress) => { - selectedAddress = JSON.parse(selectedAddress) - if (!selectedAddress || Object.entries(selectedAddress).length === 0) return - - this.wallets.get('qort').wallet = selectedAddress - this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet - this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet - this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet - // this.updateAccountTransactions(); - }) + this.wallets.get('qort').wallet = window.parent.reduxStore.getState().app.selectedAddress + this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet + this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet + this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet - parentEpml.subscribe('copy_menu_switch', async (value) => { - if (value === 'false' && this.isTextMenuOpen === true) { - this.clearSelection() - this.isTextMenuOpen = false - } - }) - }) - } + this._selectedWallet = 'qort' - render() { - return html` + parentEpml.ready().then(() => { + parentEpml.subscribe('selected_address', async (selectedAddress) => { + selectedAddress = JSON.parse(selectedAddress) + if (!selectedAddress || Object.entries(selectedAddress).length === 0) return + + this.wallets.get('qort').wallet = selectedAddress + this.wallets.get('btc').wallet = window.parent.reduxStore.getState().app.selectedAddress.btcWallet + this.wallets.get('ltc').wallet = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet + this.wallets.get('doge').wallet = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet + }) + + parentEpml.subscribe('copy_menu_switch', async (value) => { + if (value === 'false' && this.isTextMenuOpen === true) { + this.clearSelection() + this.isTextMenuOpen = false + } + }) + }) + } + + render() { + return html`
Wallets
@@ -599,13 +592,11 @@ class MultiWallet extends LitElement { Receiver
${this.selectedTransaction.recipient}
- ${!this.selectedTransaction.amount - ? '' - : html` - Amount -
-
${this.selectedTransaction.amount} QORT
- `} + ${!this.selectedTransaction.amount ? '' : html` + Amount +
+
${this.selectedTransaction.amount} QORT
+ `} Transaction Fee
${this.selectedTransaction.fee}
@@ -626,52 +617,52 @@ class MultiWallet extends LitElement {
` - } + } - getSelectedWalletAddress() { - return this._selectedWallet === 'qort' - ? this.wallets.get(this._selectedWallet).wallet.address - : this.wallets.get(this._selectedWallet).wallet.address - } - + getSelectedWalletAddress() { + return this._selectedWallet === 'qort' + ? this.wallets.get(this._selectedWallet).wallet.address + : this.wallets.get(this._selectedWallet).wallet.address + } - async getTransactionGrid(coin) { - this.transactionsGrid = this.shadowRoot.querySelector(`#${coin}TransactionsGrid`) - if (coin === 'qort') { - this.transactionsGrid.addEventListener( - 'click', - (e) => { - let myItem = this.transactionsGrid.getEventContext(e).item - this.showTransactionDetails(myItem, this.wallets.get(this._selectedWallet).transactions) - }, - { passive: true } - ) - } - this.pagesControl = this.shadowRoot.querySelector('#pages') - this.pages = undefined - } + async getTransactionGrid(coin) { + this.transactionsGrid = this.shadowRoot.querySelector(`#${coin}TransactionsGrid`) + if (coin === 'qort') { + this.transactionsGrid.addEventListener( + 'click', + (e) => { + let myItem = this.transactionsGrid.getEventContext(e).item + this.showTransactionDetails(myItem, this.wallets.get(this._selectedWallet).transactions) + }, + { passive: true } + ) + } - async renderTransactions() { - if (this._selectedWallet === 'qort') { - render(this.renderQortTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM) - } else { - render(this.renderBTCLikeTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM) - } - } + this.pagesControl = this.shadowRoot.querySelector('#pages') + this.pages = undefined + } - renderQortTransactions(transactions, coin) { - const requiredConfirmations = 3 // arbitrary value - // initially `currentBlockHeight` might not be set in the store - const currentBlockHeight = window.parent.reduxStore.getState().app.blockInfo.height - if (Array.isArray(transactions)) { - transactions = transactions.map(tx => { - tx.confirmations = (currentBlockHeight - (tx.blockHeight - 1)) || '' - return tx - }) - } + async renderTransactions() { + if (this._selectedWallet === 'qort') { + render(this.renderQortTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM) + } else { + render(this.renderBTCLikeTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM) + } + } - return html` + renderQortTransactions(transactions, coin) { + const requiredConfirmations = 3 // arbitrary value + // initially `currentBlockHeight` might not be set in the store + const currentBlockHeight = window.parent.reduxStore.getState().app.blockInfo.height + if (Array.isArray(transactions)) { + transactions = transactions.map(tx => { + tx.confirmations = (currentBlockHeight - (tx.blockHeight - 1)) || '' + return tx + }) + } + + return html`