mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-02-11 17:55:51 +00:00
Merge remote-tracking branch 'origin/master' into feature/notification-and-other-fixes
This commit is contained in:
commit
e422fa434e
@ -27,7 +27,7 @@ Easiest way to install the lastest required packages on Linux is via nvm.
|
||||
``` source ~/.profile ``` (For Debian based distro) <br/>
|
||||
``` source ~/.bashrc ``` (For Fedora / CentOS) <br/>
|
||||
``` nvm ls-remote ``` (Fetch list of available versions) <br/>
|
||||
``` nvm install v18.15.0 ``` (LTS: Hydrogen supported by Electron) <br/>
|
||||
``` nvm install v18.16.1 ``` (LTS: Hydrogen supported by Electron) <br/>
|
||||
``` npm --location=global install npm@9.8.1 ``` <br/>
|
||||
|
||||
Adding via binary package mirror will only work if you have set the package path. You can do a node or java build via ports instead by downloading ports with portsnap fetch method.
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Erteilen Sie dieser Anwendung die Erlaubnis, diese Liste hinzuzufügen?",
|
||||
"bchange44": "Erteilen Sie dieser Anwendung die Erlaubnis, sie von dieser Liste zu löschen?",
|
||||
"bchange45": "Verschlüsseln",
|
||||
"bchange46": "Geben Sie dieser Anwendung die Erlaubnis, die folgende Datei zu speichern?"
|
||||
"bchange46": "Geben Sie dieser Anwendung die Erlaubnis, die folgende Datei zu speichern?",
|
||||
"bchange47": "Sofortige Veröffentlichung – erforderlich"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Datenmanagement",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "¿Le das permiso a esta aplicación para agregar a esta lista?",
|
||||
"bchange44": "¿Le das permiso a esta aplicación para eliminar de esta lista?",
|
||||
"bchange45": "Cifrar",
|
||||
"bchange46": "¿Le das permiso a esta aplicación para guardar el siguiente archivo?"
|
||||
"bchange46": "¿Le das permiso a esta aplicación para guardar el siguiente archivo?",
|
||||
"bchange47": "Publicación instantánea - requiere"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Gestión de datos",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Autorisez-vous cette application à ajouter à cette liste ?",
|
||||
"bchange44": "Autorisez-vous cette application à supprimer de cette liste ?",
|
||||
"bchange45": "Crypter",
|
||||
"bchange46": "Autorisez-vous cette application à enregistrer le fichier suivant"
|
||||
"bchange46": "Autorisez-vous cette application à enregistrer le fichier suivant",
|
||||
"bchange47": "Publication instantanée - nécessite"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Gestion de données",
|
||||
|
@ -718,7 +718,8 @@
|
||||
"bchange43": "क्या आप इस एप्लिकेशन को इस सूची में जोड़ने की अनुमति देते हैं?",
|
||||
"bchange44": "क्या आप इस एप्लिकेशन को इस सूची से हटाने की अनुमति देते हैं?",
|
||||
"bchange45": "एन्क्रिप्ट",
|
||||
"bchange46": "क्या आप इस एप्लिकेशन को निम्न फ़ाइल सहेजने की अनुमति देते हैं"
|
||||
"bchange46": "क्या आप इस एप्लिकेशन को निम्न फ़ाइल सहेजने की अनुमति देते हैं",
|
||||
"bchange47": "तत्काल प्रकाशन - आवश्यक है"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "डाटा प्रबंधन",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Dajete li ovoj aplikaciji dopuštenje za dodavanje na ovaj popis?",
|
||||
"bchange44": "Dajete li ovoj aplikaciji dopuštenje za brisanje s ovog popisa?",
|
||||
"bchange45": "Šifriraj",
|
||||
"bchange46": "Dajete li ovoj aplikaciji dopuštenje za spremanje sljedeće datoteke"
|
||||
"bchange46": "Dajete li ovoj aplikaciji dopuštenje za spremanje sljedeće datoteke",
|
||||
"bchange47": "Trenutno objavljivanje - zahtijeva"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Upravljanje podacima",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Engedélyt ad ennek az alkalmazásnak, hogy felvegye ezt a listát?",
|
||||
"bchange44": "Engedélyezi ennek az alkalmazásnak, hogy töröljön erről a listáról?",
|
||||
"bchange45": "Titkosítás",
|
||||
"bchange46": "Engedélyezi ennek az alkalmazásnak a következő fájl mentését"
|
||||
"bchange46": "Engedélyezi ennek az alkalmazásnak a következő fájl mentését",
|
||||
"bchange47": "Azonnali közzététel – szükséges"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Adatkezelés",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Concedi a questa applicazione il permesso di aggiungersi a questa lista?",
|
||||
"bchange44": "Concedi a questa applicazione il permesso di eliminare da questo elenco?",
|
||||
"bchange45": "Cripta",
|
||||
"bchange46": "Concedi a questa applicazione il permesso di salvare il seguente file"
|
||||
"bchange46": "Concedi a questa applicazione il permesso di salvare il seguente file",
|
||||
"bchange47": "Pubblicazione istantanea - richiede"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Gestione dati",
|
||||
|
@ -720,7 +720,8 @@
|
||||
"bchange43": "このアプリケーションにこのリストに追加する事を許可しますか?",
|
||||
"bchange44": "このアプリケーションにこのリストから削除する事を許可しますか?",
|
||||
"bchange45": "暗号化",
|
||||
"bchange46": "このアプリケーションに次のファイルを保存する事を許可しますか?"
|
||||
"bchange46": "このアプリケーションに次のファイルを保存する事を許可しますか?",
|
||||
"bchange47": "インスタント公開 - が必要です"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "データ管理",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "이 목록에 추가할 수 있는 권한을 이 응용 프로그램에 부여하시겠습니까?",
|
||||
"bchange44": "이 목록에서 삭제할 수 있는 권한을 이 애플리케이션에 부여하시겠습니까?",
|
||||
"bchange45": "암호화",
|
||||
"bchange46": "이 응용 프로그램에 다음 파일을 저장할 권한을 부여하시겠습니까?"
|
||||
"bchange46": "이 응용 프로그램에 다음 파일을 저장할 권한을 부여하시겠습니까?",
|
||||
"bchange47": "즉시 게시 - 필요"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "데이터 관리",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Gir du denne applikasjonen tillatelse til å legge til denne listen?",
|
||||
"bchange44": "Gir du denne applikasjonen tillatelse til å slette fra denne listen?",
|
||||
"bchange45": "Krypter",
|
||||
"bchange46": "Gir du dette programmet tillatelse til å lagre følgende fil"
|
||||
"bchange46": "Gir du dette programmet tillatelse til å lagre følgende fil",
|
||||
"bchange47": "Øyeblikkelig publisering - krever"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Data-administrasjon",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Czy zezwalasz tej aplikacji na dodanie do tej listy?",
|
||||
"bchange44": "Czy zezwalasz tej aplikacji na usunięcie z tej listy?",
|
||||
"bchange45": "Szyfruj",
|
||||
"bchange46": "Czy zezwalasz tej aplikacji na zapisanie następującego pliku"
|
||||
"bchange46": "Czy zezwalasz tej aplikacji na zapisanie następującego pliku",
|
||||
"bchange47": "Błyskawiczna publikacja - wymaga"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Zarządzanie danymi",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Você dá a este aplicativo permissão para adicionar a esta lista?",
|
||||
"bchange44": "Você dá a este aplicativo permissão para deletar desta lista?",
|
||||
"bchange45": "Criptografar",
|
||||
"bchange46": "Você concede permissão a este aplicativo para salvar o seguinte arquivo"
|
||||
"bchange46": "Você concede permissão a este aplicativo para salvar o seguinte arquivo",
|
||||
"bchange47": "Publicação instantânea - requer"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Gerenciamento de Dados",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Oferiți acestei aplicații permisiunea de a adăuga la această listă?",
|
||||
"bchange44": "Oferiți acestei aplicații permisiunea de a șterge din această listă?",
|
||||
"bchange45": "Criptați",
|
||||
"bchange46": "Dați această aplicație permisiunea de a salva următorul fișier"
|
||||
"bchange46": "Dați această aplicație permisiunea de a salva următorul fișier",
|
||||
"bchange47": "Publicare instantanee - necesită"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Gestionare date",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Da li dajete ovoj aplikaciji dozvolu za dodavanje na ovu listu?",
|
||||
"bchange44": "Da li ovoj aplikaciji dajete dozvolu za brisanje sa ove liste?",
|
||||
"bchange45": "Šifrovanje",
|
||||
"bchange46": "Da li ovoj aplikaciji dajete dozvolu da sačuva sledeću datoteku"
|
||||
"bchange46": "Da li ovoj aplikaciji dajete dozvolu da sačuva sledeću datoteku",
|
||||
"bchange47": "Trenutno objavljivanje - zahteva"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Upravljanje podacima",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "Даете ли вы этому приложению разрешение на добавление в этот список?",
|
||||
"bchange44": "Даете ли вы этому приложению разрешение на удаление из этого списка?",
|
||||
"bchange45": "Шифровать",
|
||||
"bchange46": "Даете ли вы этому приложению разрешение на сохранение следующего файла?"
|
||||
"bchange46": "Даете ли вы этому приложению разрешение на сохранение следующего файла?",
|
||||
"bchange47": "Мгновенная публикация - требуется"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Управление данными",
|
||||
|
@ -721,7 +721,8 @@
|
||||
"bchange44": "Do you give this application permission to delete from this list?",
|
||||
"bchange45": "Encrypt",
|
||||
"bchange46": "Do you give this application permission to save the following file",
|
||||
"bchange47": "Do you give this application permission to send you notifications"
|
||||
"bchange47": "Instant publish - requires",
|
||||
"bchange48": "Do you give this application permission to send you notifications"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "Data Management",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "您授予此应用程序添加到此列表的权限吗?",
|
||||
"bchange44": "您授予此应用程序从列表中删除的权限吗?",
|
||||
"bchange45": "加密",
|
||||
"bchange46": "您是否授予此应用程序保存以下文件的权限"
|
||||
"bchange46": "您是否授予此应用程序保存以下文件的权限",
|
||||
"bchange47": "即时发布 - 需要"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "资料管理",
|
||||
|
@ -717,7 +717,8 @@
|
||||
"bchange43": "您授予此應用程序添加到此列表的權限嗎?",
|
||||
"bchange44": "您授予此應用程序從列表中刪除的權限嗎?",
|
||||
"bchange45": "加密",
|
||||
"bchange46": "您是否授予此應用程序保存以下文件的權限"
|
||||
"bchange46": "您是否授予此應用程序保存以下文件的權限",
|
||||
"bchange47": "即時發布 - 需要"
|
||||
},
|
||||
"datapage": {
|
||||
"dchange1": "資料管理",
|
||||
|
@ -119,11 +119,11 @@ class AppInfo extends connect(store)(LitElement) {
|
||||
this.setStorage()
|
||||
this.getNodeInfo()
|
||||
this.getCoreInfo()
|
||||
try {
|
||||
this.confirmPublicKeyOnChain(store.getState().app.selectedAddress.address)
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
// try {
|
||||
// this.confirmPublicKeyOnChain(store.getState().app.selectedAddress.address)
|
||||
// } catch (error) {
|
||||
// console.error(error)
|
||||
// }
|
||||
|
||||
setInterval(() => {
|
||||
this.getNodeInfo()
|
||||
|
@ -3047,4 +3047,5 @@ class AppView extends connect(store)(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('app-view', AppView)
|
||||
window.customElements.define('app-view', AppView)
|
||||
|
||||
|
920
package-lock.json
generated
920
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
30
package.json
30
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "qortal-ui",
|
||||
"version": "4.3.1",
|
||||
"version": "4.3.2",
|
||||
"description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet",
|
||||
"keywords": [
|
||||
"QORT",
|
||||
@ -54,9 +54,9 @@
|
||||
"prosemirror-model": "1.19.3",
|
||||
"prosemirror-schema-list": "1.3.0",
|
||||
"prosemirror-state": "1.4.3",
|
||||
"prosemirror-transform": "1.7.4",
|
||||
"prosemirror-transform": "1.7.5",
|
||||
"prosemirror-view": "1.31.7",
|
||||
"sass": "1.65.1",
|
||||
"sass": "1.66.1",
|
||||
"short-unique-id": "4.4.4",
|
||||
"@hapi/hapi": "21.3.2",
|
||||
"@hapi/inert": "7.1.0",
|
||||
@ -72,9 +72,9 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"axios": "1.4.0",
|
||||
"electron": "25.5.0",
|
||||
"electron": "26.1.0",
|
||||
"electron-builder": "24.6.3",
|
||||
"electron-packager": "17.1.1",
|
||||
"electron-packager": "17.1.2",
|
||||
"epml": "0.3.3",
|
||||
"file-saver": "2.0.5",
|
||||
"highcharts": "11.1.0",
|
||||
@ -86,12 +86,12 @@
|
||||
"passive-events-support": "1.1.0",
|
||||
"redux": "4.2.1",
|
||||
"redux-thunk": "2.4.2",
|
||||
"rollup": "3.28.0",
|
||||
"rollup": "3.28.1",
|
||||
"rollup-plugin-node-globals": "1.4.0",
|
||||
"rollup-plugin-progress": "1.1.2",
|
||||
"rollup-plugin-scss": "3.0.0",
|
||||
"shelljs": "0.8.5",
|
||||
"@babel/core": "7.22.10",
|
||||
"@babel/core": "7.22.11",
|
||||
"@material/mwc-button": "0.27.0",
|
||||
"@material/mwc-checkbox": "0.27.0",
|
||||
"@material/mwc-dialog": "0.27.0",
|
||||
@ -131,18 +131,18 @@
|
||||
"@rollup/plugin-alias": "5.0.0",
|
||||
"@rollup/plugin-babel": "6.0.3",
|
||||
"@rollup/plugin-commonjs": "25.0.4",
|
||||
"@rollup/plugin-node-resolve": "15.1.0",
|
||||
"@rollup/plugin-node-resolve": "15.2.1",
|
||||
"@rollup/plugin-replace": "5.0.2",
|
||||
"@rollup/plugin-terser": "0.4.3",
|
||||
"@vaadin/avatar": "24.1.5",
|
||||
"@vaadin/button": "24.1.5",
|
||||
"@vaadin/grid": "24.1.5",
|
||||
"@vaadin/icons": "24.1.5",
|
||||
"@vaadin/password-field": "24.1.5",
|
||||
"@vaadin/tooltip": "24.1.5",
|
||||
"@vaadin/avatar": "24.1.6",
|
||||
"@vaadin/button": "24.1.6",
|
||||
"@vaadin/grid": "24.1.6",
|
||||
"@vaadin/icons": "24.1.6",
|
||||
"@vaadin/password-field": "24.1.6",
|
||||
"@vaadin/tooltip": "24.1.6",
|
||||
"@zip.js/zip.js": "2.7.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.15.0"
|
||||
"node": ">=18.16.1"
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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">
|
||||
|
@ -9,32 +9,35 @@ import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } fro
|
||||
const parentEpml = new Epml({ type: "WINDOW", source: window.parent });
|
||||
|
||||
export class TipUser extends LitElement {
|
||||
static get properties() {
|
||||
return {
|
||||
userName: { type: String },
|
||||
walletBalance: { type: Number },
|
||||
sendMoneyLoading: { type: Boolean },
|
||||
closeTipUser: { type: Boolean },
|
||||
btnDisable: { type: Boolean },
|
||||
errorMessage: { type: String },
|
||||
successMessage: { type: String },
|
||||
setOpenTipUser: { attribute: false },
|
||||
static get properties() {
|
||||
return {
|
||||
userName: { type: String },
|
||||
walletBalance: { type: Number },
|
||||
sendMoneyLoading: { type: Boolean },
|
||||
closeTipUser: { type: Boolean },
|
||||
btnDisable: { type: Boolean },
|
||||
errorMessage: { type: String },
|
||||
successMessage: { type: String },
|
||||
setOpenTipUser: { attribute: false },
|
||||
qortPaymentFee: { type: Number }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
constructor() {
|
||||
super()
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
this.errorMessage = ""
|
||||
this.successMessage = ""
|
||||
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress
|
||||
this.qortPaymentFee = 0.01
|
||||
}
|
||||
|
||||
static styles = [tipUserStyles]
|
||||
|
||||
async firstUpdated() {
|
||||
await this.fetchWalletDetails()
|
||||
async firstUpdated() {
|
||||
await this.fetchWalletDetails()
|
||||
this.paymentFee()
|
||||
}
|
||||
|
||||
updated(changedProperties) {
|
||||
@ -48,12 +51,34 @@ export class TipUser extends LitElement {
|
||||
}
|
||||
|
||||
async getLastRef() {
|
||||
let myRef = await parentEpml.request("apiCall", {
|
||||
type: "api",
|
||||
url: `/addresses/lastreference/${this.myAddress.address}`,
|
||||
})
|
||||
return myRef
|
||||
}
|
||||
let myRef = await parentEpml.request("apiCall", {
|
||||
type: "api",
|
||||
url: `/addresses/lastreference/${this.myAddress.address}`,
|
||||
})
|
||||
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")}`
|
||||
@ -89,7 +114,7 @@ export class TipUser extends LitElement {
|
||||
this.sendMoneyLoading = true
|
||||
this.btnDisable = true
|
||||
|
||||
if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.walletBalance)) {
|
||||
if (parseFloat(amount) + parseFloat(0.011) > parseFloat(this.walletBalance)) {
|
||||
this.sendMoneyLoading = false
|
||||
this.btnDisable = false
|
||||
let snack1string = get("chatpage.cchange51")
|
||||
@ -125,7 +150,7 @@ export class TipUser extends LitElement {
|
||||
} else {
|
||||
myRes = myNameRes
|
||||
}
|
||||
return myRes;
|
||||
return myRes
|
||||
}
|
||||
|
||||
const validateAddress = async (receiverAddress) => {
|
||||
@ -135,6 +160,7 @@ export class TipUser extends LitElement {
|
||||
|
||||
const validateReceiver = async (recipient) => {
|
||||
let lastRef = await this.getLastRef()
|
||||
let theFee = await this.getSendQortFee()
|
||||
let isAddress
|
||||
|
||||
try {
|
||||
@ -144,13 +170,13 @@ export class TipUser extends LitElement {
|
||||
}
|
||||
|
||||
if (isAddress) {
|
||||
let myTransaction = await makeTransactionRequest(recipient, lastRef)
|
||||
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)
|
||||
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef, theFee)
|
||||
getTxnRequestResponse(myTransaction)
|
||||
} else {
|
||||
console.error(this.renderReceiverText())
|
||||
@ -178,9 +204,10 @@ export class TipUser extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
const makeTransactionRequest = async (receiver, lastRef) => {
|
||||
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")
|
||||
@ -194,7 +221,7 @@ export class TipUser extends LitElement {
|
||||
recipientName: recipientName,
|
||||
amount: amount,
|
||||
lastReference: mylastRef,
|
||||
fee: 0.001,
|
||||
fee: myFee,
|
||||
dialogamount: dialogamount,
|
||||
dialogto: dialogto,
|
||||
dialogAddress,
|
||||
@ -239,7 +266,7 @@ 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>
|
||||
<p class="tip-available">${translate("chatpage.cchange49")}: ${this.qortPaymentFee} QORT</p>
|
||||
${this.sendMoneyLoading ?
|
||||
html`
|
||||
<paper-progress indeterminate style="width: 100%; margin: 4px;">
|
||||
|
@ -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 {
|
||||
@ -910,4 +909,4 @@ class Chat extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('q-chat', Chat)
|
||||
window.customElements.define('q-chat', Chat)
|
@ -465,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
|
||||
@ -1015,6 +1032,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';
|
||||
}
|
||||
@ -1034,6 +1052,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 {
|
||||
@ -1054,6 +1074,7 @@ class WebBrowser extends LitElement {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
const res2 = await showModalAndWait(
|
||||
@ -1062,7 +1083,8 @@ class WebBrowser extends LitElement {
|
||||
name,
|
||||
identifier,
|
||||
service,
|
||||
encrypt: data.encrypt
|
||||
encrypt: data.encrypt,
|
||||
feeAmount: getArbitraryFee.feeToShow
|
||||
}
|
||||
);
|
||||
if (res2.action === 'accept') {
|
||||
@ -1092,7 +1114,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);
|
||||
@ -1120,7 +1143,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);
|
||||
@ -1154,11 +1177,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
|
||||
}
|
||||
);
|
||||
|
||||
@ -1257,7 +1283,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();
|
||||
@ -3163,10 +3190,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>
|
||||
` : ''}
|
||||
@ -3179,10 +3203,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>
|
||||
` : ''}
|
||||
@ -3229,7 +3250,7 @@ async function showModalAndWait(type, data) {
|
||||
` : ''}
|
||||
${type === actions.NOTIFICATIONS_PERMISSION ? `
|
||||
<div class="modal-subcontainer">
|
||||
<p class="modal-paragraph">${get("browserpage.bchange47")}</p>
|
||||
<p class="modal-paragraph">${get("browserpage.bchange48")}</p>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
@ -3259,7 +3280,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()}`
|
||||
|
@ -708,7 +708,7 @@ class TradePortal extends LitElement {
|
||||
balance: "0",
|
||||
coinCode: "QORT",
|
||||
coinAmount: this.amountString,
|
||||
tradeFee: "0.002"
|
||||
tradeFee: "0.02"
|
||||
}
|
||||
|
||||
let bitcoin = {
|
||||
@ -2699,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)
|
||||
@ -2733,7 +2734,7 @@ class TradePortal extends LitElement {
|
||||
fundingQortAmount: parseFloat(fundingQortAmount),
|
||||
foreignBlockchain: this.selectedCoin,
|
||||
foreignAmount: parseFloat(sellTotalInput),
|
||||
tradeTimeout: 60,
|
||||
tradeTimeout: 120,
|
||||
receivingAddress: _receivingAddress,
|
||||
})
|
||||
return response
|
||||
@ -3032,10 +3033,11 @@ class TradePortal extends LitElement {
|
||||
}
|
||||
return Promise.reject(response)
|
||||
}).then((json) => {
|
||||
this.listedCoins.get("QORTAL").tradeFee = (Number(json) + 100000) / 1e8
|
||||
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;
|
||||
|
@ -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();
|
Loading…
x
Reference in New Issue
Block a user