mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-11-02 05:37:58 +00:00
Merge remote-tracking branch 'main/master' into feature/improve-q-chat-speed
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -225,7 +225,6 @@ class ChatRightPanel extends LitElement {
|
||||
if(this.groupMembers.length < 20){
|
||||
return
|
||||
}
|
||||
console.log('this.leaveGroupObjp', this.leaveGroupObj)
|
||||
this.getMoreMembers(this.leaveGroupObj.groupId)
|
||||
}
|
||||
}
|
||||
@@ -252,7 +251,6 @@ class ChatRightPanel extends LitElement {
|
||||
activeChatHeadUrl=""
|
||||
.setActiveChatHeadUrl=${(val) => {
|
||||
if (val.address === this.myAddress) return;
|
||||
console.log({ val });
|
||||
this.selectedHead = val;
|
||||
this.setOpenUserInfo(true);
|
||||
this.setUserName({
|
||||
@@ -269,7 +267,6 @@ class ChatRightPanel extends LitElement {
|
||||
activeChatHeadUrl=""
|
||||
.setActiveChatHeadUrl=${(val) => {
|
||||
if (val.address === this.myAddress) return;
|
||||
console.log({ val });
|
||||
this.selectedHead = val;
|
||||
this.setOpenUserInfo(true);
|
||||
this.setUserName({
|
||||
@@ -286,7 +283,6 @@ class ChatRightPanel extends LitElement {
|
||||
activeChatHeadUrl=""
|
||||
.setActiveChatHeadUrl=${(val) => {
|
||||
if (val.address === this.myAddress) return;
|
||||
console.log({ val });
|
||||
this.selectedHead = val;
|
||||
this.setOpenUserInfo(true);
|
||||
this.setUserName({
|
||||
|
||||
@@ -101,7 +101,7 @@ function processText(input) {
|
||||
// Store the URL in a data attribute
|
||||
link.setAttribute('data-url', part)
|
||||
link.textContent = part
|
||||
link.style.color = 'var(--nav-text-color)'
|
||||
link.style.color = 'var(--code-block-text-color)'
|
||||
link.style.textDecoration = 'underline'
|
||||
link.style.cursor = 'pointer'
|
||||
|
||||
@@ -125,7 +125,7 @@ function processText(input) {
|
||||
url: `qdn/browser/index.html${query}`,
|
||||
id: uid(),
|
||||
myPlugObj: {
|
||||
"url": service === 'WEBSITE' ? "websites" : "qapps",
|
||||
"url": "myapp",
|
||||
"domain": "core",
|
||||
"page": `qdn/browser/index.html${query}`,
|
||||
"title": name,
|
||||
|
||||
@@ -506,21 +506,6 @@ mwc-checkbox::shadow .mdc-checkbox::after, mwc-checkbox::shadow .mdc-checkbox::b
|
||||
<button class="emoji-button" ?disabled=${this.isLoading || this.isLoadingMessages}>
|
||||
${html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg" />`}
|
||||
</button>
|
||||
${this.setOpenGifModal ?
|
||||
html`
|
||||
<button
|
||||
class="emoji-button"
|
||||
@click=${()=> {
|
||||
if (!this.userName) {
|
||||
parentEpml.request('showSnackBar', get("gifs.gchange26"));
|
||||
return;
|
||||
}
|
||||
this.setOpenGifModal(true)
|
||||
}}>
|
||||
<span style="font-size: 30px" class="material-symbols-outlined"></span>
|
||||
</button>
|
||||
`
|
||||
: ''}
|
||||
${this.editedMessageObj ? (
|
||||
html`
|
||||
<div style="margin-bottom: 10px">
|
||||
|
||||
@@ -19,6 +19,7 @@ export class TipUser extends LitElement {
|
||||
errorMessage: { type: String },
|
||||
successMessage: { type: String },
|
||||
setOpenTipUser: { attribute: false },
|
||||
qortPaymentFee: { type: Number }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +30,14 @@ export class TipUser extends LitElement {
|
||||
this.errorMessage = ""
|
||||
this.successMessage = ""
|
||||
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress
|
||||
this.qortPaymentFee = 0.01
|
||||
}
|
||||
|
||||
static styles = [tipUserStyles]
|
||||
|
||||
async firstUpdated() {
|
||||
await this.fetchWalletDetails()
|
||||
this.paymentFee()
|
||||
}
|
||||
|
||||
updated(changedProperties) {
|
||||
@@ -55,6 +58,28 @@ export class TipUser extends LitElement {
|
||||
return myRef
|
||||
}
|
||||
|
||||
async getSendQortFee() {
|
||||
let sendFee = await parentEpml.request('apiCall', {
|
||||
type: "api",
|
||||
url: `/transactions/unitfee?txType=PAYMENT`
|
||||
})
|
||||
return (Number(sendFee) / 1e8).toFixed(8)
|
||||
}
|
||||
|
||||
async paymentFee() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
const url = `${nodeUrl}/transactions/unitfee?txType=PAYMENT`
|
||||
await fetch(url).then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
return Promise.reject(response)
|
||||
}).then((json) => {
|
||||
this.qortPaymentFee = (Number(json) / 1e8).toFixed(8)
|
||||
})
|
||||
}
|
||||
|
||||
renderSuccessText() {
|
||||
return html`${translate("chatpage.cchange55")}`
|
||||
}
|
||||
@@ -79,62 +104,69 @@ export class TipUser extends LitElement {
|
||||
this.sendMoneyLoading = true
|
||||
this.btnDisable = true
|
||||
|
||||
if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.walletBalance)) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack1string = get("chatpage.cchange51")
|
||||
parentEpml.request('showSnackBar', `${snack1string}`)
|
||||
return false
|
||||
if (parseFloat(amount) + parseFloat(0.011) > parseFloat(this.walletBalance)) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack1string = get("chatpage.cchange51")
|
||||
parentEpml.request('showSnackBar', `${snack1string}`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (parseFloat(amount) <= 0) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack2string = get("chatpage.cchange52")
|
||||
parentEpml.request('showSnackBar', `${snack2string}`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (recipient.length === 0) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack3string = get("chatpage.cchange53")
|
||||
parentEpml.request('showSnackBar', `${snack3string}`)
|
||||
return false
|
||||
}
|
||||
|
||||
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 this.getLastRef()
|
||||
let theFee = await this.getSendQortFee()
|
||||
let isAddress
|
||||
|
||||
try {
|
||||
isAddress = await validateAddress(recipient)
|
||||
} catch (err) {
|
||||
isAddress = false
|
||||
}
|
||||
|
||||
if (parseFloat(amount) <= 0) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack2string = get("chatpage.cchange52")
|
||||
parentEpml.request('showSnackBar', `${snack2string}`)
|
||||
return false
|
||||
}
|
||||
|
||||
if (recipient.length === 0) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack3string = get("chatpage.cchange53")
|
||||
parentEpml.request('showSnackBar', `${snack3string}`)
|
||||
return false
|
||||
}
|
||||
|
||||
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 this.getLastRef()
|
||||
let isAddress
|
||||
|
||||
try {
|
||||
isAddress = await validateAddress(recipient)
|
||||
} catch (err) {
|
||||
isAddress = false
|
||||
}
|
||||
|
||||
if (isAddress) {
|
||||
let myTransaction = await makeTransactionRequest(recipient, lastRef)
|
||||
if (isAddress) {
|
||||
let myTransaction = await makeTransactionRequest(recipient, lastRef, theFee)
|
||||
getTxnRequestResponse(myTransaction)
|
||||
} else {
|
||||
let myNameRes = await validateName(recipient)
|
||||
if (myNameRes !== false) {
|
||||
let myNameAddress = myNameRes.owner
|
||||
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef, theFee)
|
||||
getTxnRequestResponse(myTransaction)
|
||||
} else {
|
||||
let myNameRes = await validateName(recipient)
|
||||
@@ -220,8 +252,61 @@ export class TipUser extends LitElement {
|
||||
validateReceiver(recipient)
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
const makeTransactionRequest = async (receiver, lastRef, theFee) => {
|
||||
let myReceiver = receiver
|
||||
let mylastRef = lastRef
|
||||
let myFee = theFee
|
||||
let dialogamount = get("transactions.amount")
|
||||
let dialogAddress = get("login.address")
|
||||
let dialogName = get("login.name")
|
||||
let dialogto = get("transactions.to")
|
||||
let recipientName = await getName(myReceiver)
|
||||
let myTxnrequest = await parentEpml.request('transaction', {
|
||||
type: 2,
|
||||
nonce: this.myAddress.nonce,
|
||||
params: {
|
||||
recipient: myReceiver,
|
||||
recipientName: recipientName,
|
||||
amount: amount,
|
||||
lastReference: mylastRef,
|
||||
fee: myFee,
|
||||
dialogamount: dialogamount,
|
||||
dialogto: dialogto,
|
||||
dialogAddress,
|
||||
dialogName
|
||||
},
|
||||
})
|
||||
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.errorMessage = ''
|
||||
this.successMessage = this.renderSuccessText()
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
setTimeout(() => {
|
||||
this.setOpenTipUser(false)
|
||||
this.successMessage = ""
|
||||
}, 3000)
|
||||
} else {
|
||||
this.errorMessage = txnResponse.data.message
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
throw new Error(txnResponse)
|
||||
}
|
||||
}
|
||||
validateReceiver(recipient)
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
<div class="tip-user-header">
|
||||
<img src="/img/qort.png" width="32" height="32">
|
||||
<p class="tip-user-header-font">${translate("chatpage.cchange43")} ${this.userName}</p>
|
||||
@@ -229,9 +314,9 @@ export class TipUser extends LitElement {
|
||||
<div class="tip-user-body">
|
||||
<p class="tip-available">${translate("chatpage.cchange47")}: ${this.walletBalance} QORT</p>
|
||||
<input id="amountInput" class="tip-input" type="number" placeholder="${translate("chatpage.cchange46")}" />
|
||||
<p class="tip-available">${translate("chatpage.cchange49")}: 0.001 QORT</p>
|
||||
${this.sendMoneyLoading ?
|
||||
html`
|
||||
<p class="tip-available">${translate("chatpage.cchange49")}: ${this.qortPaymentFee} QORT</p>
|
||||
${this.sendMoneyLoading ?
|
||||
html`
|
||||
<paper-progress indeterminate style="width: 100%; margin: 4px;">
|
||||
</paper-progress>`
|
||||
: html`
|
||||
|
||||
@@ -50,4 +50,13 @@ export const DECRYPT_DATA_GROUP = 'DECRYPT_DATA_GROUP'
|
||||
export const SAVE_FILE = 'SAVE_FILE'
|
||||
|
||||
//SET_TAB_NOTIFICATIONS
|
||||
export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
|
||||
export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
|
||||
|
||||
//OPEN_NEW_TAB
|
||||
export const OPEN_NEW_TAB = 'OPEN_NEW_TAB'
|
||||
|
||||
//NOTIFICATIONS_PERMISSION
|
||||
export const NOTIFICATIONS_PERMISSION = 'NOTIFICATIONS_PERMISSION'
|
||||
|
||||
//SEND_LOCAL_NOTIFICATION
|
||||
export const SEND_LOCAL_NOTIFICATION = 'SEND_LOCAL_NOTIFICATION'
|
||||
@@ -30,7 +30,6 @@ import '@vaadin/grid'
|
||||
passiveSupport({ events: ['touchstart'] })
|
||||
|
||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||
|
||||
class Chat extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
@@ -912,4 +911,4 @@ class Chat extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('q-chat', Chat)
|
||||
window.customElements.define('q-chat', Chat)
|
||||
@@ -3,6 +3,7 @@ import { render } from 'lit/html.js'
|
||||
import { Epml } from '../../../../epml'
|
||||
import isElectron from 'is-electron'
|
||||
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||
import ShortUniqueId from 'short-unique-id';
|
||||
|
||||
registerTranslateConfig({
|
||||
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json())
|
||||
@@ -131,6 +132,7 @@ class WebBrowser extends LitElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.url = 'about:blank';
|
||||
this.uid = new ShortUniqueId()
|
||||
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress
|
||||
this._publicKey = { key: '', hasPubKey: false }
|
||||
const urlParams = new URLSearchParams(window.location.search)
|
||||
@@ -318,6 +320,44 @@ class WebBrowser extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
async linkOpenNewTab(link) {
|
||||
|
||||
const value = link
|
||||
let newQuery = value;
|
||||
if (newQuery.endsWith('/')) {
|
||||
newQuery = newQuery.slice(0, -1);
|
||||
}
|
||||
const res = await this.extractComponents(newQuery)
|
||||
if (!res) return
|
||||
const { service, name, identifier, path } = res
|
||||
let query = `?service=${service}`
|
||||
if (name) {
|
||||
query = query + `&name=${name}`
|
||||
}
|
||||
if (identifier) {
|
||||
query = query + `&identifier=${identifier}`
|
||||
}
|
||||
if (path) {
|
||||
query = query + `&path=${path}`
|
||||
}
|
||||
|
||||
window.parent.reduxStore.dispatch(window.parent.reduxAction.setNewTab({
|
||||
url: `qdn/browser/index.html${query}`,
|
||||
id: this.uid(),
|
||||
myPlugObj: {
|
||||
"url": service === 'WEBSITE' ? "websites" : "qapps",
|
||||
"domain": "core",
|
||||
"page": `qdn/browser/index.html${query}`,
|
||||
"title": name,
|
||||
"icon": service === 'WEBSITE' ? 'vaadin:desktop' : 'vaadin:external-browser',
|
||||
"mwcicon": service === 'WEBSITE' ? 'desktop_mac' : 'open_in_browser',
|
||||
"menus": [],
|
||||
"parent": false
|
||||
}
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
return html`
|
||||
@@ -425,6 +465,23 @@ class WebBrowser extends LitElement {
|
||||
const joinFee = (Number(data) / 1e8).toFixed(8)
|
||||
return joinFee
|
||||
}
|
||||
async getArbitraryFee (){
|
||||
const timestamp = Date.now()
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
const url = `${nodeUrl}/transactions/unitfee?txType=ARBITRARY×tamp=${timestamp}`
|
||||
const response = await fetch(url)
|
||||
if (!response.ok) {
|
||||
throw new Error('Error when fetching arbitrary fee');
|
||||
}
|
||||
const data = await response.json()
|
||||
const arbitraryFee = (Number(data) / 1e8).toFixed(8)
|
||||
return {
|
||||
timestamp,
|
||||
fee : Number(data),
|
||||
feeToShow: arbitraryFee
|
||||
}
|
||||
}
|
||||
async sendQortFee() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
@@ -492,7 +549,7 @@ class WebBrowser extends LitElement {
|
||||
|
||||
}
|
||||
|
||||
async _deployAt(name, description, tags, creationBytes, amount, assetId, fee, atType) {
|
||||
async _deployAt(name, description, tags, creationBytes, amount, assetId, atType) {
|
||||
const deployAtFee = await this.deployAtFee()
|
||||
const getLastRef = async () => {
|
||||
let myRef = await parentEpml.request('apiCall', {
|
||||
@@ -510,13 +567,15 @@ class WebBrowser extends LitElement {
|
||||
}
|
||||
|
||||
const makeTransactionRequest = async (lastRef) => {
|
||||
let groupdialog1 = get("transactions.groupdialog1")
|
||||
let groupdialog2 = get("transactions.groupdialog2")
|
||||
let deployAtdialog1 = get("transactions.deployAtdialog1")
|
||||
let deployAtdialog2 = get("transactions.deployAtdialog2")
|
||||
let deployAtdialog3 = get("transactions.deployAtdialog3")
|
||||
let deployAtdialog4 = get("walletpage.wchange12")
|
||||
let myTxnrequest = await parentEpml.request('transaction', {
|
||||
type: 16,
|
||||
nonce: this.selectedAddress.nonce,
|
||||
params: {
|
||||
fee: fee || deployAtFee,
|
||||
fee: deployAtFee,
|
||||
rName: name,
|
||||
rDescription: description,
|
||||
rTags: tags,
|
||||
@@ -525,8 +584,10 @@ class WebBrowser extends LitElement {
|
||||
rCreationBytes: creationBytes,
|
||||
atType: atType,
|
||||
lastReference: lastRef,
|
||||
atDeployDialog1: groupdialog1,
|
||||
atDeployDialog2: groupdialog2
|
||||
atDeployDialog1: deployAtdialog1,
|
||||
atDeployDialog2: deployAtdialog2,
|
||||
atDeployDialog3: deployAtdialog3,
|
||||
atDeployDialog4: deployAtdialog4
|
||||
},
|
||||
apiVersion: 2
|
||||
})
|
||||
@@ -975,6 +1036,7 @@ class WebBrowser extends LitElement {
|
||||
const tag3 = data.tag3;
|
||||
const tag4 = data.tag4;
|
||||
const tag5 = data.tag5;
|
||||
let feeAmount = null
|
||||
if (data.identifier == null) {
|
||||
identifier = 'default';
|
||||
}
|
||||
@@ -994,6 +1056,8 @@ class WebBrowser extends LitElement {
|
||||
if (data.file) {
|
||||
data64 = await fileToBase64(data.file)
|
||||
}
|
||||
const getArbitraryFee = await this.getArbitraryFee()
|
||||
feeAmount = getArbitraryFee.fee
|
||||
|
||||
if (data.encrypt) {
|
||||
try {
|
||||
@@ -1014,6 +1078,7 @@ class WebBrowser extends LitElement {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const res2 = await showModalAndWait(
|
||||
@@ -1022,7 +1087,8 @@ class WebBrowser extends LitElement {
|
||||
name,
|
||||
identifier,
|
||||
service,
|
||||
encrypt: data.encrypt
|
||||
encrypt: data.encrypt,
|
||||
feeAmount: getArbitraryFee.feeToShow
|
||||
}
|
||||
);
|
||||
if (res2.action === 'accept') {
|
||||
@@ -1052,7 +1118,8 @@ class WebBrowser extends LitElement {
|
||||
tag4,
|
||||
tag5,
|
||||
apiVersion: 2,
|
||||
withFee: res2.userData.isWithFee === true ? true : false
|
||||
withFee: res2.userData.isWithFee === true ? true : false,
|
||||
feeAmount: feeAmount
|
||||
});
|
||||
|
||||
response = JSON.stringify(resPublish);
|
||||
@@ -1080,7 +1147,7 @@ class WebBrowser extends LitElement {
|
||||
case actions.PUBLISH_MULTIPLE_QDN_RESOURCES: {
|
||||
const requiredFields = ['resources'];
|
||||
const missingFields = [];
|
||||
|
||||
let feeAmount = null
|
||||
requiredFields.forEach((field) => {
|
||||
if (!data[field]) {
|
||||
missingFields.push(field);
|
||||
@@ -1114,11 +1181,14 @@ class WebBrowser extends LitElement {
|
||||
response = JSON.stringify(data);
|
||||
break
|
||||
}
|
||||
const getArbitraryFee = await this.getArbitraryFee()
|
||||
feeAmount = getArbitraryFee.fee
|
||||
const res2 = await showModalAndWait(
|
||||
actions.PUBLISH_MULTIPLE_QDN_RESOURCES,
|
||||
{
|
||||
resources,
|
||||
encrypt: data.encrypt
|
||||
encrypt: data.encrypt,
|
||||
feeAmount: getArbitraryFee.feeToShow
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1217,7 +1287,8 @@ class WebBrowser extends LitElement {
|
||||
tag4,
|
||||
tag5,
|
||||
apiVersion: 2,
|
||||
withFee: res2.userData.isWithFee === true ? true : false
|
||||
withFee: res2.userData.isWithFee === true ? true : false,
|
||||
feeAmount: feeAmount
|
||||
});
|
||||
|
||||
worker.terminate();
|
||||
@@ -1253,8 +1324,95 @@ class WebBrowser extends LitElement {
|
||||
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
|
||||
break;
|
||||
}
|
||||
case actions.OPEN_NEW_TAB: {
|
||||
if(!data.qortalLink){
|
||||
const obj = {};
|
||||
const errorMsg = 'Please enter a qortal link - qortal://...';
|
||||
obj['error'] = errorMsg;
|
||||
response = JSON.stringify(obj);
|
||||
break
|
||||
}
|
||||
|
||||
try {
|
||||
await this.linkOpenNewTab(data.qortalLink)
|
||||
response = true
|
||||
break;
|
||||
} catch (error) {
|
||||
console.log('error', error)
|
||||
const obj = {};
|
||||
const errorMsg = "Invalid qortal link";
|
||||
obj['error'] = errorMsg;
|
||||
response = JSON.stringify(obj);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
case actions.NOTIFICATIONS_PERMISSION: {
|
||||
try {
|
||||
|
||||
const res = await showModalAndWait(
|
||||
actions.NOTIFICATIONS_PERMISSION,
|
||||
{
|
||||
name: this.name
|
||||
}
|
||||
);
|
||||
if (res.action === 'accept'){
|
||||
this.addAppToNotificationList(this.name)
|
||||
response = true
|
||||
break;
|
||||
} else {
|
||||
response = false
|
||||
break;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
case actions.SEND_LOCAL_NOTIFICATION: {
|
||||
const {title, url, icon, message} = data
|
||||
try {
|
||||
const id = `appNotificationList-${this.selectedAddress.address}`
|
||||
const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null;
|
||||
if(!checkData || !checkData[this.name]) throw new Error('App not on permission list')
|
||||
const appInfo = checkData[this.name]
|
||||
const lastNotification = appInfo.lastNotification
|
||||
const interval = appInfo.interval
|
||||
if (lastNotification && interval) {
|
||||
const timeDifference = Date.now() - lastNotification;
|
||||
|
||||
if (timeDifference > interval) {
|
||||
parentEpml.request('showNotification', {
|
||||
title, type: "qapp-local-notification", sound: '', url, options: { body: message, icon, badge: icon }
|
||||
})
|
||||
response = true
|
||||
this.updateLastNotification(id, this.name)
|
||||
break;
|
||||
} else {
|
||||
throw new Error(`duration until another notification can be sent: ${interval - timeDifference}`)
|
||||
}
|
||||
} else if(!lastNotification){
|
||||
parentEpml.request('showNotification', {
|
||||
title, type: "qapp-local-notification", sound: '', url, options: { body: message, icon, badge: icon }
|
||||
})
|
||||
response = true
|
||||
this.updateLastNotification(id)
|
||||
break;
|
||||
} else {
|
||||
throw new Error(`invalid data`)
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
const obj = {};
|
||||
const errorMsg = error.message || "error in pushing notification";
|
||||
obj['error'] = errorMsg;
|
||||
response = JSON.stringify(obj);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
case actions.SEND_CHAT_MESSAGE: {
|
||||
const message = data.message;
|
||||
const recipient = data.destinationAddress;
|
||||
@@ -1618,41 +1776,41 @@ class WebBrowser extends LitElement {
|
||||
break;
|
||||
}
|
||||
|
||||
// case 'DEPLOY_AT': {
|
||||
// const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type'];
|
||||
// const missingFields = [];
|
||||
case 'DEPLOY_AT': {
|
||||
const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type'];
|
||||
const missingFields = [];
|
||||
|
||||
// requiredFields.forEach((field) => {
|
||||
// if (!data[field]) {
|
||||
// missingFields.push(field);
|
||||
// }
|
||||
// });
|
||||
requiredFields.forEach((field) => {
|
||||
if (!data[field] && data[field] !== 0) {
|
||||
missingFields.push(field);
|
||||
}
|
||||
});
|
||||
|
||||
// if (missingFields.length > 0) {
|
||||
// const missingFieldsString = missingFields.join(', ');
|
||||
// const errorMsg = `Missing fields: ${missingFieldsString}`
|
||||
// let data = {};
|
||||
// data['error'] = errorMsg;
|
||||
// response = JSON.stringify(data);
|
||||
// break
|
||||
// }
|
||||
if (missingFields.length > 0) {
|
||||
const missingFieldsString = missingFields.join(', ');
|
||||
const errorMsg = `Missing fields: ${missingFieldsString}`
|
||||
let data = {};
|
||||
data['error'] = errorMsg;
|
||||
response = JSON.stringify(data);
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
// try {
|
||||
// this.loader.show();
|
||||
// const fee = data.fee || undefined
|
||||
// const resJoinGroup = await this._deployAt(data.name, data.description, data.tags, data.creationBytes, data.amount, data.assetId, fee, data.type)
|
||||
// response = JSON.stringify(resJoinGroup);
|
||||
// } catch (error) {
|
||||
// const obj = {};
|
||||
// const errorMsg = error.message || 'Failed to join the group.';
|
||||
// obj['error'] = errorMsg;
|
||||
// response = JSON.stringify(obj);
|
||||
// } finally {
|
||||
// this.loader.hide();
|
||||
// }
|
||||
// break;
|
||||
// }
|
||||
try {
|
||||
this.loader.show();
|
||||
|
||||
const resDeployAt = await this._deployAt(data.name, data.description, data.tags, data.creationBytes, data.amount, data.assetId, data.type)
|
||||
response = JSON.stringify(resDeployAt);
|
||||
} catch (error) {
|
||||
const obj = {};
|
||||
const errorMsg = error.message || 'Failed to join the group.';
|
||||
obj['error'] = errorMsg;
|
||||
response = JSON.stringify(obj);
|
||||
} finally {
|
||||
this.loader.hide();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
case actions.GET_WALLET_BALANCE: {
|
||||
@@ -2707,6 +2865,46 @@ class WebBrowser extends LitElement {
|
||||
use(checkLanguage);
|
||||
}
|
||||
}
|
||||
addAppToNotificationList(appName) {
|
||||
if(!appName) throw new Error('unknown app name')
|
||||
const id = `appNotificationList-${this.selectedAddress.address}`;
|
||||
const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null;
|
||||
|
||||
if (!checkData) {
|
||||
const newData = {
|
||||
[appName]: {
|
||||
interval: 900000, // 15mins in milliseconds
|
||||
lastNotification: null,
|
||||
},
|
||||
};
|
||||
localStorage.setItem(id, JSON.stringify(newData));
|
||||
} else {
|
||||
const copyData = { ...checkData };
|
||||
copyData[appName] = {
|
||||
interval: 900000, // 15mins in milliseconds
|
||||
lastNotification: null,
|
||||
};
|
||||
localStorage.setItem(id, JSON.stringify(copyData));
|
||||
}
|
||||
}
|
||||
|
||||
updateLastNotification(id, appName) {
|
||||
const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null;
|
||||
|
||||
if (checkData) {
|
||||
const copyData = { ...checkData };
|
||||
if (copyData[appName]) {
|
||||
copyData[appName].lastNotification = Date.now(); // Make sure to use Date.now(), not date.now()
|
||||
} else {
|
||||
copyData[appName] = {
|
||||
interval: 900000, // 15mins in milliseconds
|
||||
lastNotification: Date.now(),
|
||||
};
|
||||
}
|
||||
localStorage.setItem(id, JSON.stringify(copyData));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
renderFollowUnfollowButton() {
|
||||
// Only show the follow/unfollow button if we have permission to modify the list on this node
|
||||
@@ -3000,10 +3198,7 @@ async function showModalAndWait(type, data) {
|
||||
`).join('')}
|
||||
</table>
|
||||
<div class="checkbox-row">
|
||||
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);">
|
||||
${get('browserpage.bchange33')} ${data.resources.length * 0.001} QORT fee
|
||||
</label>
|
||||
<mwc-checkbox checked style="margin-right: -15px;" id="isWithFee"></mwc-checkbox>
|
||||
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph">${get('browserpage.bchange47')} <span style="font-weight: bold">${data.resources.length * data.feeAmount} QORT fee</span></p>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
@@ -3016,10 +3211,7 @@ async function showModalAndWait(type, data) {
|
||||
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange32")}:</span> ${data.identifier}</p>
|
||||
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph"><span style="font-weight: bold">${get("browserpage.bchange45")}:</span> ${data.encrypt ? true : false}</p>
|
||||
<div class="checkbox-row">
|
||||
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);">
|
||||
${get('browserpage.bchange29')}
|
||||
</label>
|
||||
<mwc-checkbox checked style="margin-right: -15px;" id="isWithFee"></mwc-checkbox>
|
||||
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph">${get('browserpage.bchange47')} <span style="font-weight: bold">${data.feeAmount} QORT fee</span></p>
|
||||
</div>
|
||||
</div>
|
||||
` : ''}
|
||||
@@ -3064,7 +3256,12 @@ async function showModalAndWait(type, data) {
|
||||
<p class="modal-paragraph">${get("browserpage.bchange46")}: <span> ${data.filename}</span></p>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
${type === actions.NOTIFICATIONS_PERMISSION ? `
|
||||
<div class="modal-subcontainer">
|
||||
<p class="modal-paragraph">${get("browserpage.bchange48")}</p>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
${type === actions.DELETE_LIST_ITEM ? `
|
||||
<div class="modal-subcontainer">
|
||||
<p class="modal-paragraph">${get("browserpage.bchange44")}</p>
|
||||
@@ -3091,7 +3288,8 @@ async function showModalAndWait(type, data) {
|
||||
const userData = {};
|
||||
if (type === actions.PUBLISH_QDN_RESOURCE || type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES) {
|
||||
const isWithFeeCheckbox = modal.querySelector('#isWithFee');
|
||||
userData.isWithFee = isWithFeeCheckbox.checked;
|
||||
// userData.isWithFee = isWithFeeCheckbox.checked;
|
||||
userData.isWithFee = true
|
||||
}
|
||||
if (modal.parentNode === document.body) {
|
||||
document.body.removeChild(modal);
|
||||
|
||||
@@ -14,6 +14,7 @@ import '@material/mwc-select'
|
||||
import '@material/mwc-dialog'
|
||||
import '@material/mwc-list/mwc-list-item.js'
|
||||
import '@polymer/paper-progress/paper-progress.js'
|
||||
import { modalHelper } from '../../../utils/publish-modal'
|
||||
|
||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||
|
||||
@@ -299,8 +300,10 @@ class PublishData extends LitElement {
|
||||
<p style="color: green; word-break: break-word;">${this.successMessage}</p>
|
||||
${this.loading ? html` <paper-progress indeterminate style="width:100%; margin:4px;"></paper-progress> ` : ''}
|
||||
<div class="buttons">
|
||||
<mwc-button ?disabled=${this.btnDisable} style="width:49%;" raised icon="science" @click=${(e) => this.doPublish(e, true, false)}> ${translate("appspage.schange40")}</mwc-button>
|
||||
<mwc-button ?disabled=${this.btnDisable} style="width:49%;" raised icon="send" @click=${() => this.shadowRoot.querySelector('#publishWithFeeDialog').show()}> ${translate("publishpage.pchange11")}</mwc-button>
|
||||
<mwc-button ?disabled=${this.btnDisable} style="width:49%;" raised icon="science" @click=${(e) => this.shadowRoot.querySelector('#publishWithFeeDialog').close()}> ${translate("appspage.schange40")}</mwc-button>
|
||||
<mwc-button ?disabled=${this.btnDisable} style="width:49%;" raised icon="send" @click=${(e) => {
|
||||
this.doPublish(e, false, true)
|
||||
}}> ${translate("publishpage.pchange11")}</mwc-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -310,7 +313,7 @@ class PublishData extends LitElement {
|
||||
<mwc-button slot="primaryAction" @click="${(e) => this.feeDialogNo(e, false, false)}" class="red">
|
||||
${translate("general.no")}
|
||||
</mwc-button>
|
||||
<mwc-button slot="secondaryAction" @click="${(e) => this.feeDialogYes(e, false, true)}" class="green">
|
||||
<mwc-button slot="secondaryAction" @click="${(e) => this.feeDialogYes(e, false, true)}" class="green">
|
||||
${translate("general.yes")}
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
@@ -418,7 +421,7 @@ class PublishData extends LitElement {
|
||||
this.shadowRoot.querySelector('#publishWithFeeDialog').close()
|
||||
}
|
||||
|
||||
doPublish(e, preview, fee) {
|
||||
async doPublish(e, preview, fee) {
|
||||
let registeredName = this.shadowRoot.getElementById('registeredName').value
|
||||
let service = this.shadowRoot.getElementById('service').value
|
||||
let identifier = this.shadowRoot.getElementById('identifier').value
|
||||
@@ -464,7 +467,22 @@ class PublishData extends LitElement {
|
||||
parentEpml.request('showSnackBar', `${err5string}`)
|
||||
}
|
||||
else {
|
||||
this.publishData(registeredName, path, file, service, identifier, preview, fee)
|
||||
try {
|
||||
if(!preview){
|
||||
const arbitraryFeeData = await modalHelper.getArbitraryFee()
|
||||
const res = await modalHelper.showModalAndWaitPublish(
|
||||
{
|
||||
feeAmount: arbitraryFeeData.feeToShow
|
||||
}
|
||||
);
|
||||
if (res.action !== 'accept') throw new Error('User declined publish')
|
||||
}
|
||||
|
||||
this.publishData(registeredName, path, file, service, identifier, preview, fee)
|
||||
} catch (error) {
|
||||
this.shadowRoot.querySelector('#publishWithFeeDialog').close()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,6 +506,17 @@ class PublishData extends LitElement {
|
||||
this.successMessage = ''
|
||||
console.error(errorMessage)
|
||||
}
|
||||
const getArbitraryFee = async () => {
|
||||
const timestamp = Date.now()
|
||||
let fee = await parentEpml.request('apiCall', {
|
||||
url: `/transactions/unitfee?txType=ARBITRARY×tamp=${timestamp}`
|
||||
})
|
||||
return {
|
||||
timestamp,
|
||||
fee : Number(fee),
|
||||
feeToShow: (Number(fee) / 1e8).toFixed(8)
|
||||
}
|
||||
}
|
||||
|
||||
const validate = async () => {
|
||||
let validNameRes = await validateName(registeredName)
|
||||
@@ -501,8 +530,17 @@ class PublishData extends LitElement {
|
||||
this.generalMessage = `${err6string}`
|
||||
let transactionBytes
|
||||
let previewUrlPath
|
||||
let feeAmount = null
|
||||
|
||||
let uploadDataRes = await uploadData(registeredName, path, file, preview, fee)
|
||||
if(fee){
|
||||
const res = await getArbitraryFee()
|
||||
if(res.fee){
|
||||
feeAmount= res.fee
|
||||
} else {
|
||||
throw new Error('unable to get fee')
|
||||
}
|
||||
}
|
||||
let uploadDataRes = await uploadData(registeredName, path, file, preview, fee, feeAmount)
|
||||
|
||||
if (uploadDataRes.error) {
|
||||
let err7string = get("publishpage.pchange20")
|
||||
@@ -531,12 +569,13 @@ class PublishData extends LitElement {
|
||||
if (fee) {
|
||||
let err9string = get("publishpage.pchange26")
|
||||
this.generalMessage = `${err9string}`
|
||||
|
||||
} else {
|
||||
let err9string = get("publishpage.pchange22")
|
||||
this.generalMessage = `${err9string}`
|
||||
}
|
||||
|
||||
let signAndProcessRes = await signAndProcess(transactionBytes, fee)
|
||||
let signAndProcessRes = await signAndProcess(transactionBytes, fee, feeAmount)
|
||||
|
||||
if (signAndProcessRes.error) {
|
||||
let err10string = get("publishpage.pchange20")
|
||||
@@ -554,7 +593,9 @@ class PublishData extends LitElement {
|
||||
this.successMessage = `${err11string}`
|
||||
}
|
||||
|
||||
const uploadData = async (registeredName, path, file, preview, fee) => {
|
||||
|
||||
|
||||
const uploadData = async (registeredName, path, file, preview, fee, feeAmount) => {
|
||||
let postBody = path
|
||||
let urlSuffix = ""
|
||||
if (file != null) {
|
||||
@@ -592,9 +633,9 @@ class PublishData extends LitElement {
|
||||
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}&preview=${new Boolean(preview).toString()}`
|
||||
}
|
||||
} else if (fee) {
|
||||
uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&fee=100000&apiKey=${this.getApiKey()}`
|
||||
uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&fee=${feeAmount}&apiKey=${this.getApiKey()}`
|
||||
if (identifier != null && identifier.trim().length > 0) {
|
||||
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&fee=100000&apiKey=${this.getApiKey()}`
|
||||
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&fee=${feeAmount}&apiKey=${this.getApiKey()}`
|
||||
}
|
||||
} else {
|
||||
uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
|
||||
|
||||
@@ -2104,6 +2104,7 @@ class TradeBotPortal extends LitElement {
|
||||
|
||||
this.changeTheme()
|
||||
this.changeLanguage()
|
||||
this.tradeFee()
|
||||
|
||||
this.autoHelperMessage = this.renderAutoHelperPass()
|
||||
|
||||
@@ -3736,6 +3737,20 @@ class TradeBotPortal extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
async tradeFee() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
const url = `${nodeUrl}/transactions/unitfee?txType=DEPLOY_AT`
|
||||
await fetch(url).then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
return Promise.reject(response)
|
||||
}).then((json) => {
|
||||
this.listedCoins.get("QORTAL").tradeFee = (Number(json) + 100000) / 1e8
|
||||
})
|
||||
}
|
||||
|
||||
getApiKey() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
|
||||
let apiKey = myNode.apiKey;
|
||||
|
||||
@@ -708,7 +708,7 @@ class TradePortal extends LitElement {
|
||||
balance: "0",
|
||||
coinCode: "QORT",
|
||||
coinAmount: this.amountString,
|
||||
tradeFee: "0.002"
|
||||
tradeFee: "0.02"
|
||||
}
|
||||
|
||||
let bitcoin = {
|
||||
@@ -1421,6 +1421,7 @@ class TradePortal extends LitElement {
|
||||
|
||||
this.changeTheme()
|
||||
this.changeLanguage()
|
||||
this.tradeFee()
|
||||
|
||||
this.tradeHelperMessage = this.renderTradeHelperPass()
|
||||
|
||||
@@ -2698,6 +2699,7 @@ class TradePortal extends LitElement {
|
||||
async sellAction() {
|
||||
this.isSellLoading = true
|
||||
this.sellBtnDisable = true
|
||||
await this.tradeFee()
|
||||
const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value
|
||||
const sellTotalInput = this.shadowRoot.getElementById('sellTotalInput').value
|
||||
const fundingQortAmount = this.round(parseFloat(sellAmountInput) + 0.001)
|
||||
@@ -2732,7 +2734,7 @@ class TradePortal extends LitElement {
|
||||
fundingQortAmount: parseFloat(fundingQortAmount),
|
||||
foreignBlockchain: this.selectedCoin,
|
||||
foreignAmount: parseFloat(sellTotalInput),
|
||||
tradeTimeout: 60,
|
||||
tradeTimeout: 120,
|
||||
receivingAddress: _receivingAddress,
|
||||
})
|
||||
return response
|
||||
@@ -2758,7 +2760,7 @@ class TradePortal extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.round(parseFloat(fundingQortAmount) + parseFloat(0.002)) > parseFloat(this.listedCoins.get("QORTAL").balance)) {
|
||||
if (this.round(parseFloat(fundingQortAmount) + parseFloat(this.listedCoins.get("QORTAL").tradeFee)) > parseFloat(this.listedCoins.get("QORTAL").balance)) {
|
||||
this.isSellLoading = false
|
||||
this.sellBtnDisable = false
|
||||
let snack4string = get("tradepage.tchange22")
|
||||
@@ -3021,6 +3023,21 @@ class TradePortal extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
async tradeFee() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
const url = `${nodeUrl}/transactions/unitfee?txType=DEPLOY_AT`
|
||||
await fetch(url).then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
return Promise.reject(response)
|
||||
}).then((json) => {
|
||||
this.listedCoins.get("QORTAL").tradeFee = (Number(json) * 2) / 1e8
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
getApiKey() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
|
||||
let apiKey = myNode.apiKey;
|
||||
|
||||
@@ -75,6 +75,7 @@ class MultiWallet extends LitElement {
|
||||
isValidAmount: { type: Boolean },
|
||||
balance: { type: Number },
|
||||
balanceString: { type: String },
|
||||
qortPaymentFee: { type: Number },
|
||||
btcFeePerByte: { type: Number },
|
||||
ltcFeePerByte: { type: Number },
|
||||
dogeFeePerByte: { type: Number },
|
||||
@@ -795,6 +796,7 @@ class MultiWallet extends LitElement {
|
||||
this.dgbAmount = 0
|
||||
this.rvnAmount = 0
|
||||
this.arrrAmount = 0
|
||||
this.qortPaymentFee = 0.001
|
||||
this.btcFeePerByte = 100
|
||||
this.btcSatMinFee = 20
|
||||
this.btcSatMaxFee = 150
|
||||
@@ -1352,7 +1354,7 @@ class MultiWallet extends LitElement {
|
||||
</mwc-textfield>
|
||||
</p>
|
||||
<div style="margin-bottom: 10px;">
|
||||
<p style="margin-bottom: 0;">${translate("walletpage.wchange21")} <span style="font-weight: bold;">0.001 QORT<span></p>
|
||||
<p style="margin-bottom: 0;">${translate("walletpage.wchange21")} <span style="font-weight: bold;">${this.qortPaymentFee} QORT<span></p>
|
||||
</div>
|
||||
${this.renderClearSuccess()}
|
||||
${this.renderClearError()}
|
||||
@@ -2821,6 +2823,7 @@ class MultiWallet extends LitElement {
|
||||
firstUpdated() {
|
||||
this.changeTheme()
|
||||
this.changeLanguage()
|
||||
this.paymentFee()
|
||||
|
||||
this.bookQortalAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||
this.bookBitcoinAddress = window.parent.reduxStore.getState().app.selectedAddress.btcWallet.address
|
||||
@@ -2906,6 +2909,23 @@ class MultiWallet extends LitElement {
|
||||
setInterval(() => {
|
||||
this.clearConsole()
|
||||
}, 60000)
|
||||
setInterval(() => {
|
||||
this.paymentFee()
|
||||
}, 600000)
|
||||
}
|
||||
|
||||
async paymentFee() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
const url = `${nodeUrl}/transactions/unitfee?txType=PAYMENT`
|
||||
await fetch(url).then((response) => {
|
||||
if (response.ok) {
|
||||
return response.json()
|
||||
}
|
||||
return Promise.reject(response)
|
||||
}).then((json) => {
|
||||
this.qortPaymentFee = (Number(json) / 1e8).toFixed(8)
|
||||
})
|
||||
}
|
||||
|
||||
clearConsole() {
|
||||
@@ -4048,11 +4068,11 @@ class MultiWallet extends LitElement {
|
||||
calculateQortAll() {
|
||||
this.amount = 0
|
||||
this.shadowRoot.getElementById('amountInput').value = this.amount
|
||||
if (this.balance < 0.00110000) {
|
||||
if (this.balance < 0.01100000) {
|
||||
let not_enough_string = get("walletpage.wchange26")
|
||||
parentEpml.request('showSnackBar', `${not_enough_string}`)
|
||||
} else {
|
||||
this.amount = (this.balance - 0.00110000).toFixed(8)
|
||||
this.amount = (this.balance - 0.01100000).toFixed(8)
|
||||
this.shadowRoot.getElementById('amountInput').value = this.amount
|
||||
this.shadowRoot.getElementById('amountInput').blur()
|
||||
this.shadowRoot.getElementById('amountInput').focus()
|
||||
@@ -4238,7 +4258,7 @@ class MultiWallet extends LitElement {
|
||||
} else {
|
||||
const checkQortAmountInput = this.shadowRoot.getElementById('amountInput').value
|
||||
const checkQortAmount = this.round(parseFloat(checkQortAmountInput))
|
||||
const myFunds = this.round(parseFloat(this.balance - 0.00110000))
|
||||
const myFunds = this.round(parseFloat(this.balance - 0.01100000))
|
||||
if (Number(myFunds) >= Number(checkQortAmount)) {
|
||||
this.shadowRoot.getElementById('amountInput').value = checkQortAmountInput
|
||||
this.btnDisable = false
|
||||
@@ -4269,7 +4289,7 @@ class MultiWallet extends LitElement {
|
||||
} else {
|
||||
const checkQortAmountInput = this.shadowRoot.getElementById('amountInput').value
|
||||
const checkQortAmount = this.round(parseFloat(checkQortAmountInput))
|
||||
const myFunds = this.round(parseFloat(this.balance - 0.00110000))
|
||||
const myFunds = this.round(parseFloat(this.balance - 0.01100000))
|
||||
if (Number(myFunds) >= Number(checkQortAmount)) {
|
||||
this.shadowRoot.getElementById('amountInput').value = checkQortAmountInput
|
||||
this.btnDisable = false
|
||||
@@ -4287,7 +4307,7 @@ class MultiWallet extends LitElement {
|
||||
} else {
|
||||
const checkQortAmountInput = this.shadowRoot.getElementById('amountInput').value
|
||||
const checkQortAmount = this.round(parseFloat(checkQortAmountInput))
|
||||
const myFunds = this.round(parseFloat(this.balance - 0.00110000))
|
||||
const myFunds = this.round(parseFloat(this.balance - 0.01100000))
|
||||
if (Number(myFunds) >= Number(checkQortAmount)) {
|
||||
this.shadowRoot.getElementById('amountInput').value = checkQortAmountInput
|
||||
this.btnDisable = false
|
||||
@@ -4302,6 +4322,7 @@ class MultiWallet extends LitElement {
|
||||
}
|
||||
|
||||
async sendQort() {
|
||||
const sendFee = this.qortPaymentFee
|
||||
const amount = this.shadowRoot.getElementById('amountInput').value
|
||||
let recipient = this.shadowRoot.getElementById('recipient').value
|
||||
|
||||
@@ -4390,11 +4411,10 @@ class MultiWallet extends LitElement {
|
||||
|
||||
const getName = async (recipient)=> {
|
||||
try {
|
||||
|
||||
const getNames = await parentEpml.request("apiCall", {
|
||||
type: "api",
|
||||
url: `/names/address/${recipient}`,
|
||||
})
|
||||
type: "api",
|
||||
url: `/names/address/${recipient}`,
|
||||
})
|
||||
if(getNames?.length > 0 ){
|
||||
return getNames[0].name
|
||||
} else {
|
||||
@@ -4421,7 +4441,7 @@ class MultiWallet extends LitElement {
|
||||
recipientName: recipientName,
|
||||
amount: amount,
|
||||
lastReference: mylastRef,
|
||||
fee: 0.001,
|
||||
fee: sendFee,
|
||||
dialogamount: dialogamount,
|
||||
dialogto: dialogto,
|
||||
dialogAddress,
|
||||
|
||||
@@ -28,7 +28,8 @@ export const publishData = async ({
|
||||
tag2,
|
||||
tag3,
|
||||
tag4,
|
||||
tag5
|
||||
tag5,
|
||||
feeAmount
|
||||
}) => {
|
||||
const validateName = async (receiverName) => {
|
||||
let nameRes = await parentEpml.request("apiCall", {
|
||||
@@ -48,6 +49,17 @@ export const publishData = async ({
|
||||
})
|
||||
return convertedBytes
|
||||
}
|
||||
const getArbitraryFee = async () => {
|
||||
const timestamp = Date.now()
|
||||
let fee = await parentEpml.request('apiCall', {
|
||||
url: `/transactions/unitfee?txType=ARBITRARY×tamp=${timestamp}`
|
||||
})
|
||||
return {
|
||||
timestamp,
|
||||
fee : Number(fee),
|
||||
feeToShow: (Number(fee) / 1e8).toFixed(8)
|
||||
}
|
||||
}
|
||||
|
||||
const signAndProcess = async (transactionBytesBase58) => {
|
||||
let convertedBytesBase58 = await convertBytesForSigning(
|
||||
@@ -125,7 +137,18 @@ export const publishData = async ({
|
||||
if (validNameRes.error) {
|
||||
throw new Error('Name not found');
|
||||
}
|
||||
let transactionBytes = await uploadData(registeredName, path, file)
|
||||
let fee = null
|
||||
if(withFee && feeAmount){
|
||||
fee= feeAmount
|
||||
} else if(withFee){
|
||||
const res = await getArbitraryFee()
|
||||
if(res.fee){
|
||||
fee= res.fee
|
||||
} else {
|
||||
throw new Error('unable to get fee')
|
||||
}
|
||||
}
|
||||
let transactionBytes = await uploadData(registeredName, path, file, fee)
|
||||
if (transactionBytes.error) {
|
||||
throw new Error(transactionBytes.message || 'Error when uploading');
|
||||
} else if (
|
||||
@@ -149,7 +172,7 @@ export const publishData = async ({
|
||||
return signAndProcessRes
|
||||
}
|
||||
|
||||
const uploadData = async (registeredName, path, file) => {
|
||||
const uploadData = async (registeredName, path, file, fee) => {
|
||||
if (identifier != null && identifier.trim().length > 0) {
|
||||
let postBody = path
|
||||
let urlSuffix = ""
|
||||
@@ -181,7 +204,7 @@ export const publishData = async ({
|
||||
}
|
||||
|
||||
if(withFee){
|
||||
uploadDataUrl = uploadDataUrl + '&fee=100000'
|
||||
uploadDataUrl = uploadDataUrl + `&fee=${fee}`
|
||||
}
|
||||
|
||||
if(filename != null && filename != "undefined"){
|
||||
|
||||
147
plugins/plugins/utils/publish-modal.css
Normal file
147
plugins/plugins/utils/publish-modal.css
Normal file
@@ -0,0 +1,147 @@
|
||||
.backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgb(186 186 186 / 26%);
|
||||
overflow: hidden;
|
||||
animation: backdrop_blur cubic-bezier(0.22, 1, 0.36, 1) 1s forwards;
|
||||
z-index: 1000000;
|
||||
}
|
||||
|
||||
@keyframes backdrop_blur {
|
||||
0% {
|
||||
backdrop-filter: blur(0px);
|
||||
background: transparent;
|
||||
}
|
||||
100% {
|
||||
backdrop-filter: blur(5px);
|
||||
background: rgb(186 186 186 / 26%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes modal_transition {
|
||||
0% {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: 1s cubic-bezier(0.22, 1, 0.36, 1) 0s 1 normal forwards running modal_transition;
|
||||
z-index: 1000001;
|
||||
}
|
||||
|
||||
@keyframes modal_transition {
|
||||
0% {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: var(--white);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
max-width: 80%;
|
||||
min-width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.modal-subcontainer {
|
||||
color: var(--black);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.modal-subcontainer-error {
|
||||
color: var(--black);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.modal-paragraph-error {
|
||||
font-family: Roboto, sans-serif;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.3px;
|
||||
font-weight: 700;
|
||||
color: var(--black);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-paragraph {
|
||||
font-family: Roboto, sans-serif;
|
||||
font-size: 18px;
|
||||
letter-spacing: 0.3px;
|
||||
font-weight: 300;
|
||||
color: var(--black);
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.capitalize-first {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.checkbox-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: Montserrat, sans-serif;
|
||||
font-weight: 600;
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.modal-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.modal-buttons button {
|
||||
background-color: #4caf50;
|
||||
border: none;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.modal-buttons button:hover {
|
||||
background-color: #3e8e41;
|
||||
}
|
||||
|
||||
#cancel-button {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
#cancel-button:hover {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
270
plugins/plugins/utils/publish-modal.js
Normal file
270
plugins/plugins/utils/publish-modal.js
Normal file
@@ -0,0 +1,270 @@
|
||||
import { get } from 'lit-translate';
|
||||
|
||||
export class ModalHelper {
|
||||
constructor() {
|
||||
this.initializeStyles();
|
||||
}
|
||||
|
||||
async getArbitraryFee() {
|
||||
const timestamp = Date.now();
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
|
||||
const nodeUrl = `${myNode.protocol}://${myNode.domain}:${myNode.port}`;
|
||||
const url = `${nodeUrl}/transactions/unitfee?txType=ARBITRARY×tamp=${timestamp}`;
|
||||
const response = await fetch(url);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Error when fetching arbitrary fee');
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
const arbitraryFee = (Number(data) / 1e8).toFixed(8);
|
||||
return {
|
||||
timestamp,
|
||||
fee: Number(data),
|
||||
feeToShow: arbitraryFee
|
||||
};
|
||||
}
|
||||
|
||||
async showModalAndWaitPublish(data) {
|
||||
return new Promise((resolve) => {
|
||||
const modal = this.createModal(data);
|
||||
document.body.appendChild(modal);
|
||||
this.addModalEventListeners(modal, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
createModal(data) {
|
||||
const modal = document.createElement('div');
|
||||
modal.id = "backdrop";
|
||||
modal.classList.add("backdrop");
|
||||
modal.innerHTML = `
|
||||
<div class="modal my-modal-class">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<div class="modal-subcontainer">
|
||||
<div class="checkbox-row">
|
||||
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph">${get('browserpage.bchange47')} <span style="font-weight: bold">${data.feeAmount} QORT fee</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-buttons">
|
||||
<button id="cancel-button">${get("browserpage.bchange27")}</button>
|
||||
<button id="ok-button">${get("browserpage.bchange28")}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
return modal;
|
||||
}
|
||||
|
||||
addModalEventListeners(modal, resolve) {
|
||||
// Event listener for the 'OK' button
|
||||
const okButton = modal.querySelector('#ok-button');
|
||||
okButton.addEventListener('click', () => {
|
||||
const userData = { isWithFee: true };
|
||||
if (modal.parentNode === document.body) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
resolve({ action: 'accept', userData });
|
||||
});
|
||||
|
||||
// Prevent modal content from closing the modal
|
||||
const modalContent = modal.querySelector('.modal-content');
|
||||
modalContent.addEventListener('click', e => {
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
// Event listeners for backdrop and 'Cancel' button
|
||||
const backdropClick = document.getElementById('backdrop');
|
||||
backdropClick.addEventListener('click', () => {
|
||||
if (modal.parentNode === document.body) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
resolve({ action: 'reject' });
|
||||
});
|
||||
|
||||
const cancelButton = modal.querySelector('#cancel-button');
|
||||
cancelButton.addEventListener('click', () => {
|
||||
if (modal.parentNode === document.body) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
resolve({ action: 'reject' });
|
||||
});
|
||||
}
|
||||
|
||||
initializeStyles() {
|
||||
const styles = `
|
||||
* {
|
||||
--mdc-theme-primary: rgb(3, 169, 244);
|
||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
||||
--paper-input-container-focus-color: var(--mdc-theme-primary);
|
||||
--mdc-checkbox-unchecked-color: var(--black);
|
||||
--mdc-theme-on-surface: var(--black);
|
||||
--mdc-checkbox-disabled-color: var(--black);
|
||||
--mdc-checkbox-ink-color: var(--black);
|
||||
}
|
||||
|
||||
.backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgb(186 186 186 / 26%);
|
||||
overflow: hidden;
|
||||
animation: backdrop_blur cubic-bezier(0.22, 1, 0.36, 1) 0.1s forwards;
|
||||
z-index: 1000000;
|
||||
}
|
||||
|
||||
@keyframes backdrop_blur {
|
||||
0% {
|
||||
backdrop-filter: blur(0px);
|
||||
background: transparent;
|
||||
}
|
||||
100% {
|
||||
backdrop-filter: blur(5px);
|
||||
background: rgb(186 186 186 / 26%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes modal_transition {
|
||||
0% {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
animation: 0.1s cubic-bezier(0.22, 1, 0.36, 1) 0s 1 normal forwards running modal_transition;
|
||||
z-index: 1000001;
|
||||
}
|
||||
|
||||
@keyframes modal_transition {
|
||||
0% {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
}
|
||||
100% {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
background-color: var(--white);
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
|
||||
max-width: 80%;
|
||||
min-width: 300px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
.modal-subcontainer {
|
||||
color: var(--black);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.modal-subcontainer-error {
|
||||
color: var(--black);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.modal-paragraph-error {
|
||||
font-family: Roboto, sans-serif;
|
||||
font-size: 20px;
|
||||
letter-spacing: 0.3px;
|
||||
font-weight: 700;
|
||||
color: var(--black);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.modal-paragraph {
|
||||
font-family: Roboto, sans-serif;
|
||||
font-size: 18px;
|
||||
letter-spacing: 0.3px;
|
||||
font-weight: 300;
|
||||
color: var(--black);
|
||||
margin: 0;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.capitalize-first {
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.checkbox-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: Montserrat, sans-serif;
|
||||
font-weight: 600;
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
.modal-buttons {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.modal-buttons button {
|
||||
background-color: #4caf50;
|
||||
border: none;
|
||||
color: #fff;
|
||||
padding: 10px 20px;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.2s;
|
||||
}
|
||||
|
||||
.modal-buttons button:hover {
|
||||
background-color: #3e8e41;
|
||||
}
|
||||
|
||||
#cancel-button {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
#cancel-button:hover {
|
||||
background-color: #d32f2f;
|
||||
}
|
||||
`;
|
||||
|
||||
const styleSheet = new CSSStyleSheet();
|
||||
styleSheet.replaceSync(styles);
|
||||
|
||||
document.adoptedStyleSheets = [styleSheet];
|
||||
}
|
||||
|
||||
static getInstance() {
|
||||
if (!ModalHelper.instance) {
|
||||
ModalHelper.instance = new ModalHelper();
|
||||
}
|
||||
return ModalHelper.instance;
|
||||
}
|
||||
}
|
||||
|
||||
export const modalHelper = ModalHelper.getInstance();
|
||||
Reference in New Issue
Block a user