Merge remote-tracking branch 'origin/master' into feature/notification-and-other-fixes

This commit is contained in:
Phillip 2023-08-25 23:30:33 -05:00
commit e422fa434e
33 changed files with 1544 additions and 1183 deletions

View File

@ -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 ~/.profile ``` (For Debian based distro) <br/>
``` source ~/.bashrc ``` (For Fedora / CentOS) <br/> ``` source ~/.bashrc ``` (For Fedora / CentOS) <br/>
``` nvm ls-remote ``` (Fetch list of available versions) <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/> ``` 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. 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.

View File

@ -717,7 +717,8 @@
"bchange43": "Erteilen Sie dieser Anwendung die Erlaubnis, diese Liste hinzuzufügen?", "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?", "bchange44": "Erteilen Sie dieser Anwendung die Erlaubnis, sie von dieser Liste zu löschen?",
"bchange45": "Verschlüsseln", "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": { "datapage": {
"dchange1": "Datenmanagement", "dchange1": "Datenmanagement",

View File

@ -717,7 +717,8 @@
"bchange43": "¿Le das permiso a esta aplicación para agregar a esta lista?", "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?", "bchange44": "¿Le das permiso a esta aplicación para eliminar de esta lista?",
"bchange45": "Cifrar", "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": { "datapage": {
"dchange1": "Gestión de datos", "dchange1": "Gestión de datos",

View File

@ -717,7 +717,8 @@
"bchange43": "Autorisez-vous cette application à ajouter à cette liste ?", "bchange43": "Autorisez-vous cette application à ajouter à cette liste ?",
"bchange44": "Autorisez-vous cette application à supprimer de cette liste ?", "bchange44": "Autorisez-vous cette application à supprimer de cette liste ?",
"bchange45": "Crypter", "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": { "datapage": {
"dchange1": "Gestion de données", "dchange1": "Gestion de données",

View File

@ -718,7 +718,8 @@
"bchange43": "क्या आप इस एप्लिकेशन को इस सूची में जोड़ने की अनुमति देते हैं?", "bchange43": "क्या आप इस एप्लिकेशन को इस सूची में जोड़ने की अनुमति देते हैं?",
"bchange44": "क्या आप इस एप्लिकेशन को इस सूची से हटाने की अनुमति देते हैं?", "bchange44": "क्या आप इस एप्लिकेशन को इस सूची से हटाने की अनुमति देते हैं?",
"bchange45": "एन्क्रिप्ट", "bchange45": "एन्क्रिप्ट",
"bchange46": "क्या आप इस एप्लिकेशन को निम्न फ़ाइल सहेजने की अनुमति देते हैं" "bchange46": "क्या आप इस एप्लिकेशन को निम्न फ़ाइल सहेजने की अनुमति देते हैं",
"bchange47": "तत्काल प्रकाशन - आवश्यक है"
}, },
"datapage": { "datapage": {
"dchange1": "डाटा प्रबंधन", "dchange1": "डाटा प्रबंधन",

View File

@ -717,7 +717,8 @@
"bchange43": "Dajete li ovoj aplikaciji dopuštenje za dodavanje na ovaj popis?", "bchange43": "Dajete li ovoj aplikaciji dopuštenje za dodavanje na ovaj popis?",
"bchange44": "Dajete li ovoj aplikaciji dopuštenje za brisanje s ovog popisa?", "bchange44": "Dajete li ovoj aplikaciji dopuštenje za brisanje s ovog popisa?",
"bchange45": "Šifriraj", "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": { "datapage": {
"dchange1": "Upravljanje podacima", "dchange1": "Upravljanje podacima",

View File

@ -717,7 +717,8 @@
"bchange43": "Engedélyt ad ennek az alkalmazásnak, hogy felvegye ezt a listát?", "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?", "bchange44": "Engedélyezi ennek az alkalmazásnak, hogy töröljön erről a listáról?",
"bchange45": "Titkosítás", "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": { "datapage": {
"dchange1": "Adatkezelés", "dchange1": "Adatkezelés",

View File

@ -717,7 +717,8 @@
"bchange43": "Concedi a questa applicazione il permesso di aggiungersi a questa lista?", "bchange43": "Concedi a questa applicazione il permesso di aggiungersi a questa lista?",
"bchange44": "Concedi a questa applicazione il permesso di eliminare da questo elenco?", "bchange44": "Concedi a questa applicazione il permesso di eliminare da questo elenco?",
"bchange45": "Cripta", "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": { "datapage": {
"dchange1": "Gestione dati", "dchange1": "Gestione dati",

View File

@ -720,7 +720,8 @@
"bchange43": "このアプリケーションにこのリストに追加する事を許可しますか?", "bchange43": "このアプリケーションにこのリストに追加する事を許可しますか?",
"bchange44": "このアプリケーションにこのリストから削除する事を許可しますか?", "bchange44": "このアプリケーションにこのリストから削除する事を許可しますか?",
"bchange45": "暗号化", "bchange45": "暗号化",
"bchange46": "このアプリケーションに次のファイルを保存する事を許可しますか?" "bchange46": "このアプリケーションに次のファイルを保存する事を許可しますか?",
"bchange47": "インスタント公開 - が必要です"
}, },
"datapage": { "datapage": {
"dchange1": "データ管理", "dchange1": "データ管理",

View File

@ -717,7 +717,8 @@
"bchange43": "이 목록에 추가할 수 있는 권한을 이 응용 프로그램에 부여하시겠습니까?", "bchange43": "이 목록에 추가할 수 있는 권한을 이 응용 프로그램에 부여하시겠습니까?",
"bchange44": "이 목록에서 삭제할 수 있는 권한을 이 애플리케이션에 부여하시겠습니까?", "bchange44": "이 목록에서 삭제할 수 있는 권한을 이 애플리케이션에 부여하시겠습니까?",
"bchange45": "암호화", "bchange45": "암호화",
"bchange46": "이 응용 프로그램에 다음 파일을 저장할 권한을 부여하시겠습니까?" "bchange46": "이 응용 프로그램에 다음 파일을 저장할 권한을 부여하시겠습니까?",
"bchange47": "즉시 게시 - 필요"
}, },
"datapage": { "datapage": {
"dchange1": "데이터 관리", "dchange1": "데이터 관리",

View File

@ -717,7 +717,8 @@
"bchange43": "Gir du denne applikasjonen tillatelse til å legge til denne listen?", "bchange43": "Gir du denne applikasjonen tillatelse til å legge til denne listen?",
"bchange44": "Gir du denne applikasjonen tillatelse til å slette fra denne listen?", "bchange44": "Gir du denne applikasjonen tillatelse til å slette fra denne listen?",
"bchange45": "Krypter", "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": { "datapage": {
"dchange1": "Data-administrasjon", "dchange1": "Data-administrasjon",

View File

@ -717,7 +717,8 @@
"bchange43": "Czy zezwalasz tej aplikacji na dodanie do tej listy?", "bchange43": "Czy zezwalasz tej aplikacji na dodanie do tej listy?",
"bchange44": "Czy zezwalasz tej aplikacji na usunięcie z tej listy?", "bchange44": "Czy zezwalasz tej aplikacji na usunięcie z tej listy?",
"bchange45": "Szyfruj", "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": { "datapage": {
"dchange1": "Zarządzanie danymi", "dchange1": "Zarządzanie danymi",

View File

@ -717,7 +717,8 @@
"bchange43": "Você dá a este aplicativo permissão para adicionar a esta lista?", "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?", "bchange44": "Você dá a este aplicativo permissão para deletar desta lista?",
"bchange45": "Criptografar", "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": { "datapage": {
"dchange1": "Gerenciamento de Dados", "dchange1": "Gerenciamento de Dados",

View File

@ -717,7 +717,8 @@
"bchange43": "Oferiți acestei aplicații permisiunea de a adăuga la această listă?", "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ă?", "bchange44": "Oferiți acestei aplicații permisiunea de a șterge din această listă?",
"bchange45": "Criptați", "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": { "datapage": {
"dchange1": "Gestionare date", "dchange1": "Gestionare date",

View File

@ -717,7 +717,8 @@
"bchange43": "Da li dajete ovoj aplikaciji dozvolu za dodavanje na ovu listu?", "bchange43": "Da li dajete ovoj aplikaciji dozvolu za dodavanje na ovu listu?",
"bchange44": "Da li ovoj aplikaciji dajete dozvolu za brisanje sa ove liste?", "bchange44": "Da li ovoj aplikaciji dajete dozvolu za brisanje sa ove liste?",
"bchange45": "Šifrovanje", "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": { "datapage": {
"dchange1": "Upravljanje podacima", "dchange1": "Upravljanje podacima",

View File

@ -717,7 +717,8 @@
"bchange43": "Даете ли вы этому приложению разрешение на добавление в этот список?", "bchange43": "Даете ли вы этому приложению разрешение на добавление в этот список?",
"bchange44": "Даете ли вы этому приложению разрешение на удаление из этого списка?", "bchange44": "Даете ли вы этому приложению разрешение на удаление из этого списка?",
"bchange45": "Шифровать", "bchange45": "Шифровать",
"bchange46": "Даете ли вы этому приложению разрешение на сохранение следующего файла?" "bchange46": "Даете ли вы этому приложению разрешение на сохранение следующего файла?",
"bchange47": "Мгновенная публикация - требуется"
}, },
"datapage": { "datapage": {
"dchange1": "Управление данными", "dchange1": "Управление данными",

View File

@ -721,7 +721,8 @@
"bchange44": "Do you give this application permission to delete from this list?", "bchange44": "Do you give this application permission to delete from this list?",
"bchange45": "Encrypt", "bchange45": "Encrypt",
"bchange46": "Do you give this application permission to save the following file", "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": { "datapage": {
"dchange1": "Data Management", "dchange1": "Data Management",

View File

@ -717,7 +717,8 @@
"bchange43": "您授予此应用程序添加到此列表的权限吗?", "bchange43": "您授予此应用程序添加到此列表的权限吗?",
"bchange44": "您授予此应用程序从列表中删除的权限吗?", "bchange44": "您授予此应用程序从列表中删除的权限吗?",
"bchange45": "加密", "bchange45": "加密",
"bchange46": "您是否授予此应用程序保存以下文件的权限" "bchange46": "您是否授予此应用程序保存以下文件的权限",
"bchange47": "即时发布 - 需要"
}, },
"datapage": { "datapage": {
"dchange1": "资料管理", "dchange1": "资料管理",

View File

@ -717,7 +717,8 @@
"bchange43": "您授予此應用程序添加到此列表的權限嗎?", "bchange43": "您授予此應用程序添加到此列表的權限嗎?",
"bchange44": "您授予此應用程序從列表中刪除的權限嗎?", "bchange44": "您授予此應用程序從列表中刪除的權限嗎?",
"bchange45": "加密", "bchange45": "加密",
"bchange46": "您是否授予此應用程序保存以下文件的權限" "bchange46": "您是否授予此應用程序保存以下文件的權限",
"bchange47": "即時發布 - 需要"
}, },
"datapage": { "datapage": {
"dchange1": "資料管理", "dchange1": "資料管理",

View File

@ -119,11 +119,11 @@ class AppInfo extends connect(store)(LitElement) {
this.setStorage() this.setStorage()
this.getNodeInfo() this.getNodeInfo()
this.getCoreInfo() this.getCoreInfo()
try { // try {
this.confirmPublicKeyOnChain(store.getState().app.selectedAddress.address) // this.confirmPublicKeyOnChain(store.getState().app.selectedAddress.address)
} catch (error) { // } catch (error) {
console.error(error) // console.error(error)
} // }
setInterval(() => { setInterval(() => {
this.getNodeInfo() this.getNodeInfo()

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{ {
"name": "qortal-ui", "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", "description": "Qortal Project - decentralize the world - Data storage, communications, web hosting, decentralized trading, complete infrastructure for the future blockchain-based Internet",
"keywords": [ "keywords": [
"QORT", "QORT",
@ -54,9 +54,9 @@
"prosemirror-model": "1.19.3", "prosemirror-model": "1.19.3",
"prosemirror-schema-list": "1.3.0", "prosemirror-schema-list": "1.3.0",
"prosemirror-state": "1.4.3", "prosemirror-state": "1.4.3",
"prosemirror-transform": "1.7.4", "prosemirror-transform": "1.7.5",
"prosemirror-view": "1.31.7", "prosemirror-view": "1.31.7",
"sass": "1.65.1", "sass": "1.66.1",
"short-unique-id": "4.4.4", "short-unique-id": "4.4.4",
"@hapi/hapi": "21.3.2", "@hapi/hapi": "21.3.2",
"@hapi/inert": "7.1.0", "@hapi/inert": "7.1.0",
@ -72,9 +72,9 @@
}, },
"devDependencies": { "devDependencies": {
"axios": "1.4.0", "axios": "1.4.0",
"electron": "25.5.0", "electron": "26.1.0",
"electron-builder": "24.6.3", "electron-builder": "24.6.3",
"electron-packager": "17.1.1", "electron-packager": "17.1.2",
"epml": "0.3.3", "epml": "0.3.3",
"file-saver": "2.0.5", "file-saver": "2.0.5",
"highcharts": "11.1.0", "highcharts": "11.1.0",
@ -86,12 +86,12 @@
"passive-events-support": "1.1.0", "passive-events-support": "1.1.0",
"redux": "4.2.1", "redux": "4.2.1",
"redux-thunk": "2.4.2", "redux-thunk": "2.4.2",
"rollup": "3.28.0", "rollup": "3.28.1",
"rollup-plugin-node-globals": "1.4.0", "rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-progress": "1.1.2", "rollup-plugin-progress": "1.1.2",
"rollup-plugin-scss": "3.0.0", "rollup-plugin-scss": "3.0.0",
"shelljs": "0.8.5", "shelljs": "0.8.5",
"@babel/core": "7.22.10", "@babel/core": "7.22.11",
"@material/mwc-button": "0.27.0", "@material/mwc-button": "0.27.0",
"@material/mwc-checkbox": "0.27.0", "@material/mwc-checkbox": "0.27.0",
"@material/mwc-dialog": "0.27.0", "@material/mwc-dialog": "0.27.0",
@ -131,18 +131,18 @@
"@rollup/plugin-alias": "5.0.0", "@rollup/plugin-alias": "5.0.0",
"@rollup/plugin-babel": "6.0.3", "@rollup/plugin-babel": "6.0.3",
"@rollup/plugin-commonjs": "25.0.4", "@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-replace": "5.0.2",
"@rollup/plugin-terser": "0.4.3", "@rollup/plugin-terser": "0.4.3",
"@vaadin/avatar": "24.1.5", "@vaadin/avatar": "24.1.6",
"@vaadin/button": "24.1.5", "@vaadin/button": "24.1.6",
"@vaadin/grid": "24.1.5", "@vaadin/grid": "24.1.6",
"@vaadin/icons": "24.1.5", "@vaadin/icons": "24.1.6",
"@vaadin/password-field": "24.1.5", "@vaadin/password-field": "24.1.6",
"@vaadin/tooltip": "24.1.5", "@vaadin/tooltip": "24.1.6",
"@zip.js/zip.js": "2.7.24" "@zip.js/zip.js": "2.7.24"
}, },
"engines": { "engines": {
"node": ">=18.15.0" "node": ">=18.16.1"
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -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}> <button class="emoji-button" ?disabled=${this.isLoading || this.isLoadingMessages}>
${html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg" />`} ${html`<img class="emoji" draggable="false" alt="😀" src="/emoji/svg/1f600.svg" />`}
</button> </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">&#xe7a3;</span>
</button>
`
: ''}
${this.editedMessageObj ? ( ${this.editedMessageObj ? (
html` html`
<div style="margin-bottom: 10px"> <div style="margin-bottom: 10px">

View File

@ -9,32 +9,35 @@ import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } fro
const parentEpml = new Epml({ type: "WINDOW", source: window.parent }); const parentEpml = new Epml({ type: "WINDOW", source: window.parent });
export class TipUser extends LitElement { export class TipUser extends LitElement {
static get properties() { static get properties() {
return { return {
userName: { type: String }, userName: { type: String },
walletBalance: { type: Number }, walletBalance: { type: Number },
sendMoneyLoading: { type: Boolean }, sendMoneyLoading: { type: Boolean },
closeTipUser: { type: Boolean }, closeTipUser: { type: Boolean },
btnDisable: { type: Boolean }, btnDisable: { type: Boolean },
errorMessage: { type: String }, errorMessage: { type: String },
successMessage: { type: String }, successMessage: { type: String },
setOpenTipUser: { attribute: false }, setOpenTipUser: { attribute: false },
qortPaymentFee: { type: Number }
} }
} }
constructor() { constructor() {
super() super()
this.sendMoneyLoading = false this.sendMoneyLoading = false
this.btnDisable = false this.btnDisable = false
this.errorMessage = "" this.errorMessage = ""
this.successMessage = "" this.successMessage = ""
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress this.myAddress = window.parent.reduxStore.getState().app.selectedAddress
this.qortPaymentFee = 0.01
} }
static styles = [tipUserStyles] static styles = [tipUserStyles]
async firstUpdated() { async firstUpdated() {
await this.fetchWalletDetails() await this.fetchWalletDetails()
this.paymentFee()
} }
updated(changedProperties) { updated(changedProperties) {
@ -48,12 +51,34 @@ export class TipUser extends LitElement {
} }
async getLastRef() { async getLastRef() {
let myRef = await parentEpml.request("apiCall", { let myRef = await parentEpml.request("apiCall", {
type: "api", type: "api",
url: `/addresses/lastreference/${this.myAddress.address}`, url: `/addresses/lastreference/${this.myAddress.address}`,
}) })
return myRef 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() { renderSuccessText() {
return html`${translate("chatpage.cchange55")}` return html`${translate("chatpage.cchange55")}`
@ -89,7 +114,7 @@ export class TipUser extends LitElement {
this.sendMoneyLoading = true this.sendMoneyLoading = true
this.btnDisable = 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.sendMoneyLoading = false
this.btnDisable = false this.btnDisable = false
let snack1string = get("chatpage.cchange51") let snack1string = get("chatpage.cchange51")
@ -125,7 +150,7 @@ export class TipUser extends LitElement {
} else { } else {
myRes = myNameRes myRes = myNameRes
} }
return myRes; return myRes
} }
const validateAddress = async (receiverAddress) => { const validateAddress = async (receiverAddress) => {
@ -135,6 +160,7 @@ export class TipUser extends LitElement {
const validateReceiver = async (recipient) => { const validateReceiver = async (recipient) => {
let lastRef = await this.getLastRef() let lastRef = await this.getLastRef()
let theFee = await this.getSendQortFee()
let isAddress let isAddress
try { try {
@ -144,13 +170,13 @@ export class TipUser extends LitElement {
} }
if (isAddress) { if (isAddress) {
let myTransaction = await makeTransactionRequest(recipient, lastRef) let myTransaction = await makeTransactionRequest(recipient, lastRef, theFee)
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} else { } else {
let myNameRes = await validateName(recipient) let myNameRes = await validateName(recipient)
if (myNameRes !== false) { if (myNameRes !== false) {
let myNameAddress = myNameRes.owner let myNameAddress = myNameRes.owner
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef) let myTransaction = await makeTransactionRequest(myNameAddress, lastRef, theFee)
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} else { } else {
console.error(this.renderReceiverText()) 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 myReceiver = receiver
let mylastRef = lastRef let mylastRef = lastRef
let myFee = theFee
let dialogamount = get("transactions.amount") let dialogamount = get("transactions.amount")
let dialogAddress = get("login.address") let dialogAddress = get("login.address")
let dialogName = get("login.name") let dialogName = get("login.name")
@ -194,7 +221,7 @@ export class TipUser extends LitElement {
recipientName: recipientName, recipientName: recipientName,
amount: amount, amount: amount,
lastReference: mylastRef, lastReference: mylastRef,
fee: 0.001, fee: myFee,
dialogamount: dialogamount, dialogamount: dialogamount,
dialogto: dialogto, dialogto: dialogto,
dialogAddress, dialogAddress,
@ -239,7 +266,7 @@ export class TipUser extends LitElement {
<div class="tip-user-body"> <div class="tip-user-body">
<p class="tip-available">${translate("chatpage.cchange47")}: ${this.walletBalance} QORT</p> <p class="tip-available">${translate("chatpage.cchange47")}: ${this.walletBalance} QORT</p>
<input id="amountInput" class="tip-input" type="number" placeholder="${translate("chatpage.cchange46")}" /> <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 ? ${this.sendMoneyLoading ?
html` html`
<paper-progress indeterminate style="width: 100%; margin: 4px;"> <paper-progress indeterminate style="width: 100%; margin: 4px;">

View File

@ -30,7 +30,6 @@ import '@vaadin/grid'
passiveSupport({ events: ['touchstart'] }) passiveSupport({ events: ['touchstart'] })
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class Chat extends LitElement { class Chat extends LitElement {
static get properties() { static get properties() {
return { return {
@ -910,4 +909,4 @@ class Chat extends LitElement {
} }
} }
window.customElements.define('q-chat', Chat) window.customElements.define('q-chat', Chat)

View File

@ -465,6 +465,23 @@ class WebBrowser extends LitElement {
const joinFee = (Number(data) / 1e8).toFixed(8) const joinFee = (Number(data) / 1e8).toFixed(8)
return joinFee 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&timestamp=${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() { async sendQortFee() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] 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 nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
@ -1015,6 +1032,7 @@ class WebBrowser extends LitElement {
const tag3 = data.tag3; const tag3 = data.tag3;
const tag4 = data.tag4; const tag4 = data.tag4;
const tag5 = data.tag5; const tag5 = data.tag5;
let feeAmount = null
if (data.identifier == null) { if (data.identifier == null) {
identifier = 'default'; identifier = 'default';
} }
@ -1034,6 +1052,8 @@ class WebBrowser extends LitElement {
if (data.file) { if (data.file) {
data64 = await fileToBase64(data.file) data64 = await fileToBase64(data.file)
} }
const getArbitraryFee = await this.getArbitraryFee()
feeAmount = getArbitraryFee.fee
if (data.encrypt) { if (data.encrypt) {
try { try {
@ -1054,6 +1074,7 @@ class WebBrowser extends LitElement {
} }
const res2 = await showModalAndWait( const res2 = await showModalAndWait(
@ -1062,7 +1083,8 @@ class WebBrowser extends LitElement {
name, name,
identifier, identifier,
service, service,
encrypt: data.encrypt encrypt: data.encrypt,
feeAmount: getArbitraryFee.feeToShow
} }
); );
if (res2.action === 'accept') { if (res2.action === 'accept') {
@ -1092,7 +1114,8 @@ class WebBrowser extends LitElement {
tag4, tag4,
tag5, tag5,
apiVersion: 2, apiVersion: 2,
withFee: res2.userData.isWithFee === true ? true : false withFee: res2.userData.isWithFee === true ? true : false,
feeAmount: feeAmount
}); });
response = JSON.stringify(resPublish); response = JSON.stringify(resPublish);
@ -1120,7 +1143,7 @@ class WebBrowser extends LitElement {
case actions.PUBLISH_MULTIPLE_QDN_RESOURCES: { case actions.PUBLISH_MULTIPLE_QDN_RESOURCES: {
const requiredFields = ['resources']; const requiredFields = ['resources'];
const missingFields = []; const missingFields = [];
let feeAmount = null
requiredFields.forEach((field) => { requiredFields.forEach((field) => {
if (!data[field]) { if (!data[field]) {
missingFields.push(field); missingFields.push(field);
@ -1154,11 +1177,14 @@ class WebBrowser extends LitElement {
response = JSON.stringify(data); response = JSON.stringify(data);
break break
} }
const getArbitraryFee = await this.getArbitraryFee()
feeAmount = getArbitraryFee.fee
const res2 = await showModalAndWait( const res2 = await showModalAndWait(
actions.PUBLISH_MULTIPLE_QDN_RESOURCES, actions.PUBLISH_MULTIPLE_QDN_RESOURCES,
{ {
resources, resources,
encrypt: data.encrypt encrypt: data.encrypt,
feeAmount: getArbitraryFee.feeToShow
} }
); );
@ -1257,7 +1283,8 @@ class WebBrowser extends LitElement {
tag4, tag4,
tag5, tag5,
apiVersion: 2, apiVersion: 2,
withFee: res2.userData.isWithFee === true ? true : false withFee: res2.userData.isWithFee === true ? true : false,
feeAmount: feeAmount
}); });
worker.terminate(); worker.terminate();
@ -3163,10 +3190,7 @@ async function showModalAndWait(type, data) {
`).join('')} `).join('')}
</table> </table>
<div class="checkbox-row"> <div class="checkbox-row">
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);"> <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>
${get('browserpage.bchange33')} ${data.resources.length * 0.001} QORT fee
</label>
<mwc-checkbox checked style="margin-right: -15px;" id="isWithFee"></mwc-checkbox>
</div> </div>
</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.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> <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"> <div class="checkbox-row">
<label for="isWithFee" id="isWithFeeLabel" style="color: var(--black);"> <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>
${get('browserpage.bchange29')}
</label>
<mwc-checkbox checked style="margin-right: -15px;" id="isWithFee"></mwc-checkbox>
</div> </div>
</div> </div>
` : ''} ` : ''}
@ -3229,7 +3250,7 @@ async function showModalAndWait(type, data) {
` : ''} ` : ''}
${type === actions.NOTIFICATIONS_PERMISSION ? ` ${type === actions.NOTIFICATIONS_PERMISSION ? `
<div class="modal-subcontainer"> <div class="modal-subcontainer">
<p class="modal-paragraph">${get("browserpage.bchange47")}</p> <p class="modal-paragraph">${get("browserpage.bchange48")}</p>
</div> </div>
` : ''} ` : ''}
@ -3259,7 +3280,8 @@ async function showModalAndWait(type, data) {
const userData = {}; const userData = {};
if (type === actions.PUBLISH_QDN_RESOURCE || type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES) { if (type === actions.PUBLISH_QDN_RESOURCE || type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES) {
const isWithFeeCheckbox = modal.querySelector('#isWithFee'); const isWithFeeCheckbox = modal.querySelector('#isWithFee');
userData.isWithFee = isWithFeeCheckbox.checked; // userData.isWithFee = isWithFeeCheckbox.checked;
userData.isWithFee = true
} }
if (modal.parentNode === document.body) { if (modal.parentNode === document.body) {
document.body.removeChild(modal); document.body.removeChild(modal);

View File

@ -14,6 +14,7 @@ import '@material/mwc-select'
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@material/mwc-list/mwc-list-item.js' import '@material/mwc-list/mwc-list-item.js'
import '@polymer/paper-progress/paper-progress.js' import '@polymer/paper-progress/paper-progress.js'
import { modalHelper } from '../../../utils/publish-modal'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) 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> <p style="color: green; word-break: break-word;">${this.successMessage}</p>
${this.loading ? html` <paper-progress indeterminate style="width:100%; margin:4px;"></paper-progress> ` : ''} ${this.loading ? html` <paper-progress indeterminate style="width:100%; margin:4px;"></paper-progress> ` : ''}
<div class="buttons"> <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="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=${() => this.shadowRoot.querySelector('#publishWithFeeDialog').show()}> ${translate("publishpage.pchange11")}</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> </div>
</div> </div>
@ -310,7 +313,7 @@ class PublishData extends LitElement {
<mwc-button slot="primaryAction" @click="${(e) => this.feeDialogNo(e, false, false)}" class="red"> <mwc-button slot="primaryAction" @click="${(e) => this.feeDialogNo(e, false, false)}" class="red">
${translate("general.no")} ${translate("general.no")}
</mwc-button> </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")} ${translate("general.yes")}
</mwc-button> </mwc-button>
</mwc-dialog> </mwc-dialog>
@ -418,7 +421,7 @@ class PublishData extends LitElement {
this.shadowRoot.querySelector('#publishWithFeeDialog').close() this.shadowRoot.querySelector('#publishWithFeeDialog').close()
} }
doPublish(e, preview, fee) { async doPublish(e, preview, fee) {
let registeredName = this.shadowRoot.getElementById('registeredName').value let registeredName = this.shadowRoot.getElementById('registeredName').value
let service = this.shadowRoot.getElementById('service').value let service = this.shadowRoot.getElementById('service').value
let identifier = this.shadowRoot.getElementById('identifier').value let identifier = this.shadowRoot.getElementById('identifier').value
@ -464,7 +467,22 @@ class PublishData extends LitElement {
parentEpml.request('showSnackBar', `${err5string}`) parentEpml.request('showSnackBar', `${err5string}`)
} }
else { 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 = '' this.successMessage = ''
console.error(errorMessage) console.error(errorMessage)
} }
const getArbitraryFee = async () => {
const timestamp = Date.now()
let fee = await parentEpml.request('apiCall', {
url: `/transactions/unitfee?txType=ARBITRARY&timestamp=${timestamp}`
})
return {
timestamp,
fee : Number(fee),
feeToShow: (Number(fee) / 1e8).toFixed(8)
}
}
const validate = async () => { const validate = async () => {
let validNameRes = await validateName(registeredName) let validNameRes = await validateName(registeredName)
@ -501,8 +530,17 @@ class PublishData extends LitElement {
this.generalMessage = `${err6string}` this.generalMessage = `${err6string}`
let transactionBytes let transactionBytes
let previewUrlPath 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) { if (uploadDataRes.error) {
let err7string = get("publishpage.pchange20") let err7string = get("publishpage.pchange20")
@ -531,12 +569,13 @@ class PublishData extends LitElement {
if (fee) { if (fee) {
let err9string = get("publishpage.pchange26") let err9string = get("publishpage.pchange26")
this.generalMessage = `${err9string}` this.generalMessage = `${err9string}`
} else { } else {
let err9string = get("publishpage.pchange22") let err9string = get("publishpage.pchange22")
this.generalMessage = `${err9string}` this.generalMessage = `${err9string}`
} }
let signAndProcessRes = await signAndProcess(transactionBytes, fee) let signAndProcessRes = await signAndProcess(transactionBytes, fee, feeAmount)
if (signAndProcessRes.error) { if (signAndProcessRes.error) {
let err10string = get("publishpage.pchange20") let err10string = get("publishpage.pchange20")
@ -554,7 +593,9 @@ class PublishData extends LitElement {
this.successMessage = `${err11string}` this.successMessage = `${err11string}`
} }
const uploadData = async (registeredName, path, file, preview, fee) => {
const uploadData = async (registeredName, path, file, preview, fee, feeAmount) => {
let postBody = path let postBody = path
let urlSuffix = "" let urlSuffix = ""
if (file != null) { 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()}` uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}&preview=${new Boolean(preview).toString()}`
} }
} else if (fee) { } 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) { 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 { } else {
uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}` uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`

View File

@ -708,7 +708,7 @@ class TradePortal extends LitElement {
balance: "0", balance: "0",
coinCode: "QORT", coinCode: "QORT",
coinAmount: this.amountString, coinAmount: this.amountString,
tradeFee: "0.002" tradeFee: "0.02"
} }
let bitcoin = { let bitcoin = {
@ -2699,6 +2699,7 @@ class TradePortal extends LitElement {
async sellAction() { async sellAction() {
this.isSellLoading = true this.isSellLoading = true
this.sellBtnDisable = true this.sellBtnDisable = true
await this.tradeFee()
const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value const sellAmountInput = this.shadowRoot.getElementById('sellAmountInput').value
const sellTotalInput = this.shadowRoot.getElementById('sellTotalInput').value const sellTotalInput = this.shadowRoot.getElementById('sellTotalInput').value
const fundingQortAmount = this.round(parseFloat(sellAmountInput) + 0.001) const fundingQortAmount = this.round(parseFloat(sellAmountInput) + 0.001)
@ -2733,7 +2734,7 @@ class TradePortal extends LitElement {
fundingQortAmount: parseFloat(fundingQortAmount), fundingQortAmount: parseFloat(fundingQortAmount),
foreignBlockchain: this.selectedCoin, foreignBlockchain: this.selectedCoin,
foreignAmount: parseFloat(sellTotalInput), foreignAmount: parseFloat(sellTotalInput),
tradeTimeout: 60, tradeTimeout: 120,
receivingAddress: _receivingAddress, receivingAddress: _receivingAddress,
}) })
return response return response
@ -3032,10 +3033,11 @@ class TradePortal extends LitElement {
} }
return Promise.reject(response) return Promise.reject(response)
}).then((json) => { }).then((json) => {
this.listedCoins.get("QORTAL").tradeFee = (Number(json) + 100000) / 1e8 this.listedCoins.get("QORTAL").tradeFee = (Number(json) * 2) / 1e8
}) })
} }
getApiKey() { getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey; let apiKey = myNode.apiKey;

View File

@ -28,7 +28,8 @@ export const publishData = async ({
tag2, tag2,
tag3, tag3,
tag4, tag4,
tag5 tag5,
feeAmount
}) => { }) => {
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
let nameRes = await parentEpml.request("apiCall", { let nameRes = await parentEpml.request("apiCall", {
@ -48,6 +49,17 @@ export const publishData = async ({
}) })
return convertedBytes return convertedBytes
} }
const getArbitraryFee = async () => {
const timestamp = Date.now()
let fee = await parentEpml.request('apiCall', {
url: `/transactions/unitfee?txType=ARBITRARY&timestamp=${timestamp}`
})
return {
timestamp,
fee : Number(fee),
feeToShow: (Number(fee) / 1e8).toFixed(8)
}
}
const signAndProcess = async (transactionBytesBase58) => { const signAndProcess = async (transactionBytesBase58) => {
let convertedBytesBase58 = await convertBytesForSigning( let convertedBytesBase58 = await convertBytesForSigning(
@ -125,7 +137,18 @@ export const publishData = async ({
if (validNameRes.error) { if (validNameRes.error) {
throw new Error('Name not found'); 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) { if (transactionBytes.error) {
throw new Error(transactionBytes.message || 'Error when uploading'); throw new Error(transactionBytes.message || 'Error when uploading');
} else if ( } else if (
@ -149,7 +172,7 @@ export const publishData = async ({
return signAndProcessRes return signAndProcessRes
} }
const uploadData = async (registeredName, path, file) => { const uploadData = async (registeredName, path, file, fee) => {
if (identifier != null && identifier.trim().length > 0) { if (identifier != null && identifier.trim().length > 0) {
let postBody = path let postBody = path
let urlSuffix = "" let urlSuffix = ""
@ -181,7 +204,7 @@ export const publishData = async ({
} }
if(withFee){ if(withFee){
uploadDataUrl = uploadDataUrl + '&fee=100000' uploadDataUrl = uploadDataUrl + `&fee=${fee}`
} }
if(filename != null && filename != "undefined"){ if(filename != null && filename != "undefined"){

View 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;
}

View 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&timestamp=${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();