mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-05-09 11:17:51 +00:00
Merge branch 'feature/group-features' into feature/new-editor
This commit is contained in:
commit
13c8242e6c
2
.gitignore
vendored
2
.gitignore
vendored
@ -5,7 +5,7 @@ yarn.lock
|
|||||||
qortal-ui-plugins/plugins/core/**/*.js
|
qortal-ui-plugins/plugins/core/**/*.js
|
||||||
!*.src.js
|
!*.src.js
|
||||||
qortal-ui-core/src/redux/app/version.js
|
qortal-ui-core/src/redux/app/version.js
|
||||||
!qortal-ui-plugins/plugins/core/components/*.js
|
!qortal-ui-plugins/plugins/core/components/**/*.js
|
||||||
|
|
||||||
# Node modules
|
# Node modules
|
||||||
node_modules/
|
node_modules/
|
||||||
|
12
package.json
12
package.json
@ -19,12 +19,12 @@
|
|||||||
"install_link:all": "(cd qortal-ui-core && yarn install && yarn link) && (cd qortal-ui-plugins && yarn install && yarn link) && (cd qortal-ui-crypto && yarn install && yarn link) && (yarn link qortal-ui-core && yarn link qortal-ui-plugins && yarn link qortal-ui-crypto)",
|
"install_link:all": "(cd qortal-ui-core && yarn install && yarn link) && (cd qortal-ui-plugins && yarn install && yarn link) && (cd qortal-ui-crypto && yarn install && yarn link) && (yarn link qortal-ui-core && yarn link qortal-ui-plugins && yarn link qortal-ui-crypto)",
|
||||||
"dev": "node server.js",
|
"dev": "node server.js",
|
||||||
"prebuild": "node -p \"'export const UI_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > qortal-ui-core/src/redux/app/version.js",
|
"prebuild": "node -p \"'export const UI_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > qortal-ui-core/src/redux/app/version.js",
|
||||||
"build-dev": "node build.js",
|
"build-dev": "node --max-old-space-size=8192 build.js",
|
||||||
"build": "NODE_ENV=production node build.js",
|
"build": "NODE_ENV=production node --max-old-space-size=8192 build.js",
|
||||||
"server": "NODE_ENV=production node server.js",
|
"server": "NODE_ENV=production node --max-old-space-size=8192 server.js",
|
||||||
"watch": "node watch.js",
|
"watch": "node --max-old-space-size=8192 watch.js",
|
||||||
"watch-inline": "node watch-inline.js",
|
"watch-inline": "node --max-old-space-size=8192 watch-inline.js",
|
||||||
"start-electron": "NODE_ENV=production electron .",
|
"start-electron": "NODE_ENV=production electron --js-flags=--max-old-space-size=8192 .",
|
||||||
"build-electron": "electron-builder build --publish never",
|
"build-electron": "electron-builder build --publish never",
|
||||||
"deploy-electron": "electron-builder build --win --publish never",
|
"deploy-electron": "electron-builder build --win --publish never",
|
||||||
"release": "NODE_ENV=production electron-builder build --publish never",
|
"release": "NODE_ENV=production electron-builder build --publish never",
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI mit Knoten verbunden",
|
"snack2":"UI mit Knoten verbunden",
|
||||||
"snack3":"Benutzerdefinierter Knoten erfolgreich hinzugefügt und gespeichert",
|
"snack3":"Benutzerdefinierter Knoten erfolgreich hinzugefügt und gespeichert",
|
||||||
"snack4":"Knoten erfolgreich gespeichert als",
|
"snack4":"Knoten erfolgreich gespeichert als",
|
||||||
"snack5":"Knoten erfolgreich importiert"
|
"snack5":"Knoten erfolgreich importiert",
|
||||||
|
"exp1":"Privaten Hauptschlüssel exportieren",
|
||||||
|
"exp2":"Hauptschlüssel exportieren",
|
||||||
|
"exp3":"Exportieren",
|
||||||
|
"exp4":"Bitte wählen Sie eine Brieftasche aus, um den privaten Hauptschlüssel zu sichern."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Blockhöhe",
|
"blockheight":"Blockhöhe",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTO KAUFEN MIT",
|
"tchange45":"AUTO KAUFEN MIT",
|
||||||
"tchange46":"AUTOKAUF",
|
"tchange46":"AUTOKAUF",
|
||||||
"tchange47":"Verkaufe für diesen Preis",
|
"tchange47":"Verkaufe für diesen Preis",
|
||||||
"tchange48":"NICHT GENUG"
|
"tchange48":"NICHT GENUG",
|
||||||
|
"tchange49":"Preisdiagramm"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Belohnungsanteile",
|
"rchange1":"Belohnungsanteile",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"Beim Drücken auf Bestätigen wird die Anfrage zum Abbrechen der Einladung gesendet!",
|
"mg49":"Beim Drücken auf Bestätigen wird die Anfrage zum Abbrechen der Einladung gesendet!",
|
||||||
"mg50":"Kommt bald...",
|
"mg50":"Kommt bald...",
|
||||||
"mg51":"Minimum 3 Zeichen / Maximum 32 Zeichen",
|
"mg51":"Minimum 3 Zeichen / Maximum 32 Zeichen",
|
||||||
"mg52":"Maximal 128 Zeichen"
|
"mg52":"Maximal 128 Zeichen",
|
||||||
|
"mg53":"Ihre offenen Beitrittsanfragen",
|
||||||
|
"mg54":"Keine offenen Beitrittsanfragen",
|
||||||
|
"mg55":"Sind Sie sicher, dass Sie die Beitrittsanfrage von diesem Mitglied annehmen werden?",
|
||||||
|
"mg56":"Beim Drücken von Bestätigen wird die Beitrittsanfrage gesendet!",
|
||||||
|
"mg57":"Beitrittsanfrage erfolgreich angenommen",
|
||||||
|
"mg58":"ETWAS GING FALSCH",
|
||||||
|
"mg59":"Beitrittsanfrage abbrechen erfolgreich akzeptiert",
|
||||||
|
"mg60":"Sind Sie sicher, dass Sie die Beitrittsanfrage dieses Mitglieds abbrechen möchten?",
|
||||||
|
"mg61":"Beim Drücken auf Bestätigen wird die Anfrage zum Abbrechen des Beitritts gesendet!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI conectada al nodo",
|
"snack2":"UI conectada al nodo",
|
||||||
"snack3":"Nodo personalizado agregado y guardado con éxito",
|
"snack3":"Nodo personalizado agregado y guardado con éxito",
|
||||||
"snack4":"Nodos guardados con éxito como",
|
"snack4":"Nodos guardados con éxito como",
|
||||||
"snack5":"Nodos importados con éxito"
|
"snack5":"Nodos importados con éxito",
|
||||||
|
"exp1":"Exportar clave maestra privada",
|
||||||
|
"exp2":"Exportar clave maestra",
|
||||||
|
"exp3":"Exportar",
|
||||||
|
"exp4":"Elija una billetera para hacer una copia de seguridad de la clave maestra privada."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Altura del Bloque",
|
"blockheight":"Altura del Bloque",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTO COMPRAR CON",
|
"tchange45":"AUTO COMPRAR CON",
|
||||||
"tchange46":"COMPRA AUTOMÁTICA",
|
"tchange46":"COMPRA AUTOMÁTICA",
|
||||||
"tchange47":"Vender por este precio",
|
"tchange47":"Vender por este precio",
|
||||||
"tchange48":"NO ES SUFICIENTE"
|
"tchange48":"NO ES SUFICIENTE",
|
||||||
|
"tchange49":"Gráfico de precios"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Rewardshares",
|
"rchange1":"Rewardshares",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"¡Al presionar confirmar, se enviará la solicitud de cancelación de invitación!",
|
"mg49":"¡Al presionar confirmar, se enviará la solicitud de cancelación de invitación!",
|
||||||
"mg50":"Próximamente...",
|
"mg50":"Próximamente...",
|
||||||
"mg51":"Mínimo 3 Caracteres / Máximo 32 Caracteres",
|
"mg51":"Mínimo 3 Caracteres / Máximo 32 Caracteres",
|
||||||
"mg52":"Máximo de 128 caracteres"
|
"mg52":"Máximo de 128 caracteres",
|
||||||
|
"mg53":"Tus solicitudes abiertas de unión",
|
||||||
|
"mg54":"Sin solicitudes de unión abiertas",
|
||||||
|
"mg55":"¿Está seguro de aceptar la solicitud de ingreso de este miembro?",
|
||||||
|
"mg56":"¡Al presionar confirmar, se enviará la solicitud de aceptación de ingreso!",
|
||||||
|
"mg57":"Solicitud de ingreso aceptada con éxito",
|
||||||
|
"mg58":"ALGO SALIO MAL",
|
||||||
|
"mg59":"Solicitud de cancelación de unión aceptada con éxito",
|
||||||
|
"mg60":"¿Está seguro de cancelar la solicitud de ingreso de este miembro?",
|
||||||
|
"mg61":"¡Al presionar confirmar, se enviará la solicitud de cancelación de unión!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"Interface utilisateur connectée au noeud",
|
"snack2":"Interface utilisateur connectée au noeud",
|
||||||
"snack3":"Noeud personnalisé ajouté et enregistré avec succès",
|
"snack3":"Noeud personnalisé ajouté et enregistré avec succès",
|
||||||
"snack4":"Les noeuds ont été enregistrés avec succès sous",
|
"snack4":"Les noeuds ont été enregistrés avec succès sous",
|
||||||
"snack5":"Les noeuds ont été importés avec succès"
|
"snack5":"Les noeuds ont été importés avec succès",
|
||||||
|
"exp1":"Exporter la clé principale privée",
|
||||||
|
"exp2":"Exporter la clé principale",
|
||||||
|
"exp3":"Exporter",
|
||||||
|
"exp4":"Veuillez choisir un portefeuille pour sauvegarder la clé principale privée."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Hauteur de bloc",
|
"blockheight":"Hauteur de bloc",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"ACHAT AUTO AVEC",
|
"tchange45":"ACHAT AUTO AVEC",
|
||||||
"tchange46":"ACHAT AUTOMATIQUE",
|
"tchange46":"ACHAT AUTOMATIQUE",
|
||||||
"tchange47":"Vendre à ce prix",
|
"tchange47":"Vendre à ce prix",
|
||||||
"tchange48":"PAS ASSEZ"
|
"tchange48":"PAS ASSEZ",
|
||||||
|
"tchange49":"Tableau des prix"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Récompenses",
|
"rchange1":"Récompenses",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"En appuyant sur confirmer, la demande d'annulation d'invitation sera envoyée !",
|
"mg49":"En appuyant sur confirmer, la demande d'annulation d'invitation sera envoyée !",
|
||||||
"mg50":"Bientôt disponible...",
|
"mg50":"Bientôt disponible...",
|
||||||
"mg51":"Minimum 3 caractères / Maximum 32 caractères",
|
"mg51":"Minimum 3 caractères / Maximum 32 caractères",
|
||||||
"mg52":"Maximum 128 caractères"
|
"mg52":"Maximum 128 caractères",
|
||||||
|
"mg53":"Vos demandes d'ouverture de jointure",
|
||||||
|
"mg54":"Aucune demande de jointure ouverte",
|
||||||
|
"mg55":"Êtes-vous sûr d'accepter la demande d'adhésion de ce membre ?",
|
||||||
|
"mg56":"En appuyant sur confirmer, la demande d'adhésion acceptée sera envoyée !",
|
||||||
|
"mg57":"Demande d'adhésion acceptée avec succès",
|
||||||
|
"mg58":"QUELQUE CHOSE S'EST TROMPÉ",
|
||||||
|
"mg59":"Annuler la demande d'adhésion acceptée avec succès",
|
||||||
|
"mg60":"Êtes-vous sûr d'annuler la demande d'adhésion de ce membre ?",
|
||||||
|
"mg61":"En appuyant sur confirmer, la demande d'annulation de l'adhésion sera envoyée !"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +129,11 @@
|
|||||||
"snack2":"यूआई नोड से जुड़ा",
|
"snack2":"यूआई नोड से जुड़ा",
|
||||||
"snack3":"कस्टम नोड को सफलतापूर्वक जोड़ा और सहेजा गया",
|
"snack3":"कस्टम नोड को सफलतापूर्वक जोड़ा और सहेजा गया",
|
||||||
"snack4":"नोड्स सफलतापूर्वक सहेजे गए",
|
"snack4":"नोड्स सफलतापूर्वक सहेजे गए",
|
||||||
"snack5":"नोड्स सफलतापूर्वक आयात किए गए"
|
"snack5":"नोड्स सफलतापूर्वक आयात किए गए",
|
||||||
|
"exp1":"निजी मास्टर कुंजी निर्यात करें",
|
||||||
|
"exp2":"निर्यात मास्टर कुंजी",
|
||||||
|
"exp3":"निर्यात",
|
||||||
|
"exp4":"निजी मास्टर कुंजी का बैकअप लेने के लिए कृपया एक वॉलेट चुनें।"
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"ब्लॉक ऊँचाई",
|
"blockheight":"ब्लॉक ऊँचाई",
|
||||||
@ -330,7 +334,8 @@
|
|||||||
"tchange45":"ऑटो के साथ खरीदें",
|
"tchange45":"ऑटो के साथ खरीदें",
|
||||||
"tchange46":"ऑटो खरीदें",
|
"tchange46":"ऑटो खरीदें",
|
||||||
"tchange47":"इस कीमत पर बेचें",
|
"tchange47":"इस कीमत पर बेचें",
|
||||||
"tchange48":"पर्याप्त नहीं"
|
"tchange48":"पर्याप्त नहीं",
|
||||||
|
"tchange49":"मूल्य चार्ट"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"रिवॉर्डशेयर",
|
"rchange1":"रिवॉर्डशेयर",
|
||||||
@ -799,7 +804,16 @@
|
|||||||
"mg48":"क्या आप वाकई इस सदस्य के लिए आमंत्रण रद्द करना चाहते हैं?",
|
"mg48":"क्या आप वाकई इस सदस्य के लिए आमंत्रण रद्द करना चाहते हैं?",
|
||||||
"mg49":"पुष्टि करें दबाने पर, रद्द आमंत्रण अनुरोध भेजा जाएगा!",
|
"mg49":"पुष्टि करें दबाने पर, रद्द आमंत्रण अनुरोध भेजा जाएगा!",
|
||||||
"mg50":"जल्द ही आ रहा है ...",
|
"mg50":"जल्द ही आ रहा है ...",
|
||||||
"mg51": "न्यूनतम 3 वर्ण / अधिकतम 32 वर्ण",
|
"mg51":"न्यूनतम 3 वर्ण / अधिकतम 32 वर्ण",
|
||||||
"mg52": "अधिकतम 128 वर्ण"
|
"mg52":"अधिकतम 128 वर्ण",
|
||||||
|
"mg53":"आपका खुला शामिल होने का अनुरोध",
|
||||||
|
"mg54":"नो ओपन जॉइन रिक्वेस्ट",
|
||||||
|
"mg55":"क्या आप निश्चित रूप से इस सदस्य के शामिल होने के अनुरोध को स्वीकार करना चाहते हैं?",
|
||||||
|
"mg56":"पुष्टि करें दबाने पर, स्वीकार करने का अनुरोध भेजा जाएगा!",
|
||||||
|
"mg57":"जुड़ने का अनुरोध सफलतापूर्वक स्वीकार किया गया",
|
||||||
|
"mg58":"कुछ गलत हो गया",
|
||||||
|
"mg59":"रद्द करें शामिल होने का अनुरोध सफलतापूर्वक स्वीकार किया गया",
|
||||||
|
"mg60":"क्या आप निश्चित रूप से इस सदस्य के शामिल होने के अनुरोध को रद्द करना चाहते हैं?",
|
||||||
|
"mg61":"पुष्टि करें दबाने पर, रद्द करने का अनुरोध भेजा जाएगा!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI spojen na čvor",
|
"snack2":"UI spojen na čvor",
|
||||||
"snack3":"Uspješno dodan i spremljen prilagođeni čvor",
|
"snack3":"Uspješno dodan i spremljen prilagođeni čvor",
|
||||||
"snack4":"Čvorovi su uspješno spremljeni kao",
|
"snack4":"Čvorovi su uspješno spremljeni kao",
|
||||||
"snack5":"Čvorovi su uspješno uvezeni"
|
"snack5":"Čvorovi su uspješno uvezeni",
|
||||||
|
"exp1":"Izvezi privatni glavni ključ",
|
||||||
|
"exp2":"Glavni ključ izvoza",
|
||||||
|
"exp3":"Izvoz",
|
||||||
|
"exp4":"Odaberite novčanik za sigurnosnu kopiju privatnog glavnog ključa."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Visina bloka",
|
"blockheight":"Visina bloka",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTO KUPITE SA",
|
"tchange45":"AUTO KUPITE SA",
|
||||||
"tchange46":"AUTO OTKUP",
|
"tchange46":"AUTO OTKUP",
|
||||||
"tchange47":"Prodaj za ovu cijenu",
|
"tchange47":"Prodaj za ovu cijenu",
|
||||||
"tchange48":"NEDOVOLJNO"
|
"tchange48":"NEDOVOLJNO",
|
||||||
|
"tchange49":"Grafikon cijena"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Nagradni udio (Rewardshares)",
|
"rchange1":"Nagradni udio (Rewardshares)",
|
||||||
@ -798,7 +803,16 @@
|
|||||||
"mg48":"Jeste li sigurni da želite otkazati poziv za ovog člana?",
|
"mg48":"Jeste li sigurni da želite otkazati poziv za ovog člana?",
|
||||||
"mg49":"Pritiskom na potvrdu, zahtjev za pozivnicu za otkazivanje bit će poslan!",
|
"mg49":"Pritiskom na potvrdu, zahtjev za pozivnicu za otkazivanje bit će poslan!",
|
||||||
"mg50":"Uskoro...",
|
"mg50":"Uskoro...",
|
||||||
"mg51": "Minimalno 3 znaka / Maksimalno 32 znaka",
|
"mg51":"Minimalno 3 znaka / Maksimalno 32 znaka",
|
||||||
"mg52": "Maksimalno 128 znakova"
|
"mg52":"Maksimalno 128 znakova",
|
||||||
|
"mg53":"Vaši otvoreni zahtjevi za pridruživanje",
|
||||||
|
"mg54":"Nema otvorenih zahtjeva za pridruživanje",
|
||||||
|
"mg55":"Jeste li sigurni da prihvaćate zahtjev za pridruživanje ovog člana?",
|
||||||
|
"mg56":"Pritiskom na potvrdu, zahtjev za prihvaćanje pridruživanja bit će poslan!",
|
||||||
|
"mg57":"Zahtjev za pridruživanje uspješno prihvaćen",
|
||||||
|
"mg58":"NEŠTO JE POŠLO PO ZLOU",
|
||||||
|
"mg59":"Poništi zahtjev za pridruživanje uspješno prihvaćen",
|
||||||
|
"mg60":"Jeste li sigurni da želite otkazati zahtjev za pridruživanje ovog člana?",
|
||||||
|
"mg61":"Pritiskom na potvrdu, bit će poslan zahtjev za otkazivanje pridruživanja!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI csatlakozik a csomóponthoz",
|
"snack2":"UI csatlakozik a csomóponthoz",
|
||||||
"snack3":"Az egyéni csomópont sikeresen hozzáadva és mentve",
|
"snack3":"Az egyéni csomópont sikeresen hozzáadva és mentve",
|
||||||
"snack4":"A csomópontok sikeresen mentve másként",
|
"snack4":"A csomópontok sikeresen mentve másként",
|
||||||
"snack5":"A csomópontok sikeresen importálva"
|
"snack5":"A csomópontok sikeresen importálva",
|
||||||
|
"exp1":"Privát főkulcs exportálása",
|
||||||
|
"exp2":"Főkulcs exportálása",
|
||||||
|
"exp3":"Exportálás",
|
||||||
|
"exp4":"Kérjük, válasszon egy tárcát a privát főkulcs biztonsági mentéséhez."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Blokk Magassága",
|
"blockheight":"Blokk Magassága",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTOMATIKUS VÁSÁRLÁS",
|
"tchange45":"AUTOMATIKUS VÁSÁRLÁS",
|
||||||
"tchange46":"AUTOMATIKUS VÁSÁRLÁS",
|
"tchange46":"AUTOMATIKUS VÁSÁRLÁS",
|
||||||
"tchange47":"Eladni ezen az áron",
|
"tchange47":"Eladni ezen az áron",
|
||||||
"tchange48":"NEM ELÉG"
|
"tchange48":"NEM ELÉG",
|
||||||
|
"tchange49":"Árdiagram"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Jutalommegosztások",
|
"rchange1":"Jutalommegosztások",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"A megerősítés megnyomására a rendszer elküldi a meghívó visszavonási kérelmét!",
|
"mg49":"A megerősítés megnyomására a rendszer elküldi a meghívó visszavonási kérelmét!",
|
||||||
"mg50":"Hamarosan...",
|
"mg50":"Hamarosan...",
|
||||||
"mg51":"Minimum 3 karakter / legfeljebb 32 karakter",
|
"mg51":"Minimum 3 karakter / legfeljebb 32 karakter",
|
||||||
"mg52":"Legfeljebb 128 karakter"
|
"mg52":"Legfeljebb 128 karakter",
|
||||||
|
"mg53":"Az Ön nyitott csatlakozási kérelmei",
|
||||||
|
"mg54":"Nincsenek nyitott csatlakozási kérelmek",
|
||||||
|
"mg55":"Biztosan elfogadja ennek a tagnak a csatlakozási kérelmét?",
|
||||||
|
"mg56":"A megerősítés megnyomására a rendszer elküldi az elfogadási csatlakozási kérelmet!",
|
||||||
|
"mg57":"Csatlakozási kérelem sikeresen elfogadva",
|
||||||
|
"mg58":"VALAMI RÁMADT",
|
||||||
|
"mg59":"Csatlakozási kérelem visszavonása sikeresen elfogadva",
|
||||||
|
"mg60":"Biztosan visszavonja ennek a tagnak a csatlakozási kérelmét?",
|
||||||
|
"mg61":"A megerősítés megnyomására a csatlakozás megszakítási kérelme elküldésre kerül!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"Interfaccia utente collegata al nodo",
|
"snack2":"Interfaccia utente collegata al nodo",
|
||||||
"snack3":"Nodo personalizzato aggiunto e salvato con successo",
|
"snack3":"Nodo personalizzato aggiunto e salvato con successo",
|
||||||
"snack4":"Nodi salvati con successo come",
|
"snack4":"Nodi salvati con successo come",
|
||||||
"snack5":"Nodi importati correttamente"
|
"snack5":"Nodi importati correttamente",
|
||||||
|
"exp1":"Esporta chiave master privata",
|
||||||
|
"exp2":"Esporta chiave master",
|
||||||
|
"exp3":"Esporta",
|
||||||
|
"exp4":"Scegli un portafoglio per il backup della chiave master privata."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Altezza blocco",
|
"blockheight":"Altezza blocco",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"ACQUISTA AUTO CON",
|
"tchange45":"ACQUISTA AUTO CON",
|
||||||
"tchange46":"ACQUISTO AUTO",
|
"tchange46":"ACQUISTO AUTO",
|
||||||
"tchange47":"Vendi a questo prezzo",
|
"tchange47":"Vendi a questo prezzo",
|
||||||
"tchange48":"NON ABBASTANZA"
|
"tchange48":"NON ABBASTANZA",
|
||||||
|
"tchange49":"Tabella dei prezzi"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Quote di ricompensa",
|
"rchange1":"Quote di ricompensa",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"Premendo conferma, verrà inviata la richiesta di annullamento dell'invito!",
|
"mg49":"Premendo conferma, verrà inviata la richiesta di annullamento dell'invito!",
|
||||||
"mg50":"Prossimamente...",
|
"mg50":"Prossimamente...",
|
||||||
"mg51":"Minimo 3 caratteri / Massimo 32 caratteri",
|
"mg51":"Minimo 3 caratteri / Massimo 32 caratteri",
|
||||||
"mg52":"Massimo 128 caratteri"
|
"mg52":"Massimo 128 caratteri",
|
||||||
|
"mg53":"Le tue richieste di partecipazione aperte",
|
||||||
|
"mg54":"Nessuna richiesta di partecipazione aperta",
|
||||||
|
"mg55":"Sei sicuro di accettare la richiesta di adesione di questo membro ?",
|
||||||
|
"mg56":"Premendo conferma, verrà inviata la richiesta di partecipazione accettata!",
|
||||||
|
"mg57":"Richiesta di partecipazione accettata con successo",
|
||||||
|
"mg58":"QUALCOSA È ANDATO storto",
|
||||||
|
"mg59":"Annulla richiesta di partecipazione accettata con successo",
|
||||||
|
"mg60":"Sei sicuro di voler annullare la richiesta di adesione di questo membro ?",
|
||||||
|
"mg61":"Premendo conferma, verrà inviata la richiesta di annullamento partecipazione!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"노드에 연결된 UI",
|
"snack2":"노드에 연결된 UI",
|
||||||
"snack3":"사용자 정의 노드를 성공적으로 추가하고 저장했습니다.",
|
"snack3":"사용자 정의 노드를 성공적으로 추가하고 저장했습니다.",
|
||||||
"snack4":"노드가 다음으로 성공적으로 저장되었습니다",
|
"snack4":"노드가 다음으로 성공적으로 저장되었습니다",
|
||||||
"snack5":"노드를 성공적으로 가져왔습니다."
|
"snack5":"노드를 성공적으로 가져왔습니다.",
|
||||||
|
"exp1":"개인 마스터 키 내보내기",
|
||||||
|
"exp2":"마스터 키 내보내기",
|
||||||
|
"exp3":"내보내기",
|
||||||
|
"exp4":"개인 마스터 키를 백업할 지갑을 선택하세요."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"블록 높이",
|
"blockheight":"블록 높이",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"자동 구매",
|
"tchange45":"자동 구매",
|
||||||
"tchange46":"자동 구매",
|
"tchange46":"자동 구매",
|
||||||
"tchange47":"이 가격에 팔아요",
|
"tchange47":"이 가격에 팔아요",
|
||||||
"tchange48":"부족한"
|
"tchange48":"부족한",
|
||||||
|
"tchange49":"가격 차트"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"보상 공유",
|
"rchange1":"보상 공유",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"확인을 누르면 초대 취소 요청이 전송됩니다!",
|
"mg49":"확인을 누르면 초대 취소 요청이 전송됩니다!",
|
||||||
"mg50":"출시 예정...",
|
"mg50":"출시 예정...",
|
||||||
"mg51":"최소 3자 / 최대 32자",
|
"mg51":"최소 3자 / 최대 32자",
|
||||||
"mg52":"최대 128자"
|
"mg52":"최대 128자",
|
||||||
|
"mg53":"귀하의 오픈 조인 요청",
|
||||||
|
"mg54":"오픈 조인 요청 없음",
|
||||||
|
"mg55":"이 회원의 가입 요청을 수락하시겠습니까?",
|
||||||
|
"mg56":"확인을 누르면 가입 수락 요청이 전송됩니다!",
|
||||||
|
"mg57":"가입 요청이 성공적으로 수락됨",
|
||||||
|
"mg58":"뭔가 잘못되었습니다",
|
||||||
|
"mg59":"가입 요청 취소 성공",
|
||||||
|
"mg60":"이 회원의 가입 요청을 취소하시겠습니까?",
|
||||||
|
"mg61":"확인을 누르면 가입 취소 요청이 전송됩니다!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI koblet til node",
|
"snack2":"UI koblet til node",
|
||||||
"snack3":"Egendefinert node er lagt til og lagret",
|
"snack3":"Egendefinert node er lagt til og lagret",
|
||||||
"snack4":"Noder ble lagret som",
|
"snack4":"Noder ble lagret som",
|
||||||
"snack5":"Noder ble importert"
|
"snack5":"Noder ble importert",
|
||||||
|
"exp1":"Eksporter privat hovednøkkel",
|
||||||
|
"exp2":"Eksporter hovednøkkel",
|
||||||
|
"exp3":"Eksporter",
|
||||||
|
"exp4":"Velg en lommebok for å sikkerhetskopiere den private hovednøkkelen."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Blokkhøyde",
|
"blockheight":"Blokkhøyde",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTOKJØP MED",
|
"tchange45":"AUTOKJØP MED",
|
||||||
"tchange46":"AUTOKJØP",
|
"tchange46":"AUTOKJØP",
|
||||||
"tchange47":"Selges for denne prisen",
|
"tchange47":"Selges for denne prisen",
|
||||||
"tchange48":"IKKE NOK"
|
"tchange48":"IKKE NOK",
|
||||||
|
"tchange49":"Prisdiagram"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Belønningsdel",
|
"rchange1":"Belønningsdel",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"Når du trykker på bekreftelse, vil forespørselen om kansellering av invitasjon bli sendt!",
|
"mg49":"Når du trykker på bekreftelse, vil forespørselen om kansellering av invitasjon bli sendt!",
|
||||||
"mg50":"Kommer snart...",
|
"mg50":"Kommer snart...",
|
||||||
"mg51":"Minimum 3 tegn / maksimum 32 tegn",
|
"mg51":"Minimum 3 tegn / maksimum 32 tegn",
|
||||||
"mg52": "Maksimalt 128 tegn"
|
"mg52":"Maksimalt 128 tegn",
|
||||||
|
"mg53":"Dine åpne forespørsler om bli med",
|
||||||
|
"mg54":"Ingen åpne forespørsler om medlemskap",
|
||||||
|
"mg55":"Er du sikker på å godta forespørselen fra dette medlemmet?",
|
||||||
|
"mg56":"Når du trykker på bekreft, vil forespørselen om å godta bli sendt bli sendt!",
|
||||||
|
"mg57":"Bli med forespørsel ble godtatt",
|
||||||
|
"mg58":"NOE GIKK FEIL",
|
||||||
|
"mg59":"Avbryt deltakelsesforespørsel ble godtatt",
|
||||||
|
"mg60":"Er du sikker på å avbryte forespørselen om å bli medlem fra dette medlemmet?",
|
||||||
|
"mg61":"Når du trykker på bekreft, vil forespørselen om kansellering bli sendt!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"Interfejs użytkownika połączony z węzłem",
|
"snack2":"Interfejs użytkownika połączony z węzłem",
|
||||||
"snack3":"Pomyślnie dodano i zapisano niestandardowy węzeł",
|
"snack3":"Pomyślnie dodano i zapisano niestandardowy węzeł",
|
||||||
"snack4":"Węzły pomyślnie zapisane jako",
|
"snack4":"Węzły pomyślnie zapisane jako",
|
||||||
"snack5":"Węzły pomyślnie zaimportowane"
|
"snack5":"Węzły pomyślnie zaimportowane",
|
||||||
|
"exp1":"Eksportuj prywatny klucz główny",
|
||||||
|
"exp2":"Eksportuj klucz główny",
|
||||||
|
"exp3":"Eksportuj",
|
||||||
|
"exp4":"Wybierz portfel do wykonania kopii zapasowej prywatnego klucza głównego."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Wysokość bloku",
|
"blockheight":"Wysokość bloku",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTO KUP Z",
|
"tchange45":"AUTO KUP Z",
|
||||||
"tchange46":"AUTO KUP",
|
"tchange46":"AUTO KUP",
|
||||||
"tchange47":"Sprzedaj za tę cenę",
|
"tchange47":"Sprzedaj za tę cenę",
|
||||||
"tchange48":"NIEWYSTARCZAJĄCO"
|
"tchange48":"NIEWYSTARCZAJĄCO",
|
||||||
|
"tchange49":"Tabela cen"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Podział nagród",
|
"rchange1":"Podział nagród",
|
||||||
@ -798,7 +803,16 @@
|
|||||||
"mg48":"Czy na pewno chcesz anulować zaproszenie dla tego członka?",
|
"mg48":"Czy na pewno chcesz anulować zaproszenie dla tego członka?",
|
||||||
"mg49":"Po naciśnięciu potwierdzenia zostanie wysłana prośba o anulowanie zaproszenia!",
|
"mg49":"Po naciśnięciu potwierdzenia zostanie wysłana prośba o anulowanie zaproszenia!",
|
||||||
"mg50":"Już wkrótce...",
|
"mg50":"Już wkrótce...",
|
||||||
"mg51": "Minimum 3 znaki / Maksymalnie 32 znaki",
|
"mg51":"Minimum 3 znaki / Maksymalnie 32 znaki",
|
||||||
"mg52": "Maksymalnie 128 znaków"
|
"mg52":"Maksymalnie 128 znaków",
|
||||||
|
"mg53":"Twoje otwarte prośby o dołączenie",
|
||||||
|
"mg54":"Brak otwartych próśb o dołączenie",
|
||||||
|
"mg55":"Czy na pewno akceptujesz prośbę o dołączenie od tego członka?",
|
||||||
|
"mg56":"Po naciśnięciu potwierdzenia zostanie wysłana prośba o zaakceptowanie dołączenia!",
|
||||||
|
"mg57":"Prośba o dołączenie pomyślnie zaakceptowana",
|
||||||
|
"mg58":"COŚ POszło nie tak",
|
||||||
|
"mg59":"Anuluj prośbę o dołączenie pomyślnie zaakceptowaną",
|
||||||
|
"mg60":"Czy na pewno chcesz anulować prośbę o dołączenie od tego członka?",
|
||||||
|
"mg61":"Po naciśnięciu potwierdzenia, zostanie wysłana prośba o anulowanie dołączenia!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI conectada ao nó",
|
"snack2":"UI conectada ao nó",
|
||||||
"snack3":"Nó personalizado adicionado e salvo com sucesso",
|
"snack3":"Nó personalizado adicionado e salvo com sucesso",
|
||||||
"snack4":"Nós salvos com sucesso como",
|
"snack4":"Nós salvos com sucesso como",
|
||||||
"snack5":"Nós importados com sucesso"
|
"snack5":"Nós importados com sucesso",
|
||||||
|
"exp1":"Exportar Chave Mestra Privada",
|
||||||
|
"exp2":"Exportar Chave Mestra",
|
||||||
|
"exp3":"Exportar",
|
||||||
|
"exp4":"Por favor, escolha uma carteira para fazer backup da chave mestra privada."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Altura do Bloco",
|
"blockheight":"Altura do Bloco",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"COMPRA AUTOMÁTICA COM",
|
"tchange45":"COMPRA AUTOMÁTICA COM",
|
||||||
"tchange46":"COMPRA AUTOMÁTICA",
|
"tchange46":"COMPRA AUTOMÁTICA",
|
||||||
"tchange47":"Vendo por este preço",
|
"tchange47":"Vendo por este preço",
|
||||||
"tchange48":"INSUFICIENTE"
|
"tchange48":"INSUFICIENTE",
|
||||||
|
"tchange49":"Tabela de preços"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Ações de recompensa",
|
"rchange1":"Ações de recompensa",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"Ao pressionar confirmar, a solicitação de cancelamento do convite será enviada!",
|
"mg49":"Ao pressionar confirmar, a solicitação de cancelamento do convite será enviada!",
|
||||||
"mg50":"Em Breve...",
|
"mg50":"Em Breve...",
|
||||||
"mg51":"Mínimo de 3 caracteres / Máximo de 32 caracteres",
|
"mg51":"Mínimo de 3 caracteres / Máximo de 32 caracteres",
|
||||||
"mg52":"Máximo de 128 caracteres"
|
"mg52":"Máximo de 128 caracteres",
|
||||||
|
"mg53":"Suas solicitações de entrada abertas",
|
||||||
|
"mg54":"Nenhuma solicitação de entrada aberta",
|
||||||
|
"mg55":"Tem certeza que aceita a solicitação de entrada deste membro?",
|
||||||
|
"mg56":"Ao pressionar confirmar, o pedido de aceitação de entrada será enviado!",
|
||||||
|
"mg57":"Solicitação de entrada aceita com sucesso",
|
||||||
|
"mg58":"ALGO DEU ERRADO",
|
||||||
|
"mg59":"Cancelar pedido de entrada aceito com sucesso",
|
||||||
|
"mg60":"Tem certeza que deseja cancelar a solicitação de ingresso deste membro ?",
|
||||||
|
"mg61":"Ao pressionar confirmar, o pedido de cancelamento de adesão será enviado!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"Interfata de utilizare conectata la nod",
|
"snack2":"Interfata de utilizare conectata la nod",
|
||||||
"snack3":"Nod personalizat adaugat si salvat cu succes",
|
"snack3":"Nod personalizat adaugat si salvat cu succes",
|
||||||
"snack4":"Nodurile au fost salvate cu succes ca",
|
"snack4":"Nodurile au fost salvate cu succes ca",
|
||||||
"snack5":"Nodurile au fost importate cu succes"
|
"snack5":"Nodurile au fost importate cu succes",
|
||||||
|
"exp1":"Exportați cheia principală privată",
|
||||||
|
"exp2":"Exportați cheia principală",
|
||||||
|
"exp3":"Export",
|
||||||
|
"exp4":"Vă rugăm să alegeți un portofel pentru a face backup cheii master private."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Dimensiunea blocului",
|
"blockheight":"Dimensiunea blocului",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"CUMPARA AUTOMATA CU",
|
"tchange45":"CUMPARA AUTOMATA CU",
|
||||||
"tchange46":"CUMPARARE AUTOMATA",
|
"tchange46":"CUMPARARE AUTOMATA",
|
||||||
"tchange47":"Vinde la acest pret",
|
"tchange47":"Vinde la acest pret",
|
||||||
"tchange48":"INSUFICIENT"
|
"tchange48":"INSUFICIENT",
|
||||||
|
"tchange49":"Diagrama prețurilor"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Cote de recompensa",
|
"rchange1":"Cote de recompensa",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"La apăsarea confirmării, cererea de anulare a invitației va fi trimisă!",
|
"mg49":"La apăsarea confirmării, cererea de anulare a invitației va fi trimisă!",
|
||||||
"mg50":"În curând...",
|
"mg50":"În curând...",
|
||||||
"mg51":"Minim 3 caractere / Maxim 32 de caractere",
|
"mg51":"Minim 3 caractere / Maxim 32 de caractere",
|
||||||
"mg52":"Maximum 128 de caractere"
|
"mg52":"Maximum 128 de caractere",
|
||||||
|
"mg53":"Solicitările dvs. de înscriere deschise",
|
||||||
|
"mg54":"Fără solicitări de aderare deschise",
|
||||||
|
"mg55":"Sunteți sigur că acceptați solicitarea de alăturare de la acest membru?",
|
||||||
|
"mg56":"La apăsarea confirmării, va fi trimisă cererea de acceptare a înscrierii!",
|
||||||
|
"mg57":"Solicitarea de înscriere a fost acceptată cu succes",
|
||||||
|
"mg58":"CEVA A MERAT GREUT",
|
||||||
|
"mg59":"Anularea cererii de aderare a fost acceptată cu succes",
|
||||||
|
"mg60":"Sigur anulați solicitarea de alăturare de la acest membru?",
|
||||||
|
"mg61":"La apăsarea confirmării, cererea de anulare a aderării va fi trimisă!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"UI je povezan sa čvorom",
|
"snack2":"UI je povezan sa čvorom",
|
||||||
"snack3":"Uspešno dodat i sačuvan prilagođeni čvor",
|
"snack3":"Uspešno dodat i sačuvan prilagođeni čvor",
|
||||||
"snack4":"Čvorovi su uspešno sačuvani kao",
|
"snack4":"Čvorovi su uspešno sačuvani kao",
|
||||||
"snack5":"Čvorovi su uspešno uvezeni"
|
"snack5":"Čvorovi su uspešno uvezeni",
|
||||||
|
"exp1":"Izvezi privatni glavni ključ",
|
||||||
|
"exp2":"Izvezi glavni ključ",
|
||||||
|
"exp3":"Izvoz",
|
||||||
|
"exp4":"Molimo izaberite novčanik za rezervnu kopiju privatnog glavnog ključa."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Visina Bloka",
|
"blockheight":"Visina Bloka",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTO KUPI SA",
|
"tchange45":"AUTO KUPI SA",
|
||||||
"tchange46":"AUTO BUI",
|
"tchange46":"AUTO BUI",
|
||||||
"tchange47":"Prodaj za ovu cenu",
|
"tchange47":"Prodaj za ovu cenu",
|
||||||
"tchange48":"NEDOVOLJNO"
|
"tchange48":"NEDOVOLJNO",
|
||||||
|
"tchange49":"Grafik cena"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Udeo nagrade",
|
"rchange1":"Udeo nagrade",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"Pritiskom na potvrdi, zahtev za otkazivanje pozivnice će biti poslat!",
|
"mg49":"Pritiskom na potvrdi, zahtev za otkazivanje pozivnice će biti poslat!",
|
||||||
"mg50":"Uskoro...",
|
"mg50":"Uskoro...",
|
||||||
"mg51":"Najmanje 3 znaka / maksimalno 32 znaka",
|
"mg51":"Najmanje 3 znaka / maksimalno 32 znaka",
|
||||||
"mg52":"Maksimalno 128 znakova"
|
"mg52":"Maksimalno 128 znakova",
|
||||||
|
"mg53":"Vaši zahtevi za otvoreno pridruživanje",
|
||||||
|
"mg54":"Nema otvorenih zahteva za pridruživanje",
|
||||||
|
"mg55":"Da li ste sigurni da prihvatate zahtev za pridruživanje ovog člana?",
|
||||||
|
"mg56":"Pritiskom na potvrdi, biće poslat zahtev za prihvatanje pridruživanja!",
|
||||||
|
"mg57":"Zahtev za pridruživanje je uspešno prihvaćen",
|
||||||
|
"mg58":"NEŠTO JE POŠLO NA ZLO",
|
||||||
|
"mg59":"Zahtev za otkazivanje pridruživanja je uspešno prihvaćen",
|
||||||
|
"mg60":"Da li ste sigurni da otkažete zahtev za pridruživanje ovog člana?",
|
||||||
|
"mg61":"Pritiskom na potvrdu, zahtev za otkazivanje pridruživanja će biti poslat!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"Пользовательский интерфейс, подключенный к узлу",
|
"snack2":"Пользовательский интерфейс, подключенный к узлу",
|
||||||
"snack3":"Пользовательский узел успешно добавлен и сохранен",
|
"snack3":"Пользовательский узел успешно добавлен и сохранен",
|
||||||
"snack4":"Узлы успешно сохранены как",
|
"snack4":"Узлы успешно сохранены как",
|
||||||
"snack5":"Узлы успешно импортированы"
|
"snack5":"Узлы успешно импортированы",
|
||||||
|
"exp1":"Экспорт закрытого мастер-ключа",
|
||||||
|
"exp2":"Экспорт мастер-ключа",
|
||||||
|
"exp3":"Экспорт",
|
||||||
|
"exp4":"Пожалуйста, выберите кошелек для резервного копирования приватного главного ключа."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"Высота блока",
|
"blockheight":"Высота блока",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"АВТО КУПИТЬ С",
|
"tchange45":"АВТО КУПИТЬ С",
|
||||||
"tchange46":"АВТО КУПИТЬ",
|
"tchange46":"АВТО КУПИТЬ",
|
||||||
"tchange47":"Продать по этой цене",
|
"tchange47":"Продать по этой цене",
|
||||||
"tchange48":"НЕДОСТАТОЧНО"
|
"tchange48":"НЕДОСТАТОЧНО",
|
||||||
|
"tchange49":"График цен"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"Вознаграждения",
|
"rchange1":"Вознаграждения",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"При нажатии подтверждения будет отправлен запрос на отмену приглашения!",
|
"mg49":"При нажатии подтверждения будет отправлен запрос на отмену приглашения!",
|
||||||
"mg50":"Скоро...",
|
"mg50":"Скоро...",
|
||||||
"mg51":"Минимум 3 символа / максимум 32 символа",
|
"mg51":"Минимум 3 символа / максимум 32 символа",
|
||||||
"mg52":"Максимум 128 символов"
|
"mg52":"Максимум 128 символов",
|
||||||
|
"mg53":"Ваши открытые запросы на вступление",
|
||||||
|
"mg54":"Открытых запросов на присоединение нет",
|
||||||
|
"mg55":"Вы уверены, что принимаете запрос на вступление от этого участника?",
|
||||||
|
"mg56":"При нажатии подтверждения будет отправлен запрос на присоединение!",
|
||||||
|
"mg57":"Запрос на присоединение успешно принят",
|
||||||
|
"mg58":"ЧТО-ТО ПОШЛО НЕ ТАК",
|
||||||
|
"mg59":"Запрос на отмену присоединения успешно принят",
|
||||||
|
"mg60":"Вы уверены, что отмените запрос на вступление от этого участника?",
|
||||||
|
"mg61":"При нажатии кнопки подтверждения будет отправлен запрос на отмену присоединения!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,22 +21,22 @@
|
|||||||
"korean": "Korean"
|
"korean": "Korean"
|
||||||
},
|
},
|
||||||
"sidemenu": {
|
"sidemenu": {
|
||||||
"minting":"MINTING",
|
"minting": "MINTING",
|
||||||
"mintingdetails":"MINTING DETAILS",
|
"mintingdetails": "MINTING DETAILS",
|
||||||
"becomeAMinter":"BECOME A MINTER",
|
"becomeAMinter": "BECOME A MINTER",
|
||||||
"wallets":"WALLETS",
|
"wallets": "WALLETS",
|
||||||
"tradeportal":"TRADE PORTAL",
|
"tradeportal": "TRADE PORTAL",
|
||||||
"rewardshare":"REWARD SHARE",
|
"rewardshare": "REWARD SHARE",
|
||||||
"nameregistration":"NAME REGISTRATION",
|
"nameregistration": "NAME REGISTRATION",
|
||||||
"websites":"WEBSITES",
|
"websites": "WEBSITES",
|
||||||
"management":"MANAGEMENT",
|
"management": "MANAGEMENT",
|
||||||
"datamanagement":"DATA MANAGEMENT",
|
"datamanagement": "DATA MANAGEMENT",
|
||||||
"qchat":"Q-CHAT",
|
"qchat": "Q-CHAT",
|
||||||
"groupmanagement":"GROUP MANAGEMENT",
|
"groupmanagement": "GROUP MANAGEMENT",
|
||||||
"puzzles":"PUZZLES",
|
"puzzles": "PUZZLES",
|
||||||
"nodemanagement":"NODE MANAGEMENT",
|
"nodemanagement": "NODE MANAGEMENT",
|
||||||
"trading":"TRADING",
|
"trading": "TRADING",
|
||||||
"groups":"GROUPS"
|
"groups": "GROUPS"
|
||||||
},
|
},
|
||||||
"login": {
|
"login": {
|
||||||
"login": "Login",
|
"login": "Login",
|
||||||
@ -93,70 +93,74 @@
|
|||||||
"selectfile": "Select file",
|
"selectfile": "Select file",
|
||||||
"dragfile": "Drag and drop backup here"
|
"dragfile": "Drag and drop backup here"
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings":{
|
||||||
"generalinfo": "General Account Info",
|
"generalinfo":"General Account Info",
|
||||||
"address": "Address",
|
"address":"Address",
|
||||||
"publickey": "Public Key",
|
"publickey":"Public Key",
|
||||||
"settings": "Settings",
|
"settings":"Settings",
|
||||||
"account": "Account",
|
"account":"Account",
|
||||||
"security": "Security",
|
"security":"Security",
|
||||||
"qr_login_menu_item": "QR Login",
|
"qr_login_menu_item":"QR Login",
|
||||||
"qr_login_description_1": "Scan this code to unlock your wallet on other device using the same password which you logged in with.",
|
"qr_login_description_1":"Scan this code to unlock your wallet on other device using the same password which you logged in with.",
|
||||||
"qr_login_description_2": "Choose a password which you will use to unlock your wallet on other device after scanning the QR code.",
|
"qr_login_description_2":"Choose a password which you will use to unlock your wallet on other device after scanning the QR code.",
|
||||||
"qr_login_button_1": "Show login QR code",
|
"qr_login_button_1":"Show login QR code",
|
||||||
"qr_login_button_2": "Generate login QR code",
|
"qr_login_button_2":"Generate login QR code",
|
||||||
"notifications": "Notifications",
|
"notifications":"Notifications",
|
||||||
"accountsecurity": "Account Security",
|
"accountsecurity":"Account Security",
|
||||||
"password": "Password",
|
"password":"Password",
|
||||||
"download": "Download Backup File",
|
"download":"Download Backup File",
|
||||||
"choose": "Please choose a password to encrypt your backup with. (This can be the same as the one you logged in with, or different)",
|
"choose":"Please choose a password to encrypt your backup with. (This can be the same as the one you logged in with, or different)",
|
||||||
"block": "Block Notifications (Coming Soon...)",
|
"block":"Block Notifications (Coming Soon...)",
|
||||||
"playsound": "Play Sound",
|
"playsound":"Play Sound",
|
||||||
"shownotifications": "Show Notifications",
|
"shownotifications":"Show Notifications",
|
||||||
"nodeurl": "Node Url",
|
"nodeurl":"Node Url",
|
||||||
"nodehint": "Select a node from the default list of nodes above or add a custom node to the list above by clicking on the button below",
|
"nodehint":"Select a node from the default list of nodes above or add a custom node to the list above by clicking on the button below",
|
||||||
"addcustomnode": "Add Custom Node",
|
"addcustomnode":"Add Custom Node",
|
||||||
"addandsave": "Add And Save",
|
"addandsave":"Add And Save",
|
||||||
"protocol": "Protocol",
|
"protocol":"Protocol",
|
||||||
"domain": "Domain",
|
"domain":"Domain",
|
||||||
"port": "Port",
|
"port":"Port",
|
||||||
"import": "Import Nodes",
|
"import":"Import Nodes",
|
||||||
"export": "Export Nodes",
|
"export":"Export Nodes",
|
||||||
"deletecustomnode": "Remove All Custom Nodes",
|
"deletecustomnode":"Remove All Custom Nodes",
|
||||||
"warning": "Your existing nodes will be deleted and from backup new created.",
|
"warning":"Your existing nodes will be deleted and from backup new created.",
|
||||||
"snack1": "Successfully deleted and added standard nodes",
|
"snack1":"Successfully deleted and added standard nodes",
|
||||||
"snack2": "UI conected to node",
|
"snack2":"UI conected to node",
|
||||||
"snack3": "Successfully added and saved custom node",
|
"snack3":"Successfully added and saved custom node",
|
||||||
"snack4": "Nodes successfully saved as",
|
"snack4":"Nodes successfully saved as",
|
||||||
"snack5": "Nodes successfully imported"
|
"snack5":"Nodes successfully imported",
|
||||||
|
"exp1":"Export Private Master Key",
|
||||||
|
"exp2":"Export Master Key",
|
||||||
|
"exp3":"Export",
|
||||||
|
"exp4":"Please choose a wallet to backup the private master key."
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo": {
|
||||||
"blockheight":"Block Height",
|
"blockheight": "Block Height",
|
||||||
"uiversion":"UI Version",
|
"uiversion": "UI Version",
|
||||||
"coreversion":"Core Version",
|
"coreversion": "Core Version",
|
||||||
"minting":"(Minting)",
|
"minting": "(Minting)",
|
||||||
"synchronizing":"Synchronizing",
|
"synchronizing": "Synchronizing",
|
||||||
"peers":"Connected Peers"
|
"peers": "Connected Peers"
|
||||||
},
|
},
|
||||||
"walletprofile": {
|
"walletprofile": {
|
||||||
"minterlevel": "Minter Level",
|
"minterlevel": "Minter Level",
|
||||||
"blocksminted": "Blocks Minted"
|
"blocksminted": "Blocks Minted"
|
||||||
},
|
},
|
||||||
"general":{
|
"general": {
|
||||||
"yes":"Yes",
|
"yes": "Yes",
|
||||||
"no":"No",
|
"no": "No",
|
||||||
"confirm":"Confirm",
|
"confirm": "Confirm",
|
||||||
"decline":"Decline",
|
"decline": "Decline",
|
||||||
"open":"Open",
|
"open": "Open",
|
||||||
"close":"Close",
|
"close": "Close",
|
||||||
"back":"Back",
|
"back": "Back",
|
||||||
"next":"Next",
|
"next": "Next",
|
||||||
"create":"Create",
|
"create": "Create",
|
||||||
"continue":"Continue",
|
"continue": "Continue",
|
||||||
"save":"Save",
|
"save": "Save",
|
||||||
"balance":"Balance",
|
"balance": "Balance",
|
||||||
"balances":"YOUR WALLET BALANCES",
|
"balances": "YOUR WALLET BALANCES",
|
||||||
"update":"UPDATE WALLET BALANCES"
|
"update": "UPDATE WALLET BALANCES"
|
||||||
},
|
},
|
||||||
"startminting": {
|
"startminting": {
|
||||||
"smchange1": "Cannot fetch minting accounts",
|
"smchange1": "Cannot fetch minting accounts",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"AUTO BUY WITH",
|
"tchange45":"AUTO BUY WITH",
|
||||||
"tchange46":"AUTO BUY",
|
"tchange46":"AUTO BUY",
|
||||||
"tchange47":"Sell for this price",
|
"tchange47":"Sell for this price",
|
||||||
"tchange48":"NOT ENOUGH"
|
"tchange48":"NOT ENOUGH",
|
||||||
|
"tchange49":"Price Chart"
|
||||||
},
|
},
|
||||||
"rewardsharepage": {
|
"rewardsharepage": {
|
||||||
"rchange1": "Rewardshares",
|
"rchange1": "Rewardshares",
|
||||||
@ -355,47 +360,47 @@
|
|||||||
"rchange21": "Reward Share Successful!",
|
"rchange21": "Reward Share Successful!",
|
||||||
"rchange22": "Reward Share Removed Successfully!"
|
"rchange22": "Reward Share Removed Successfully!"
|
||||||
},
|
},
|
||||||
"registernamepage":{
|
"registernamepage": {
|
||||||
"nchange1":"Name Registration",
|
"nchange1": "Name Registration",
|
||||||
"nchange2":"Register Name",
|
"nchange2": "Register Name",
|
||||||
"nchange3":"Registered Names",
|
"nchange3": "Registered Names",
|
||||||
"nchange4":"Avatar",
|
"nchange4": "Avatar",
|
||||||
"nchange5":"Name",
|
"nchange5": "Name",
|
||||||
"nchange6":"Owner",
|
"nchange6": "Owner",
|
||||||
"nchange7":"Action",
|
"nchange7": "Action",
|
||||||
"nchange8":"No names registered by this account!",
|
"nchange8": "No names registered by this account!",
|
||||||
"nchange9":"Register a Name!",
|
"nchange9": "Register a Name!",
|
||||||
"nchange10":"Description (optional)",
|
"nchange10": "Description (optional)",
|
||||||
"nchange11":"Doing something delicious",
|
"nchange11": "Doing something delicious",
|
||||||
"nchange12":"Registering Name",
|
"nchange12": "Registering Name",
|
||||||
"nchange13":"The current name registration fee is",
|
"nchange13": "The current name registration fee is",
|
||||||
"nchange14":"Register",
|
"nchange14": "Register",
|
||||||
"nchange15":"Set Avatar",
|
"nchange15": "Set Avatar",
|
||||||
"nchange16":"Need Core Update",
|
"nchange16": "Need Core Update",
|
||||||
"nchange17":"Name Already Exists!",
|
"nchange17": "Name Already Exists!",
|
||||||
"nchange18":"Name Registration Successful!",
|
"nchange18": "Name Registration Successful!",
|
||||||
"nchange19":"Sell Name",
|
"nchange19": "Sell Name",
|
||||||
"nchange20":"Cancel Sell",
|
"nchange20": "Cancel Sell",
|
||||||
"nchange21":"Buy Name",
|
"nchange21": "Buy Name",
|
||||||
"nchange22":"Open Market Names To Sell",
|
"nchange22": "Open Market Names To Sell",
|
||||||
"nchange23":"Sell Price",
|
"nchange23": "Sell Price",
|
||||||
"nchange24":"No Names To Sell",
|
"nchange24": "No Names To Sell",
|
||||||
"nchange25":"Name To Sell",
|
"nchange25": "Name To Sell",
|
||||||
"nchange26":"Are you sure to sell this name ?",
|
"nchange26": "Are you sure to sell this name ?",
|
||||||
"nchange27":"For this price in QORT",
|
"nchange27": "For this price in QORT",
|
||||||
"nchange28":"On pressing confirm, the sell name request will be sent!",
|
"nchange28": "On pressing confirm, the sell name request will be sent!",
|
||||||
"nchange29":"Name To Cancel",
|
"nchange29": "Name To Cancel",
|
||||||
"nchange30":"Are you sure to cancel the sell for this name ?",
|
"nchange30": "Are you sure to cancel the sell for this name ?",
|
||||||
"nchange31":"On pressing confirm, the cancel sell name request will be sent!",
|
"nchange31": "On pressing confirm, the cancel sell name request will be sent!",
|
||||||
"nchange32":"Sell Name Request Successful!",
|
"nchange32": "Sell Name Request Successful!",
|
||||||
"nchange33":"Cancel Sell Name Request Successful!",
|
"nchange33": "Cancel Sell Name Request Successful!",
|
||||||
"nchange34":"Buy Name Request Successful!",
|
"nchange34": "Buy Name Request Successful!",
|
||||||
"nchange35":"YOU HAVE A NAME!",
|
"nchange35": "YOU HAVE A NAME!",
|
||||||
"nchange36":"Only accounts with no registered name can buy a name.",
|
"nchange36": "Only accounts with no registered name can buy a name.",
|
||||||
"nchange37":"ATTENTION!",
|
"nchange37": "ATTENTION!",
|
||||||
"nchange38":"You not have enough qort to buy this name.",
|
"nchange38": "You not have enough qort to buy this name.",
|
||||||
"nchange39":"Are you sure to buy this name ?",
|
"nchange39": "Are you sure to buy this name ?",
|
||||||
"nchange40":"On pressing confirm, the buy name request will be sent!"
|
"nchange40": "On pressing confirm, the buy name request will be sent!"
|
||||||
},
|
},
|
||||||
"websitespage": {
|
"websitespage": {
|
||||||
"schange1": "Browse Websites",
|
"schange1": "Browse Websites",
|
||||||
@ -542,9 +547,25 @@
|
|||||||
"cchange38": "User Verified",
|
"cchange38": "User Verified",
|
||||||
"cchange39": "Cannot send an encrypted message to this user since they do not have their publickey on chain.",
|
"cchange39": "Cannot send an encrypted message to this user since they do not have their publickey on chain.",
|
||||||
"cchange40": "IMAGE (click to view)",
|
"cchange40": "IMAGE (click to view)",
|
||||||
"cchange41":"Your Balance Is Under 4.20 QORT",
|
"cchange41": "Your Balance Is Under 4.20 QORT",
|
||||||
"cchange42":"Out of the need to combat spam, accounts with under 4.20 Qort balance will take a long time to SEND messages in Q-Chat. If you wish to immediately increase the send speed for Q-Chat messages, obtain over 4.20 QORT to your address. This can be done with trades in the Trade Portal, or by way of another Qortian giving you the QORT. Once you have over 4.20 QORT in your account, Q-Chat messages will be instant and this dialog will no more show. Thank you for your understanding of this necessary spam prevention method, and we hope you enjoy Qortal!"
|
"cchange42": "Out of the need to combat spam, accounts with under 4.20 Qort balance will take a long time to SEND messages in Q-Chat. If you wish to immediately increase the send speed for Q-Chat messages, obtain over 4.20 QORT to your address. This can be done with trades in the Trade Portal, or by way of another Qortian giving you the QORT. Once you have over 4.20 QORT in your account, Q-Chat messages will be instant and this dialog will no more show. Thank you for your understanding of this necessary spam prevention method, and we hope you enjoy Qortal!",
|
||||||
|
"cchange43": "Tip QORT to",
|
||||||
|
"cchange44": "SEND MESSAGE",
|
||||||
|
"cchange45": "TIP USER",
|
||||||
|
"cchange46": "Tip Amount",
|
||||||
|
"cchange47": "Available Balance",
|
||||||
|
"cchange48": "Failed to Fetch QORT Balance. Try again!",
|
||||||
|
"cchange49": "Current static fee",
|
||||||
|
"cchange50": "Send",
|
||||||
|
"cchange51": "Insufficient Funds!",
|
||||||
|
"cchange52": "Invalid Amount!",
|
||||||
|
"cchange53": "Receiver cannot be empty!",
|
||||||
|
"cchange54": "Invalid Receiver!",
|
||||||
|
"cchange55": "Transaction Successful!",
|
||||||
|
"cchange56": "Transaction Failed!",
|
||||||
|
"cchange57": "User Info",
|
||||||
|
"cchange58": "SEND MESSAGE",
|
||||||
|
"cchange59": "TIP USER"
|
||||||
},
|
},
|
||||||
"welcomepage": {
|
"welcomepage": {
|
||||||
"wcchange1": "Welcome to Q-Chat",
|
"wcchange1": "Welcome to Q-Chat",
|
||||||
@ -574,67 +595,68 @@
|
|||||||
"bcchange14": "Forward",
|
"bcchange14": "Forward",
|
||||||
"bcchange15": "Message Forwarded",
|
"bcchange15": "Message Forwarded",
|
||||||
"bcchange16": "Choose Recipient or Search for One Below",
|
"bcchange16": "Choose Recipient or Search for One Below",
|
||||||
"bcchange17": "FORWARDED"
|
"bcchange17": "FORWARDED",
|
||||||
|
"bcchange18": "Tip User"
|
||||||
},
|
},
|
||||||
"grouppage":{
|
"grouppage": {
|
||||||
"gchange1":"Qortal Groups",
|
"gchange1": "Qortal Groups",
|
||||||
"gchange2":"Create Group",
|
"gchange2": "Create Group",
|
||||||
"gchange3":"Your Joined Groups",
|
"gchange3": "Your Joined Groups",
|
||||||
"gchange4":"Group Name",
|
"gchange4": "Group Name",
|
||||||
"gchange5":"Description",
|
"gchange5": "Description",
|
||||||
"gchange6":"Role",
|
"gchange6": "Role",
|
||||||
"gchange7":"Action",
|
"gchange7": "Action",
|
||||||
"gchange8":"Not a member of any group!",
|
"gchange8": "Not a member of any group!",
|
||||||
"gchange9":"Public Groups",
|
"gchange9": "Public Groups",
|
||||||
"gchange10":"Owner",
|
"gchange10": "Owner",
|
||||||
"gchange11":"No Open Public Groups available!",
|
"gchange11": "No Open Public Groups available!",
|
||||||
"gchange12":"Create a New Group",
|
"gchange12": "Create a New Group",
|
||||||
"gchange13":"Group Type",
|
"gchange13": "Group Type",
|
||||||
"gchange14":"This Field is Required",
|
"gchange14": "This Field is Required",
|
||||||
"gchange15":"Select an option",
|
"gchange15": "Select an option",
|
||||||
"gchange16":"Public",
|
"gchange16": "Public",
|
||||||
"gchange17":"Private",
|
"gchange17": "Private",
|
||||||
"gchange18":"Group Approval Threshold (number / percentage of Admins that must approve a transaction):",
|
"gchange18": "Group Approval Threshold (number / percentage of Admins that must approve a transaction):",
|
||||||
"gchange19":"NONE",
|
"gchange19": "NONE",
|
||||||
"gchange20":"ONE",
|
"gchange20": "ONE",
|
||||||
"gchange21":"Minimum Block delay for Group Transaction Approvals:",
|
"gchange21": "Minimum Block delay for Group Transaction Approvals:",
|
||||||
"gchange22":"minutes",
|
"gchange22": "minutes",
|
||||||
"gchange23":"hour",
|
"gchange23": "hour",
|
||||||
"gchange24":"hours",
|
"gchange24": "hours",
|
||||||
"gchange25":"day",
|
"gchange25": "day",
|
||||||
"gchange26":"days",
|
"gchange26": "days",
|
||||||
"gchange27":"Maximum Block delay for Group Transaction Approvals:",
|
"gchange27": "Maximum Block delay for Group Transaction Approvals:",
|
||||||
"gchange28":"Creating Group",
|
"gchange28": "Creating Group",
|
||||||
"gchange29":"Create Group",
|
"gchange29": "Create Group",
|
||||||
"gchange30":"Join Group Request",
|
"gchange30": "Join Group Request",
|
||||||
"gchange31":"Date Created",
|
"gchange31": "Date Created",
|
||||||
"gchange32":"Date Updated",
|
"gchange32": "Date Updated",
|
||||||
"gchange33":"Joining",
|
"gchange33": "Joining",
|
||||||
"gchange34":"Join Group",
|
"gchange34": "Join Group",
|
||||||
"gchange35":"Leave Group Request",
|
"gchange35": "Leave Group Request",
|
||||||
"gchange36":"Leaving",
|
"gchange36": "Leaving",
|
||||||
"gchange37":"Leave Group",
|
"gchange37": "Leave Group",
|
||||||
"gchange38":"Manage Group Owner:",
|
"gchange38": "Manage Group Owner:",
|
||||||
"gchange39":"Manage Group Admin:",
|
"gchange39": "Manage Group Admin:",
|
||||||
"gchange40":"Manage Group",
|
"gchange40": "Manage Group",
|
||||||
"gchange41":"Group Creation Successful!",
|
"gchange41": "Group Creation Successful!",
|
||||||
"gchange42":"Invalid Group Name",
|
"gchange42": "Invalid Group Name",
|
||||||
"gchange43":"Invalid Group Description",
|
"gchange43": "Invalid Group Description",
|
||||||
"gchange44":"Select a Group Typ",
|
"gchange44": "Select a Group Typ",
|
||||||
"gchange45":"Select a Group Approval Threshold",
|
"gchange45": "Select a Group Approval Threshold",
|
||||||
"gchange46":"Select a Minimum Block delay for Group Transaction Approvals",
|
"gchange46": "Select a Minimum Block delay for Group Transaction Approvals",
|
||||||
"gchange47":"Select a Maximum Block delay for Group Transaction Approvals",
|
"gchange47": "Select a Maximum Block delay for Group Transaction Approvals",
|
||||||
"gchange48":"Join Group Request Sent Successfully!",
|
"gchange48": "Join Group Request Sent Successfully!",
|
||||||
"gchange49":"Leave Group Request Sent Successfully!",
|
"gchange49": "Leave Group Request Sent Successfully!",
|
||||||
"gchange50":"Leave",
|
"gchange50": "Leave",
|
||||||
"gchange51":"Join",
|
"gchange51": "Join",
|
||||||
"gchange52":"Admin",
|
"gchange52": "Admin",
|
||||||
"gchange53":"Member",
|
"gchange53": "Member",
|
||||||
"gchange54":"Members",
|
"gchange54": "Members",
|
||||||
"gchange55":"Search Private Group",
|
"gchange55": "Search Private Group",
|
||||||
"gchange56":"Group Name To Search",
|
"gchange56": "Group Name To Search",
|
||||||
"gchange57":"Private Group Name Not Found",
|
"gchange57": "Private Group Name Not Found",
|
||||||
"gchange58":"Note that group name must exact match."
|
"gchange58": "Note that group name must exact match."
|
||||||
},
|
},
|
||||||
"puzzlepage": {
|
"puzzlepage": {
|
||||||
"pchange1": "Puzzles",
|
"pchange1": "Puzzles",
|
||||||
@ -724,51 +746,51 @@
|
|||||||
"rewarddialog5": "You are removing a reward share transaction associated with account:",
|
"rewarddialog5": "You are removing a reward share transaction associated with account:",
|
||||||
"rewarddialog6": "On pressing confirm, the rewardshare will be removed and the minting key will become invalid."
|
"rewarddialog6": "On pressing confirm, the rewardshare will be removed and the minting key will become invalid."
|
||||||
},
|
},
|
||||||
"sponsorshipspage":{
|
"sponsorshipspage": {
|
||||||
"schange1":"Active Sponsorships",
|
"schange1": "Active Sponsorships",
|
||||||
"schange2":"Account Address",
|
"schange2": "Account Address",
|
||||||
"schange3":"Total Sponsorships active",
|
"schange3": "Total Sponsorships active",
|
||||||
"schange4":"Next sponsorship ending in",
|
"schange4": "Next sponsorship ending in",
|
||||||
"schange5":"Sponsor New Minter",
|
"schange5": "Sponsor New Minter",
|
||||||
"schange6":"Finished Sponsorships",
|
"schange6": "Finished Sponsorships",
|
||||||
"schange7":"Completed",
|
"schange7": "Completed",
|
||||||
"schange8":"Addresses",
|
"schange8": "Addresses",
|
||||||
"schange9":"You currently have no active sponsorships",
|
"schange9": "You currently have no active sponsorships",
|
||||||
"schange10":"Public Key Lookup",
|
"schange10": "Public Key Lookup",
|
||||||
"schange11":"Copy",
|
"schange11": "Copy",
|
||||||
"schange12":"Address to Public Key Converter",
|
"schange12": "Address to Public Key Converter",
|
||||||
"schange13":"Enter address",
|
"schange13": "Enter address",
|
||||||
"schange14":"In progress",
|
"schange14": "In progress",
|
||||||
"schange15":"Finishing up",
|
"schange15": "Finishing up",
|
||||||
"schange16":"Copy the key below and share it with your sponsored person.",
|
"schange16": "Copy the key below and share it with your sponsored person.",
|
||||||
"schange17":"Copied to clipboard",
|
"schange17": "Copied to clipboard",
|
||||||
"schange18":"Warning: do not leave this plugin or close the Qortal UI until completion!",
|
"schange18": "Warning: do not leave this plugin or close the Qortal UI until completion!",
|
||||||
"schange19":"Copy Sponsorship Key",
|
"schange19": "Copy Sponsorship Key",
|
||||||
"schange20":"Creating relationship",
|
"schange20": "Creating relationship",
|
||||||
"schange21":"Remove Sponsorship Key"
|
"schange21": "Remove Sponsorship Key"
|
||||||
},
|
},
|
||||||
"explorerpage":{
|
"explorerpage": {
|
||||||
"exp1":"Address or name to search",
|
"exp1": "Address or name to search",
|
||||||
"exp2":"Account Balance",
|
"exp2": "Account Balance",
|
||||||
"exp3":"More Info",
|
"exp3": "More Info",
|
||||||
"exp4":"Address or Name not found !",
|
"exp4": "Address or Name not found !",
|
||||||
"exp5":"Note that registered names are case-sensitive.",
|
"exp5": "Note that registered names are case-sensitive.",
|
||||||
"exp6":"Founder",
|
"exp6": "Founder",
|
||||||
"exp7":"Info",
|
"exp7": "Info",
|
||||||
"exp8":"Show all buy trades",
|
"exp8": "Show all buy trades",
|
||||||
"exp9":"Show all sell trades",
|
"exp9": "Show all sell trades",
|
||||||
"exp10":"BUY HISTORY",
|
"exp10": "BUY HISTORY",
|
||||||
"exp11":"SELL HISTORY",
|
"exp11": "SELL HISTORY",
|
||||||
"exp12":"No buy trades made yet.",
|
"exp12": "No buy trades made yet.",
|
||||||
"exp13":"No sell trades made yet.",
|
"exp13": "No sell trades made yet.",
|
||||||
"exp14":"Show complete info",
|
"exp14": "Show complete info",
|
||||||
"exp15":"Minting Since",
|
"exp15": "Minting Since",
|
||||||
"exp16":"Not Minting",
|
"exp16": "Not Minting",
|
||||||
"exp17":"ALL PAYMENTS",
|
"exp17": "ALL PAYMENTS",
|
||||||
"exp18":"Payments",
|
"exp18": "Payments",
|
||||||
"exp19":"Sent",
|
"exp19": "Sent",
|
||||||
"exp20":"Received",
|
"exp20": "Received",
|
||||||
"exp21":"Trades"
|
"exp21": "Trades"
|
||||||
},
|
},
|
||||||
"managegroup":{
|
"managegroup":{
|
||||||
"mg1":"Group Members",
|
"mg1":"Group Members",
|
||||||
@ -822,6 +844,15 @@
|
|||||||
"mg49":"On pressing confirm, the cancel invite request will be sent!",
|
"mg49":"On pressing confirm, the cancel invite request will be sent!",
|
||||||
"mg50":"Coming Soon...",
|
"mg50":"Coming Soon...",
|
||||||
"mg51":"Minimum 3 Characters / Maximum 32 Characters",
|
"mg51":"Minimum 3 Characters / Maximum 32 Characters",
|
||||||
"mg52":"Maximum 128 Characters"
|
"mg52":"Maximum 128 Characters",
|
||||||
|
"mg53":"Your Open Join Requests",
|
||||||
|
"mg54":"No Open Join Requests",
|
||||||
|
"mg55":"Are you sure to accept the join request from this member ?",
|
||||||
|
"mg56":"On pressing confirm, the accept join request will be sent!",
|
||||||
|
"mg57":"Join Request Successfully Accepted",
|
||||||
|
"mg58":"SOMETHING WENT WRONG",
|
||||||
|
"mg59":"Cancel Join Request Successfully Accepted",
|
||||||
|
"mg60":"Are you sure to cancel the join request from this member ?",
|
||||||
|
"mg61":"On pressing confirm, the cancel join request will be sent!"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"连接到节点的 UI",
|
"snack2":"连接到节点的 UI",
|
||||||
"snack3":"成功添加并保存自定义节点",
|
"snack3":"成功添加并保存自定义节点",
|
||||||
"snack4":"节点成功保存为",
|
"snack4":"节点成功保存为",
|
||||||
"snack5":"节点成功导入"
|
"snack5":"节点成功导入",
|
||||||
|
"exp1":"导出主密钥",
|
||||||
|
"exp2":"导出主密钥",
|
||||||
|
"exp3":"导出",
|
||||||
|
"exp4":"请选择一个钱包来备份私钥。"
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"区块高度",
|
"blockheight":"区块高度",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"自动购买",
|
"tchange45":"自动购买",
|
||||||
"tchange46":"自动购买",
|
"tchange46":"自动购买",
|
||||||
"tchange47":"以这个价格出售",
|
"tchange47":"以这个价格出售",
|
||||||
"tchange48":"不够"
|
"tchange48":"不够",
|
||||||
|
"tchange49":"价格图表"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"铸币密钥",
|
"rchange1":"铸币密钥",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"按下确认后,将发送取消邀请请求!",
|
"mg49":"按下确认后,将发送取消邀请请求!",
|
||||||
"mg50":"即将推出……",
|
"mg50":"即将推出……",
|
||||||
"mg51":"最少 3 个字符 / 最多 32 个字符",
|
"mg51":"最少 3 个字符 / 最多 32 个字符",
|
||||||
"mg52":"最多 128 个字符"
|
"mg52":"最多 128 个字符",
|
||||||
|
"mg53":"您的公开加入请求",
|
||||||
|
"mg54":"没有开放的加入请求",
|
||||||
|
"mg55":"您确定接受该会员的加入请求吗?",
|
||||||
|
"mg56":"按下确认后,将发送接受加入请求!",
|
||||||
|
"mg57":"成功接受加入请求",
|
||||||
|
"mg58":"出了点问题",
|
||||||
|
"mg59":"取消加入请求已成功接受",
|
||||||
|
"mg60":"您确定要取消该会员的加入请求吗?",
|
||||||
|
"mg61":"按下确认后,将发送取消加入请求!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,7 +128,11 @@
|
|||||||
"snack2":"連接到節點的 UI",
|
"snack2":"連接到節點的 UI",
|
||||||
"snack3":"成功添加並保存自定義節點",
|
"snack3":"成功添加並保存自定義節點",
|
||||||
"snack4":"節點成功保存為",
|
"snack4":"節點成功保存為",
|
||||||
"snack5":"節點成功導入"
|
"snack5":"節點成功導入",
|
||||||
|
"exp1":"導出主密鑰",
|
||||||
|
"exp2":"導出主密鑰",
|
||||||
|
"exp3":"導出",
|
||||||
|
"exp4":"請選擇一個錢包來備份私鑰。"
|
||||||
},
|
},
|
||||||
"appinfo":{
|
"appinfo":{
|
||||||
"blockheight":"區塊高度",
|
"blockheight":"區塊高度",
|
||||||
@ -329,7 +333,8 @@
|
|||||||
"tchange45":"自動購買",
|
"tchange45":"自動購買",
|
||||||
"tchange46":"自動購買",
|
"tchange46":"自動購買",
|
||||||
"tchange47":"以這個價格出售",
|
"tchange47":"以這個價格出售",
|
||||||
"tchange48":"不夠"
|
"tchange48":"不夠",
|
||||||
|
"tchange49":"價格圖表"
|
||||||
},
|
},
|
||||||
"rewardsharepage":{
|
"rewardsharepage":{
|
||||||
"rchange1":"鑄幣密鑰",
|
"rchange1":"鑄幣密鑰",
|
||||||
@ -799,6 +804,15 @@
|
|||||||
"mg49":"按下確認後,將發送取消邀請請求!",
|
"mg49":"按下確認後,將發送取消邀請請求!",
|
||||||
"mg50":"即將推出……",
|
"mg50":"即將推出……",
|
||||||
"mg51":"最少 3 個字符 / 最多 32 個字符",
|
"mg51":"最少 3 個字符 / 最多 32 個字符",
|
||||||
"mg52":"最多 128 個字符"
|
"mg52":"最多 128 個字符",
|
||||||
|
"mg53":"您的公開加入請求",
|
||||||
|
"mg54":"沒有開放的加入請求",
|
||||||
|
"mg55":"您確定接受該會員的加入請求嗎?",
|
||||||
|
"mg56":"按下確認後,將發送接受加入請求!",
|
||||||
|
"mg57":"成功接受加入請求",
|
||||||
|
"mg58":"出了點問題",
|
||||||
|
"mg59":"取消加入請求已成功接受",
|
||||||
|
"mg60":"您確定要取消該會員的加入請求嗎?",
|
||||||
|
"mg61":"按下確認後,將發送取消加入請求!"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"sass": "1.57.1"
|
"sass": "1.57.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.20.7",
|
"@babel/core": "7.20.12",
|
||||||
"@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",
|
||||||
@ -58,28 +58,27 @@
|
|||||||
"@rollup/plugin-commonjs": "24.0.0",
|
"@rollup/plugin-commonjs": "24.0.0",
|
||||||
"@rollup/plugin-node-resolve": "15.0.1",
|
"@rollup/plugin-node-resolve": "15.0.1",
|
||||||
"@rollup/plugin-replace": "5.0.2",
|
"@rollup/plugin-replace": "5.0.2",
|
||||||
"@rollup/plugin-terser": "0.2.1",
|
"@rollup/plugin-terser": "0.3.0",
|
||||||
"@vaadin/button": "23.3.2",
|
"@vaadin/button": "23.3.3",
|
||||||
"@vaadin/grid": "23.3.2",
|
"@vaadin/grid": "23.3.3",
|
||||||
"@vaadin/icons": "23.3.2",
|
"@vaadin/icons": "23.3.3",
|
||||||
"@vaadin/password-field": "23.3.2",
|
"@vaadin/password-field": "23.3.3",
|
||||||
"@vaadin/tooltip": "23.3.2",
|
"@vaadin/tooltip": "23.3.3",
|
||||||
"asmcrypto.js": "2.3.2",
|
"asmcrypto.js": "2.3.2",
|
||||||
"bcryptjs": "2.4.3",
|
"bcryptjs": "2.4.3",
|
||||||
"epml": "0.3.3",
|
"epml": "0.3.3",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"lit": "2.5.0",
|
"lit": "2.6.0",
|
||||||
"lit-translate": "2.0.1",
|
"lit-translate": "2.0.1",
|
||||||
"pwa-helpers": "0.9.1",
|
"pwa-helpers": "0.9.1",
|
||||||
"random-sentence-generator": "0.0.8",
|
"random-sentence-generator": "0.0.8",
|
||||||
"redux": "4.2.0",
|
"redux": "4.2.0",
|
||||||
"redux-thunk": "2.4.2",
|
"redux-thunk": "2.4.2",
|
||||||
"rollup": "3.9.0",
|
"rollup": "3.9.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",
|
||||||
"rollup-plugin-terser": "7.0.2",
|
"rollup-plugin-web-worker-loader": "1.6.1"
|
||||||
"rollup-plugin-web-worker-loader": "^1.6.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.17.1"
|
"node": ">=16.17.1"
|
||||||
|
@ -142,8 +142,6 @@ class AppView extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
app-drawer {
|
app-drawer {
|
||||||
box-shadow: var(--shadow-2);
|
box-shadow: var(--shadow-2);
|
||||||
background: var(--sidetopbar);
|
|
||||||
--app-drawer-scrim-background: rgba(0,0,0,0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app-header {
|
app-header {
|
||||||
@ -185,24 +183,26 @@ class AppView extends connect(store)(LitElement) {
|
|||||||
background: var(--sidetopbar);
|
background: var(--sidetopbar);
|
||||||
}
|
}
|
||||||
|
|
||||||
.sideBarMenu{
|
.sideBarMenu {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex: 1 1;
|
flex: 1 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sideBar::-webkit-scrollbar {
|
.sideBarMenu::-webkit-scrollbar-track {
|
||||||
width: 7px;
|
background-color: whitesmoke;
|
||||||
background-color: transparent;
|
border-radius: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sideBar::-webkit-scrollbar-track {
|
.sideBarMenu::-webkit-scrollbar {
|
||||||
background-color: transparent;
|
width: 6px;
|
||||||
|
border-radius: 7px;
|
||||||
|
background-color: whitesmoke;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sideBar::-webkit-scrollbar-thumb {
|
.sideBarMenu::-webkit-scrollbar-thumb {
|
||||||
background-color: #333;
|
background-color: rgb(180, 176, 176);
|
||||||
border-radius: 6px;
|
border-radius: 7px;
|
||||||
border: 3px solid #333;
|
transition: all 0.3s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
#balanceheader {
|
#balanceheader {
|
||||||
@ -325,6 +325,11 @@ class AppView extends connect(store)(LitElement) {
|
|||||||
0%,100% { opacity: 0; }
|
0%,100% { opacity: 0; }
|
||||||
50% { opacity: 10; }
|
50% { opacity: 10; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sideBarMenu::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: rgb(148, 146, 146);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
`
|
`
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
236
qortal-ui-core/src/components/settings-view/export-keys.js
Normal file
236
qortal-ui-core/src/components/settings-view/export-keys.js
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { connect } from 'pwa-helpers'
|
||||||
|
import { store } from '../../store.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
import '@material/mwc-dialog'
|
||||||
|
import '@material/mwc-button'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
import FileSaver from 'file-saver'
|
||||||
|
|
||||||
|
class ExportKeys extends connect(store)(LitElement) {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
theme: { type: String, reflect: true },
|
||||||
|
backupErrorMessage: { type: String },
|
||||||
|
btcPMK: { type: String },
|
||||||
|
ltcPMK: { type: String },
|
||||||
|
dogePMK: { type: String },
|
||||||
|
dgbPMK: { type: String },
|
||||||
|
rvnPMK: { type: String },
|
||||||
|
btcWALLET: { type: String },
|
||||||
|
ltcWALLET: { type: String },
|
||||||
|
dogeWALLET: { type: String },
|
||||||
|
dgbWALLET: { type: String },
|
||||||
|
rvnWALLET: { type: String },
|
||||||
|
btcName: { type: String },
|
||||||
|
ltcName: { type: String },
|
||||||
|
dogeName: { type: String },
|
||||||
|
dgbName: { type: String },
|
||||||
|
rvnName: { type: String },
|
||||||
|
btcShort: { type: String },
|
||||||
|
ltcShort: { type: String },
|
||||||
|
dogeShort: { type: String },
|
||||||
|
dgbShort: { type: String },
|
||||||
|
rvnShort: { type: String },
|
||||||
|
dWalletAddress: { type: String },
|
||||||
|
dPrivateKey: { type: String },
|
||||||
|
dCoinName: { type: String },
|
||||||
|
dCoinShort: { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
* {
|
||||||
|
--mdc-theme-primary: rgb(3, 169, 244);
|
||||||
|
--mdc-theme-surface: var(--white);
|
||||||
|
--mdc-dialog-content-ink-color: var(--black);
|
||||||
|
--mdc-dialog-min-width: 500px;
|
||||||
|
--mdc-dialog-max-width: 500px;
|
||||||
|
--lumo-primary-text-color: rgb(0, 167, 245);
|
||||||
|
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
||||||
|
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
||||||
|
--lumo-primary-color: hsl(199, 100%, 48%);
|
||||||
|
--lumo-base-color: var(--white);
|
||||||
|
--lumo-body-text-color: var(--black);
|
||||||
|
--lumo-secondary-text-color: var(--sectxt);
|
||||||
|
--lumo-contrast-60pct: var(--vdicon);
|
||||||
|
}
|
||||||
|
|
||||||
|
.center-box {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, 0%);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sub-main {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-box {
|
||||||
|
text-align: center;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 400px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.export-button {
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
border: none;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
color: white;
|
||||||
|
background: #03a9f4;
|
||||||
|
width: 75%;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 40px;
|
||||||
|
margin-top: 1rem;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: all .2s;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.red {
|
||||||
|
--mdc-theme-primary: red;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.backupErrorMessage = ''
|
||||||
|
this.btcPMK = store.getState().app.selectedAddress.btcWallet.derivedMasterPrivateKey
|
||||||
|
this.btcWALLET = store.getState().app.selectedAddress.btcWallet.address
|
||||||
|
this.btcName = 'Bitcoin'
|
||||||
|
this.btcShort = 'btc'
|
||||||
|
this.ltcPMK = store.getState().app.selectedAddress.ltcWallet.derivedMasterPrivateKey
|
||||||
|
this.ltcWALLET = store.getState().app.selectedAddress.ltcWallet.address
|
||||||
|
this.ltcName = 'Litecoin'
|
||||||
|
this.ltcShort = 'ltc'
|
||||||
|
this.dogePMK = store.getState().app.selectedAddress.dogeWallet.derivedMasterPrivateKey
|
||||||
|
this.dogeWALLET = store.getState().app.selectedAddress.dogeWallet.address
|
||||||
|
this.dogeName = 'Dogecoin'
|
||||||
|
this.dogeShort = 'doge'
|
||||||
|
this.dgbPMK = store.getState().app.selectedAddress.dgbWallet.derivedMasterPrivateKey
|
||||||
|
this.dgbWALLET = store.getState().app.selectedAddress.dgbWallet.address
|
||||||
|
this.dgbName = 'Digibyte'
|
||||||
|
this.dgbShort = 'dgb'
|
||||||
|
this.rvnPMK = store.getState().app.selectedAddress.rvnWallet.derivedMasterPrivateKey
|
||||||
|
this.rvnWALLET = store.getState().app.selectedAddress.rvnWallet.address
|
||||||
|
this.rvnName = 'Ravencoin'
|
||||||
|
this.rvnShort = 'rvn'
|
||||||
|
this.dWalletAddress = ''
|
||||||
|
this.dPrivateKey = ''
|
||||||
|
this.dCoinName = ''
|
||||||
|
this.dCoinShort = 'btc'
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
${translate("settings.exp4")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="sub-main">
|
||||||
|
<div class="center-box">
|
||||||
|
<div class="content-box">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: center;">
|
||||||
|
<img src="/img/btc.png" style="width: 32px; height: 32px;"> ${this.btcWALLET}<br>
|
||||||
|
</div>
|
||||||
|
<div @click=${() => this.checkForPmkDownload(this.btcWALLET, this.btcPMK, this.btcName, this.btcShort)} class="export-button"> ${translate("settings.exp2")} </div>
|
||||||
|
</div>
|
||||||
|
<div class="content-box">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: center;">
|
||||||
|
<img src="/img/ltc.png" style="width: 32px; height: 32px;"> ${this.ltcWALLET}<br>
|
||||||
|
</div>
|
||||||
|
<div @click=${() => this.checkForPmkDownload(this.ltcWALLET, this.ltcPMK, this.ltcName, this.ltcShort)} class="export-button"> ${translate("settings.exp2")} </div>
|
||||||
|
</div>
|
||||||
|
<div class="content-box">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: center;">
|
||||||
|
<img src="/img/doge.png" style="width: 32px; height: 32px;"> ${this.dogeWALLET}<br>
|
||||||
|
</div>
|
||||||
|
<div @click=${() => this.checkForPmkDownload(this.dogeWALLET, this.dogePMK, this.dogeName, this.dogeShort)} class="export-button"> ${translate("settings.exp2")} </div>
|
||||||
|
</div>
|
||||||
|
<div class="content-box">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: center;">
|
||||||
|
<img src="/img/dgb.png" style="width: 32px; height: 32px;"> ${this.dgbWALLET}<br>
|
||||||
|
</div>
|
||||||
|
<div @click=${() => this.checkForPmkDownload(this.dgbWALLET, this.dgbPMK, this.dgbName, this.dgbShort)} class="export-button"> ${translate("settings.exp2")} </div>
|
||||||
|
</div>
|
||||||
|
<div class="content-box">
|
||||||
|
<div style="display: flex; align-items: center; justify-content: center;">
|
||||||
|
<img src="/img/rvn.png" style="width: 32px; height: 32px;"> ${this.rvnWALLET}<br>
|
||||||
|
</div>
|
||||||
|
<div @click=${() => this.checkForPmkDownload(this.rvnWALLET, this.rvnPMK, this.rvnName, this.rvnShort)} class="export-button"> ${translate("settings.exp2")} </div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<mwc-dialog id="savePkmDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
|
<img src="/img/${this.dCoinShort}.png" style="width: 32px; height: 32px;">
|
||||||
|
<h3>${this.dCoinName} ${translate("settings.exp2")}</h3>
|
||||||
|
<hr>
|
||||||
|
<h4>${translate("settings.address")}: ${this.dWalletAddress}</h4>
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click="${() => this.closeSavePkmDialog()}"
|
||||||
|
class="red"
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</mwc-button>
|
||||||
|
<mwc-button
|
||||||
|
slot="secondaryAction"
|
||||||
|
@click="${() => this.exportKey(this.dPrivateKey, this.dCoinName, this.dWalletAddress)}"
|
||||||
|
>
|
||||||
|
${translate("settings.exp3")}
|
||||||
|
</mwc-button>
|
||||||
|
</mwc-dialog>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSavePkmDialog() {
|
||||||
|
this.shadowRoot.querySelector('#savePkmDialog').close()
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForPmkDownload(wAddress, wPkm, wName, wShort) {
|
||||||
|
this.dWalletAddress = ''
|
||||||
|
this.dPrivateKey = ''
|
||||||
|
this.dCoinName = ''
|
||||||
|
this.dCoinShort = ''
|
||||||
|
this.dWalletAddress = wAddress
|
||||||
|
this.dPrivateKey = wPkm
|
||||||
|
this.dCoinName = wName
|
||||||
|
this.dCoinShort = wShort
|
||||||
|
this.shadowRoot.querySelector('#savePkmDialog').show()
|
||||||
|
}
|
||||||
|
|
||||||
|
async exportKey(cMasterKey, cName, cAddress) {
|
||||||
|
const myPrivateMasterKey = cMasterKey
|
||||||
|
const myCoinName = cName
|
||||||
|
const myCoinAddress = cAddress
|
||||||
|
const blob = new Blob([`${myPrivateMasterKey}`], { type: 'text/plain;charset=utf-8' })
|
||||||
|
FileSaver.saveAs(blob, `Private_Master_Key_${myCoinName}_${myCoinAddress}.txt`)
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChanged(state) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('export-keys', ExportKeys)
|
@ -10,6 +10,7 @@ import './account-view.js'
|
|||||||
import './security-view.js'
|
import './security-view.js'
|
||||||
import './notifications-view.js'
|
import './notifications-view.js'
|
||||||
import './qr-login-view.js'
|
import './qr-login-view.js'
|
||||||
|
import './export-keys.js'
|
||||||
|
|
||||||
import { doLogout } from '../../redux/app/app-actions.js'
|
import { doLogout } from '../../redux/app/app-actions.js'
|
||||||
|
|
||||||
@ -156,6 +157,7 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
min-height: 460px;
|
min-height: 460px;
|
||||||
|
height: 60vh;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media(max-width:700px) {
|
@media(max-width:700px) {
|
||||||
@ -226,6 +228,7 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
<ul>
|
<ul>
|
||||||
<li @click=${ () => this.setSettingsView('info')} ><a class=${this.selectedView.id === 'info' ? 'active' : ''} href="javascript:void(0)">${translate("settings.account")}</a></li>
|
<li @click=${ () => this.setSettingsView('info')} ><a class=${this.selectedView.id === 'info' ? 'active' : ''} href="javascript:void(0)">${translate("settings.account")}</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('security')} ><a class=${this.selectedView.id === 'security' ? 'active' : ''} href="javascript:void(0)">${translate("settings.security")}</a></li>
|
<li @click=${ () => this.setSettingsView('security')} ><a class=${this.selectedView.id === 'security' ? 'active' : ''} href="javascript:void(0)">${translate("settings.security")}</a></li>
|
||||||
|
<li @click=${ () => this.setSettingsView('export')} ><a class=${this.selectedView.id === 'export' ? 'active' : ''} href="javascript:void(0)">${translate("settings.exp1") }</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('qr-login')} ><a class=${this.selectedView.id === 'qr-login' ? 'active' : ''} href="javascript:void(0)">${translate("settings.qr_login_menu_item") }</a></li>
|
<li @click=${ () => this.setSettingsView('qr-login')} ><a class=${this.selectedView.id === 'qr-login' ? 'active' : ''} href="javascript:void(0)">${translate("settings.qr_login_menu_item") }</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('notification')} ><a class=${this.selectedView.id === 'notification' ? 'active' : ''} href="javascript:void(0)">${translate("settings.notifications")}</a></li>
|
<li @click=${ () => this.setSettingsView('notification')} ><a class=${this.selectedView.id === 'notification' ? 'active' : ''} href="javascript:void(0)">${translate("settings.notifications")}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -247,25 +250,29 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
renderSettingViews(selectedView) {
|
renderSettingViews(selectedView) {
|
||||||
if (selectedView.id === 'info') {
|
if (selectedView.id === 'info') {
|
||||||
return html`<account-view></account-view>`;
|
return html`<account-view></account-view>`
|
||||||
} else if (selectedView.id === 'security') {
|
} else if (selectedView.id === 'security') {
|
||||||
return html`<security-view></security-view>`;
|
return html`<security-view></security-view>`
|
||||||
|
} else if (selectedView.id === 'export') {
|
||||||
|
return html`<export-keys></export-keys>`
|
||||||
} else if (selectedView.id === 'notification') {
|
} else if (selectedView.id === 'notification') {
|
||||||
return html`<notifications-view></notifications-view>`;
|
return html`<notifications-view></notifications-view>`
|
||||||
} else if (selectedView.id === 'qr-login') {
|
} else if (selectedView.id === 'qr-login') {
|
||||||
return html`<qr-login-view></qr-login-view>`;
|
return html`<qr-login-view></qr-login-view>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderHeaderViews() {
|
renderHeaderViews() {
|
||||||
if (this.selectedView.id === 'info') {
|
if (this.selectedView.id === 'info') {
|
||||||
return html`${translate("settings.generalinfo")}`;
|
return html`${translate("settings.generalinfo")}`
|
||||||
} else if (this.selectedView.id === 'security') {
|
} else if (this.selectedView.id === 'security') {
|
||||||
return html`${translate("settings.accountsecurity")}`;
|
return html`${translate("settings.accountsecurity")}`
|
||||||
|
} else if (this.selectedView.id === 'export') {
|
||||||
|
return html`${translate("settings.exp1")}`
|
||||||
} else if (this.selectedView.id === 'notification') {
|
} else if (this.selectedView.id === 'notification') {
|
||||||
return html`UI ${translate("settings.notifications")}`;
|
return html`UI ${translate("settings.notifications")}`
|
||||||
} else if (this.selectedView.id === 'qr-login') {
|
} else if (this.selectedView.id === 'qr-login') {
|
||||||
return html`${translate("settings.qr_login_menu_item")}`;
|
return html`${translate("settings.qr_login_menu_item")}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,6 +281,8 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
return this.selectedView = { id: 'info', name: 'General Account Info' }
|
return this.selectedView = { id: 'info', name: 'General Account Info' }
|
||||||
} else if (pageId === 'security') {
|
} else if (pageId === 'security') {
|
||||||
return this.selectedView = { id: 'security', name: 'Account Security' }
|
return this.selectedView = { id: 'security', name: 'Account Security' }
|
||||||
|
} else if (pageId === 'export') {
|
||||||
|
return this.selectedView = { id: 'export', name: 'Export Master Keys' }
|
||||||
} else if (pageId === 'notification') {
|
} else if (pageId === 'notification') {
|
||||||
return this.selectedView = { id: 'notification', name: 'UI Notifications' }
|
return this.selectedView = { id: 'notification', name: 'UI Notifications' }
|
||||||
} else if (pageId === 'qr-login') {
|
} else if (pageId === 'qr-login') {
|
||||||
|
@ -17,34 +17,33 @@
|
|||||||
"author": "QORTAL <admin@qortal.org>",
|
"author": "QORTAL <admin@qortal.org>",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lit-labs/motion": "^1.0.3",
|
"@lit-labs/motion": "1.0.3",
|
||||||
"@material/mwc-list": "0.27.0",
|
"@material/mwc-list": "0.27.0",
|
||||||
"@material/mwc-select": "0.27.0",
|
"@material/mwc-select": "0.27.0",
|
||||||
"@tiptap/core": "^2.0.0-beta.209",
|
"@tiptap/core": "2.0.0-beta.209",
|
||||||
"@tiptap/extension-image": "^2.0.0-beta.209",
|
"@tiptap/extension-image": "2.0.0-beta.209",
|
||||||
"@tiptap/extension-placeholder": "^2.0.0-beta.209",
|
"@tiptap/extension-placeholder": "2.0.0-beta.209",
|
||||||
"@tiptap/extension-underline": "^2.0.0-beta.209",
|
"@tiptap/extension-underline": "2.0.0-beta.209",
|
||||||
"@tiptap/html": "^2.0.0-beta.209",
|
"@tiptap/html": "2.0.0-beta.209",
|
||||||
"@tiptap/starter-kit": "^2.0.0-beta.209",
|
"@tiptap/starter-kit": "2.0.0-beta.209",
|
||||||
"asmcrypto.js": "2.3.2",
|
"asmcrypto.js": "2.3.2",
|
||||||
"compressorjs": "^1.1.1",
|
"compressorjs": "1.1.1",
|
||||||
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
|
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
|
||||||
"localforage": "^1.10.0",
|
"prosemirror-commands": "1.5.0",
|
||||||
"prosemirror-commands": "^1.5.0",
|
"prosemirror-dropcursor": "1.6.1",
|
||||||
"prosemirror-dropcursor": "^1.6.1",
|
"prosemirror-gapcursor": "1.3.1",
|
||||||
"prosemirror-gapcursor": "^1.3.1",
|
"prosemirror-history": "1.3.0",
|
||||||
"prosemirror-history": "^1.3.0",
|
"prosemirror-keymap": "1.2.0",
|
||||||
"prosemirror-keymap": "^1.2.0",
|
"prosemirror-model": "1.18.3",
|
||||||
"prosemirror-model": "^1.18.3",
|
"prosemirror-schema-list": "1.2.2",
|
||||||
"prosemirror-schema-list": "^1.2.2",
|
"prosemirror-state": "1.4.2",
|
||||||
"prosemirror-state": "^1.4.2",
|
"prosemirror-transform": "1.7.0",
|
||||||
"prosemirror-transform": "^1.7.0",
|
"prosemirror-view": "1.29.1",
|
||||||
"prosemirror-view": "^1.29.1",
|
"localforage": "1.10.0",
|
||||||
"short-unique-id": "^4.4.4"
|
"short-unique-id": "4.4.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.20.7",
|
"@babel/core": "7.20.12",
|
||||||
"@github/time-elements": "3.1.2",
|
|
||||||
"@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",
|
||||||
@ -68,25 +67,22 @@
|
|||||||
"@rollup/plugin-commonjs": "24.0.0",
|
"@rollup/plugin-commonjs": "24.0.0",
|
||||||
"@rollup/plugin-node-resolve": "15.0.1",
|
"@rollup/plugin-node-resolve": "15.0.1",
|
||||||
"@rollup/plugin-replace": "5.0.2",
|
"@rollup/plugin-replace": "5.0.2",
|
||||||
"@rollup/plugin-terser": "0.2.1",
|
"@rollup/plugin-terser": "0.3.0",
|
||||||
"@vaadin/avatar": "23.3.2",
|
"@vaadin/avatar": "23.3.3",
|
||||||
"@vaadin/button": "23.3.2",
|
"@vaadin/button": "23.3.3",
|
||||||
"@vaadin/grid": "23.3.2",
|
"@vaadin/grid": "23.3.3",
|
||||||
"@vaadin/horizontal-layout": "23.3.2",
|
"@vaadin/icons": "23.3.3",
|
||||||
"@vaadin/icons": "23.3.2",
|
"@vaadin/tooltip": "23.3.3",
|
||||||
"@vaadin/tabs": "23.3.2",
|
|
||||||
"@vaadin/tooltip": "23.3.2",
|
|
||||||
"epml": "0.3.3",
|
"epml": "0.3.3",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"highcharts": "10.3.2",
|
"highcharts": "10.3.2",
|
||||||
"html-escaper": "3.0.3",
|
"html-escaper": "3.0.3",
|
||||||
"lit": "2.5.0",
|
"lit": "2.6.0",
|
||||||
"lit-translate": "2.0.1",
|
"lit-translate": "2.0.1",
|
||||||
"rollup": "3.9.0",
|
"rollup": "3.9.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-terser": "7.0.2",
|
"rollup-plugin-web-worker-loader": "1.6.1"
|
||||||
"rollup-plugin-web-worker-loader": "^1.6.1"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.17.1"
|
"node": ">=16.17.1"
|
||||||
|
@ -113,6 +113,7 @@ class ChatPage extends LitElement {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
height: 50vh;
|
height: 50vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +296,6 @@ class ChatPage extends LitElement {
|
|||||||
|
|
||||||
.chat-container {
|
.chat-container {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-rows: minmax(6%, 92vh) minmax(40px, auto);
|
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,13 +609,6 @@ class ChatPage extends LitElement {
|
|||||||
object-fit: contain;
|
object-fit: contain;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto);
|
|
||||||
max-height: 100%;
|
|
||||||
flex: 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-right-panel {
|
.chat-right-panel {
|
||||||
flex: 0;
|
flex: 0;
|
||||||
border-left: 3px solid rgb(221, 221, 221);
|
border-left: 3px solid rgb(221, 221, 221);
|
||||||
@ -881,13 +874,16 @@ class ChatPage extends LitElement {
|
|||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<div class="chat-container">
|
<div
|
||||||
${(!this.isReceipient && +this._chatId !== 0) ? html`
|
class="chat-container"
|
||||||
|
style=${(!this.isReceipient && +this._chatId !== 0) ? "grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto); flex: 3;" : "grid-template-rows: minmax(6%, 92vh) minmax(40px, auto); flex: 2;"}>
|
||||||
|
${(!this.isReceipient && +this._chatId !== 0) ?
|
||||||
|
html`
|
||||||
<div class="group-nav-container">
|
<div class="group-nav-container">
|
||||||
<div @click=${this._toggle} style="height: 100%;display: flex;align-items: center;flex-grow: 1;cursor: pointer;cursor:pointer;user-select:none">
|
<div @click=${this._toggle} style="height: 100%; display: flex; align-items: center;flex-grow: 1; cursor: pointer; cursor: pointer; user-select: none">
|
||||||
<p class="group-name">${this.groupInfo && this.groupInfo.groupName}</p>
|
<p class="group-name">${this.groupInfo && this.groupInfo.groupName}</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;height:100%;align-items:center">
|
<div style="display: flex; height: 100%; align-items: center">
|
||||||
<vaadin-icon class="top-bar-icon" @click=${this._toggle} style="margin: 0px 10px" icon="vaadin:info" slot="icon"></vaadin-icon>
|
<vaadin-icon class="top-bar-icon" @click=${this._toggle} style="margin: 0px 10px" icon="vaadin:info" slot="icon"></vaadin-icon>
|
||||||
<!-- <chat-group-settings .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-group-settings> -->
|
<!-- <chat-group-settings .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-group-settings> -->
|
||||||
<!-- <vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:search" slot="icon"></vaadin-icon> -->
|
<!-- <vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:search" slot="icon"></vaadin-icon> -->
|
||||||
@ -895,7 +891,7 @@ class ChatPage extends LitElement {
|
|||||||
<!-- <chat-leave-group .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-leave-group> -->
|
<!-- <chat-leave-group .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-leave-group> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
` : html`<div></div>`}
|
` : null}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
${this.isLoadingMessages ?
|
${this.isLoadingMessages ?
|
||||||
@ -1196,8 +1192,16 @@ class ChatPage extends LitElement {
|
|||||||
</wrapper-modal>
|
</wrapper-modal>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-right-panel ${this.shifted ? "movedin" : "movedout"}" ${animate()}>
|
<div class="chat-right-panel ${this.shifted ? "movedin" : "movedout"}" ${animate()}>
|
||||||
<chat-right-panel .getMoreMembers=${(val)=> this.getMoreMembers(val)} .toggle=${(val)=> this._toggle(val)} .selectedAddress=${this.selectedAddress} .groupMembers=${this.groupMembers} .groupAdmin=${this.groupAdmin} .leaveGroupObj=${this.groupInfo}></chat-right-panel>
|
<chat-right-panel
|
||||||
|
.getMoreMembers=${(val)=> this.getMoreMembers(val)}
|
||||||
|
.toggle=${(val)=> this._toggle(val)}
|
||||||
|
.selectedAddress=${this.selectedAddress}
|
||||||
|
.groupMembers=${this.groupMembers}
|
||||||
|
.groupAdmin=${this.groupAdmin}
|
||||||
|
.leaveGroupObj=${this.groupInfo}
|
||||||
|
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
||||||
|
.chatEditor=${this.chatEditor}>
|
||||||
|
</chat-right-panel>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -1525,12 +1529,10 @@ class ChatPage extends LitElement {
|
|||||||
async updated(changedProperties) {
|
async updated(changedProperties) {
|
||||||
if (changedProperties && changedProperties.has('userLanguage')) {
|
if (changedProperties && changedProperties.has('userLanguage')) {
|
||||||
const userLang = changedProperties.get('userLanguage')
|
const userLang = changedProperties.get('userLanguage')
|
||||||
|
if (userLang) {
|
||||||
if(userLang){
|
|
||||||
await new Promise(r => setTimeout(r, 100));
|
await new Promise(r => setTimeout(r, 100));
|
||||||
this.chatEditorPlaceholder = this.isReceipient === true ? `Message ${this._chatId}` : `${get("chatpage.cchange8")}`;
|
this.chatEditorPlaceholder = this.isReceipient === true ? `Message ${this._chatId}` : `${get("chatpage.cchange8")}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedProperties && changedProperties.has('chatId') && changedProperties.get('chatId')) {
|
if (changedProperties && changedProperties.has('chatId') && changedProperties.get('chatId')) {
|
||||||
@ -1541,7 +1543,6 @@ class ChatPage extends LitElement {
|
|||||||
if (this.openForwardOpen === true) {
|
if (this.openForwardOpen === true) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getName (recipient) {
|
async getName (recipient) {
|
||||||
@ -1595,6 +1596,7 @@ async getName (recipient) {
|
|||||||
chatId=${this.chatId}
|
chatId=${this.chatId}
|
||||||
.messages=${this.messagesRendered}
|
.messages=${this.messagesRendered}
|
||||||
.escapeHTML=${escape}
|
.escapeHTML=${escape}
|
||||||
|
.chatEditor=${this.chatEditor}
|
||||||
.getOldMessage=${this.getOldMessage}
|
.getOldMessage=${this.getOldMessage}
|
||||||
.setRepliedToMessageObj=${(val) => this.setRepliedToMessageObj(val)}
|
.setRepliedToMessageObj=${(val) => this.setRepliedToMessageObj(val)}
|
||||||
.setEditedMessageObj=${(val) => this.setEditedMessageObj(val)}
|
.setEditedMessageObj=${(val) => this.setEditedMessageObj(val)}
|
||||||
|
@ -1,51 +1,68 @@
|
|||||||
import { LitElement, html, css } from "lit"
|
import { LitElement, html, css } from "lit";
|
||||||
import { render } from "lit/html.js"
|
import { render } from "lit/html.js";
|
||||||
import { get, translate } from "lit-translate"
|
import { get, translate } from "lit-translate";
|
||||||
import { Epml } from "../../../epml"
|
import { Epml } from "../../../epml";
|
||||||
import snackbar from "./snackbar.js"
|
import { getUserNameFromAddress } from "../../utils/getUserNameFromAddress";
|
||||||
import "@material/mwc-button"
|
import snackbar from "./snackbar.js";
|
||||||
import "@material/mwc-dialog"
|
import "@material/mwc-button";
|
||||||
import "@polymer/paper-spinner/paper-spinner-lite.js"
|
import "@material/mwc-dialog";
|
||||||
import "@material/mwc-icon"
|
import "@polymer/paper-spinner/paper-spinner-lite.js";
|
||||||
import "./WrapperModal"
|
import '@polymer/paper-progress/paper-progress.js';
|
||||||
|
import "@material/mwc-icon";
|
||||||
const parentEpml = new Epml({ type: "WINDOW", source: window.parent })
|
import '@vaadin/button';
|
||||||
|
import "./WrapperModal";
|
||||||
|
import "./TipUser"
|
||||||
|
import "./UserInfo/UserInfo";
|
||||||
|
|
||||||
class ChatRightPanel extends LitElement {
|
class ChatRightPanel extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
isLoading: { type: Boolean },
|
openUserInfo: { type: Boolean },
|
||||||
isOpenLeaveModal: { type: Boolean },
|
|
||||||
leaveGroupObj: { type: Object },
|
leaveGroupObj: { type: Object },
|
||||||
error: { type: Boolean },
|
error: { type: Boolean },
|
||||||
message: { type: String },
|
|
||||||
chatHeads: { type: Array },
|
chatHeads: { type: Array },
|
||||||
groupAdmin: { attribute: false },
|
groupAdmin: { attribute: false },
|
||||||
groupMembers: { attribute: false },
|
groupMembers: { attribute: false },
|
||||||
selectedHead: { type: Object },
|
selectedHead: { type: Object },
|
||||||
toggle: { attribute: false },
|
toggle: { attribute: false },
|
||||||
getMoreMembers:{ attribute: false }
|
getMoreMembers:{ attribute: false },
|
||||||
|
setOpenPrivateMessage: { attribute: false },
|
||||||
|
openTipUser: { type: Boolean },
|
||||||
|
userName: { type: String },
|
||||||
|
chatEditor: { type: Object },
|
||||||
|
walletBalance: { type: Number },
|
||||||
|
sendMoneyLoading: { type: Boolean },
|
||||||
|
btnDisable: { type: Boolean },
|
||||||
|
errorMessage: { type: String },
|
||||||
|
successMessage: { type: String }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.isLoading = false
|
this.openUserInfo = false
|
||||||
this.isOpenLeaveModal = false
|
|
||||||
this.leaveGroupObj = {}
|
this.leaveGroupObj = {}
|
||||||
this.leaveFee = 0.001
|
this.leaveFee = 0.001
|
||||||
this.error = false
|
this.error = false
|
||||||
this.message = ""
|
|
||||||
this.chatHeads = []
|
this.chatHeads = []
|
||||||
this.groupAdmin = []
|
this.groupAdmin = []
|
||||||
this.groupMembers = []
|
this.groupMembers = []
|
||||||
this.observerHandler = this.observerHandler.bind(this)
|
this.observerHandler = this.observerHandler.bind(this)
|
||||||
this.viewElement = ''
|
this.viewElement = ''
|
||||||
this.downObserverElement = ''
|
this.downObserverElement = ''
|
||||||
|
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||||
|
this.openTipUser = false
|
||||||
|
this.userName = ""
|
||||||
|
this.sendMoneyLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
this.errorMessage = ""
|
||||||
|
this.successMessage = ""
|
||||||
|
this.setOpenTipUser = this.setOpenTipUser.bind(this);
|
||||||
|
this.setOpenUserInfo = this.setOpenUserInfo.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return css`
|
||||||
.top-bar-icon {
|
.top-bar-icon {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 18px;
|
height: 18px;
|
||||||
@ -171,8 +188,8 @@ return css`
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: var(--chat-bubble-msg-color);
|
color: var(--chat-bubble-msg-color);
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.viewElement = this.shadowRoot.getElementById('viewElement');
|
this.viewElement = this.shadowRoot.getElementById('viewElement');
|
||||||
@ -180,234 +197,13 @@ return css`
|
|||||||
this.elementObserver();
|
this.elementObserver();
|
||||||
}
|
}
|
||||||
|
|
||||||
timeIsoString(timestamp) {
|
async updated(changedProperties) {
|
||||||
let myTimestamp = timestamp === undefined ? 1587560082346 : timestamp
|
if (changedProperties && changedProperties.has('selectedHead')) {
|
||||||
let time = new Date(myTimestamp)
|
if (this.selectedHead !== {}) {
|
||||||
return time.toISOString()
|
const userName = await getUserNameFromAddress(this.selectedHead.address);
|
||||||
}
|
this.userName = userName;
|
||||||
|
|
||||||
resetDefaultSettings() {
|
|
||||||
this.error = false
|
|
||||||
this.message = ""
|
|
||||||
this.isLoading = false
|
|
||||||
}
|
|
||||||
|
|
||||||
renderErr9Text() {
|
|
||||||
return html`${translate("grouppage.gchange49")}`
|
|
||||||
}
|
|
||||||
|
|
||||||
async confirmRelationship(reference) {
|
|
||||||
let interval = null
|
|
||||||
let stop = false
|
|
||||||
const getAnswer = async () => {
|
|
||||||
|
|
||||||
|
|
||||||
if (!stop) {
|
|
||||||
stop = true
|
|
||||||
try {
|
|
||||||
let myRef = await parentEpml.request("apiCall", {
|
|
||||||
type: "api",
|
|
||||||
url: `/transactions/reference/${reference}`,
|
|
||||||
})
|
|
||||||
if (myRef && myRef.type) {
|
|
||||||
clearInterval(interval)
|
|
||||||
this.isLoading = false
|
|
||||||
this.isOpenLeaveModal = false
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
stop = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interval = setInterval(getAnswer, 5000)
|
|
||||||
}
|
|
||||||
|
|
||||||
async unitFee(txType) {
|
|
||||||
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=${txType}`;
|
|
||||||
let fee = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const res = await fetch(url);
|
|
||||||
const data = await res.json();
|
|
||||||
fee = (Number(data) / 1e8).toFixed(3);
|
|
||||||
} catch (error) {
|
|
||||||
fee = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return fee;
|
|
||||||
}
|
|
||||||
|
|
||||||
async getLastRef() {
|
|
||||||
let myRef = await parentEpml.request("apiCall", {
|
|
||||||
type: "api",
|
|
||||||
url: `/addresses/lastreference/${this.selectedAddress.address}`,
|
|
||||||
})
|
|
||||||
return myRef;
|
|
||||||
}
|
|
||||||
|
|
||||||
getTxnRequestResponse(txnResponse, reference) {
|
|
||||||
if (txnResponse === true) {
|
|
||||||
this.message = this.renderErr9Text()
|
|
||||||
this.error = false
|
|
||||||
this.confirmRelationship(reference)
|
|
||||||
} else {
|
|
||||||
this.error = true
|
|
||||||
this.message = ""
|
|
||||||
throw new Error(txnResponse)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async convertBytesForSigning(transactionBytesBase58) {
|
|
||||||
let convertedBytes = await parentEpml.request("apiCall", {
|
|
||||||
type: "api",
|
|
||||||
method: "POST",
|
|
||||||
url: `/transactions/convert`,
|
|
||||||
body: `${transactionBytesBase58}`,
|
|
||||||
})
|
|
||||||
return convertedBytes
|
|
||||||
}
|
|
||||||
|
|
||||||
async signTx(body){
|
|
||||||
return await parentEpml.request("apiCall", {
|
|
||||||
type: "api",
|
|
||||||
method: "POST",
|
|
||||||
url: `/transactions/sign`,
|
|
||||||
body: body,
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async process(body){
|
|
||||||
return await parentEpml.request("apiCall", {
|
|
||||||
type: "api",
|
|
||||||
method: "POST",
|
|
||||||
url: `/transactions/process`,
|
|
||||||
body: body,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async _addAdmin(groupId) {
|
|
||||||
this.resetDefaultSettings()
|
|
||||||
|
|
||||||
const leaveFeeInput = await this.unitFee('ADD_GROUP_ADMIN')
|
|
||||||
if(!leaveFeeInput){
|
|
||||||
throw Error()
|
|
||||||
}
|
|
||||||
this.isLoading = true
|
|
||||||
|
|
||||||
// Get Last Ref
|
|
||||||
const getLastRef = async () => {
|
|
||||||
let myRef = await parentEpml.request('apiCall', {
|
|
||||||
type: 'api',
|
|
||||||
url: `/addresses/lastreference/${this.selectedAddress.address}`
|
|
||||||
})
|
|
||||||
return myRef
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateReceiver = async () => {
|
|
||||||
let lastRef = await getLastRef();
|
|
||||||
let myTransaction = await makeTransactionRequest(lastRef)
|
|
||||||
getTxnRequestResponse(myTransaction)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make Transaction Request
|
|
||||||
const makeTransactionRequest = async (lastRef) => {
|
|
||||||
let groupdialog3 = get("transactions.groupdialog3")
|
|
||||||
let groupdialog4 = get("transactions.groupdialog4")
|
|
||||||
let myTxnrequest = await parentEpml.request('transaction', {
|
|
||||||
type: 24,
|
|
||||||
nonce: this.selectedAddress.nonce,
|
|
||||||
params: {
|
|
||||||
_groupId: groupId,
|
|
||||||
fee: leaveFeeInput,
|
|
||||||
member: this.selectedHead.address,
|
|
||||||
lastReference: lastRef
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return myTxnrequest
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTxnRequestResponse = (txnResponse) => {
|
|
||||||
|
|
||||||
if (txnResponse.success === false && txnResponse.message) {
|
|
||||||
this.error = true
|
|
||||||
this.message = txnResponse.message
|
|
||||||
throw new Error(txnResponse)
|
|
||||||
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
|
||||||
this.message = this.renderErr9Text()
|
|
||||||
this.error = false
|
|
||||||
this.confirmRelationship()
|
|
||||||
} else {
|
|
||||||
this.error = true
|
|
||||||
this.message = txnResponse.data.message
|
|
||||||
throw new Error(txnResponse)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validateReceiver()
|
|
||||||
}
|
|
||||||
|
|
||||||
async _removeAdmin(groupId) {
|
|
||||||
this.resetDefaultSettings()
|
|
||||||
|
|
||||||
const leaveFeeInput = await this.unitFee('REMOVE_GROUP_ADMIN')
|
|
||||||
if(!leaveFeeInput){
|
|
||||||
throw Error()
|
|
||||||
}
|
|
||||||
this.isLoading = true
|
|
||||||
|
|
||||||
// Get Last Ref
|
|
||||||
const getLastRef = async () => {
|
|
||||||
let myRef = await parentEpml.request('apiCall', {
|
|
||||||
type: 'api',
|
|
||||||
url: `/addresses/lastreference/${this.selectedAddress.address}`
|
|
||||||
})
|
|
||||||
return myRef
|
|
||||||
};
|
|
||||||
|
|
||||||
const validateReceiver = async () => {
|
|
||||||
let lastRef = await getLastRef();
|
|
||||||
let myTransaction = await makeTransactionRequest(lastRef)
|
|
||||||
getTxnRequestResponse(myTransaction)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make Transaction Request
|
|
||||||
const makeTransactionRequest = async (lastRef) => {
|
|
||||||
let groupdialog3 = get("transactions.groupdialog3")
|
|
||||||
let groupdialog4 = get("transactions.groupdialog4")
|
|
||||||
let myTxnrequest = await parentEpml.request('transaction', {
|
|
||||||
type: 25,
|
|
||||||
nonce: this.selectedAddress.nonce,
|
|
||||||
params: {
|
|
||||||
_groupId: groupId,
|
|
||||||
fee: leaveFeeInput,
|
|
||||||
member: this.selectedHead.address,
|
|
||||||
lastReference: lastRef
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return myTxnrequest
|
|
||||||
}
|
|
||||||
|
|
||||||
const getTxnRequestResponse = (txnResponse) => {
|
|
||||||
|
|
||||||
if (txnResponse.success === false && txnResponse.message) {
|
|
||||||
this.error = true
|
|
||||||
this.message = txnResponse.message
|
|
||||||
throw new Error(txnResponse)
|
|
||||||
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
|
||||||
this.message = this.renderErr9Text()
|
|
||||||
this.error = false
|
|
||||||
this.confirmRelationship()
|
|
||||||
} else {
|
|
||||||
this.error = true
|
|
||||||
this.message = txnResponse.data.message
|
|
||||||
throw new Error(txnResponse)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
validateReceiver()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elementObserver() {
|
elementObserver() {
|
||||||
@ -424,6 +220,7 @@ return css`
|
|||||||
// passing it the element to observe, and the options object
|
// passing it the element to observe, and the options object
|
||||||
observer.observe(elementToObserve);
|
observer.observe(elementToObserve);
|
||||||
}
|
}
|
||||||
|
|
||||||
observerHandler(entries) {
|
observerHandler(entries) {
|
||||||
if (!entries[0].isIntersecting) {
|
if (!entries[0].isIntersecting) {
|
||||||
return
|
return
|
||||||
@ -435,9 +232,16 @@ return css`
|
|||||||
this.getMoreMembers(this.leaveGroupObj.groupId)
|
this.getMoreMembers(this.leaveGroupObj.groupId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOpenTipUser(props) {
|
||||||
|
this.openTipUser = props
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpenUserInfo(props) {
|
||||||
|
this.openUserInfo = props
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log('this.groupMembers', this.groupMembers);
|
|
||||||
console.log(5, "Chat Right Panel Here");
|
|
||||||
const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner)
|
const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner)
|
||||||
return html`
|
return html`
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -457,7 +261,12 @@ return css`
|
|||||||
${owner.map((item) => {
|
${owner.map((item) => {
|
||||||
return html`<chat-side-nav-heads
|
return html`<chat-side-nav-heads
|
||||||
activeChatHeadUrl=""
|
activeChatHeadUrl=""
|
||||||
.setActiveChatHeadUrl=${(val) => {}}
|
.setActiveChatHeadUrl=${(val) => {
|
||||||
|
if (val.address === this.myAddress) return;
|
||||||
|
console.log({ val });
|
||||||
|
this.selectedHead = val;
|
||||||
|
this.openUserInfo = true;
|
||||||
|
}}
|
||||||
chatInfo=${JSON.stringify(item)}
|
chatInfo=${JSON.stringify(item)}
|
||||||
></chat-side-nav-heads>`
|
></chat-side-nav-heads>`
|
||||||
})}
|
})}
|
||||||
@ -465,7 +274,12 @@ return css`
|
|||||||
${this.groupAdmin.map((item) => {
|
${this.groupAdmin.map((item) => {
|
||||||
return html`<chat-side-nav-heads
|
return html`<chat-side-nav-heads
|
||||||
activeChatHeadUrl=""
|
activeChatHeadUrl=""
|
||||||
.setActiveChatHeadUrl=${(val) => {}}
|
.setActiveChatHeadUrl=${(val) => {
|
||||||
|
if (val.address === this.myAddress) return;
|
||||||
|
console.log({ val });
|
||||||
|
this.selectedHead = val;
|
||||||
|
this.openUserInfo = true;
|
||||||
|
}}
|
||||||
chatInfo=${JSON.stringify(item)}
|
chatInfo=${JSON.stringify(item)}
|
||||||
></chat-side-nav-heads>`
|
></chat-side-nav-heads>`
|
||||||
})}
|
})}
|
||||||
@ -474,9 +288,10 @@ return css`
|
|||||||
return html`<chat-side-nav-heads
|
return html`<chat-side-nav-heads
|
||||||
activeChatHeadUrl=""
|
activeChatHeadUrl=""
|
||||||
.setActiveChatHeadUrl=${(val) => {
|
.setActiveChatHeadUrl=${(val) => {
|
||||||
console.log({ val })
|
if (val.address === this.myAddress) return;
|
||||||
this.selectedHead = val
|
console.log({ val });
|
||||||
this.isOpenLeaveModal = true
|
this.selectedHead = val;
|
||||||
|
this.openUserInfo = true;
|
||||||
}}
|
}}
|
||||||
chatInfo=${JSON.stringify(item)}
|
chatInfo=${JSON.stringify(item)}
|
||||||
></chat-side-nav-heads>`
|
></chat-side-nav-heads>`
|
||||||
@ -485,56 +300,37 @@ return css`
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<wrapper-modal
|
<wrapper-modal
|
||||||
.removeImage=${() => {
|
.onClickFunc=${() => {
|
||||||
if (this.isLoading) return
|
this.openUserInfo = false;
|
||||||
this.isOpenLeaveModal = false
|
this.userName = "";
|
||||||
|
this.shadowRoot.querySelector("tip-user").shadowRoot.getElementById('amountInput').value = "";
|
||||||
}}
|
}}
|
||||||
style=${
|
style=${
|
||||||
this.isOpenLeaveModal ? "display: block" : "display: none"
|
this.openUserInfo ? "display: block" : "display: none"
|
||||||
}>
|
}>
|
||||||
<div style="text-align:center">
|
<user-info
|
||||||
<h1>${translate("grouppage.gchange35")}</h1>
|
.setOpenUserInfo=${(val) => this.setOpenUserInfo(val)}
|
||||||
<hr>
|
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}
|
||||||
</div>
|
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
||||||
|
.chatEditor=${this.chatEditor}
|
||||||
<button @click=${() =>
|
.userName=${this.userName}
|
||||||
this._addAdmin(
|
.selectedHead=${this.selectedHead}
|
||||||
this.leaveGroupObj.groupId
|
></user-info>
|
||||||
)}>Promote to Admin</button>
|
</wrapper-modal>
|
||||||
<button @click=${() =>
|
<wrapper-modal
|
||||||
this._removeAdmin(
|
.onClickFunc=${() => {
|
||||||
this.leaveGroupObj.groupId
|
this.openTipUser = false;
|
||||||
)}>Remove as Admin</button>
|
this.chatEditor.enable();
|
||||||
<div style="text-align:right; height:36px;">
|
|
||||||
<span ?hidden="${!this.isLoading}">
|
|
||||||
<!-- loading message -->
|
|
||||||
${translate("grouppage.gchange36")}
|
|
||||||
<paper-spinner-lite
|
|
||||||
style="margin-top:12px;"
|
|
||||||
?active="${this.isLoading}"
|
|
||||||
alt="Leaving"
|
|
||||||
>
|
|
||||||
</paper-spinner-lite>
|
|
||||||
</span>
|
|
||||||
<span ?hidden=${this.message === ""} style="${
|
|
||||||
this.error ? "color:red;" : ""
|
|
||||||
}">
|
|
||||||
${this.message}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<button
|
|
||||||
@click=${() => {
|
|
||||||
this.isOpenLeaveModal = false
|
|
||||||
}}
|
}}
|
||||||
class="modal-button"
|
style=${this.openTipUser ? "display: block" : "display: none"}>
|
||||||
?disabled="${this.isLoading}"
|
<tip-user
|
||||||
|
.closeTipUser=${this.openUserInfo}
|
||||||
|
.chatEditor=${this.chatEditor}
|
||||||
|
.userName=${this.userName}
|
||||||
|
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}
|
||||||
>
|
>
|
||||||
${translate("general.close")}
|
</tip-user>
|
||||||
</button>
|
</wrapper-modal>
|
||||||
</wrapper-modal >
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -63,12 +63,19 @@ export const chatStyles = css`
|
|||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.forwarded-text {
|
||||||
|
user-select: none;
|
||||||
|
color: #03a9f4;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
.message-data-forward {
|
.message-data-forward {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
color: var(--mainmenutext);
|
color: var(--mainmenutext);
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.message-data-my-name {
|
.message-data-my-name {
|
||||||
color: #cf21e8;
|
color: #cf21e8;
|
||||||
text-shadow: 0 0 3px #cf21e8;
|
text-shadow: 0 0 3px #cf21e8;
|
||||||
|
@ -5,9 +5,14 @@ import { translate, get } from 'lit-translate';
|
|||||||
import {unsafeHTML} from 'lit/directives/unsafe-html.js';
|
import {unsafeHTML} from 'lit/directives/unsafe-html.js';
|
||||||
import { chatStyles } from './ChatScroller-css.js'
|
import { chatStyles } from './ChatScroller-css.js'
|
||||||
import { Epml } from "../../../epml";
|
import { Epml } from "../../../epml";
|
||||||
|
import { EmojiPicker } from 'emoji-picker-js';
|
||||||
|
import { cropAddress } from "../../utils/cropAddress";
|
||||||
import './LevelFounder.js';
|
import './LevelFounder.js';
|
||||||
import './NameMenu.js';
|
import './NameMenu.js';
|
||||||
import './ChatModals.js';
|
import './ChatModals.js';
|
||||||
|
import './WrapperModal';
|
||||||
|
import './TipUser'
|
||||||
|
import "./UserInfo/UserInfo";
|
||||||
import '@vaadin/icons';
|
import '@vaadin/icons';
|
||||||
import '@vaadin/icon';
|
import '@vaadin/icon';
|
||||||
import '@material/mwc-button';
|
import '@material/mwc-button';
|
||||||
@ -29,17 +34,23 @@ class ChatScroller extends LitElement {
|
|||||||
escapeHTML: { attribute: false },
|
escapeHTML: { attribute: false },
|
||||||
messages: { type: Array },
|
messages: { type: Array },
|
||||||
hideMessages: { type: Array },
|
hideMessages: { type: Array },
|
||||||
setRepliedToMessageObj: {attribute: false},
|
setRepliedToMessageObj: { attribute: false },
|
||||||
setEditedMessageObj: {attribute: false},
|
setEditedMessageObj: { attribute: false },
|
||||||
sendMessage: {attribute: false},
|
focusChatEditor: { attribute: false },
|
||||||
sendMessageForward: {attribute: false},
|
sendMessage: { attribute: false },
|
||||||
showLastMessageRefScroller: { type: Function },
|
sendMessageForward: { attribute: false },
|
||||||
|
showLastMessageRefScroller: { attribute: false },
|
||||||
emojiPicker: { attribute: false },
|
emojiPicker: { attribute: false },
|
||||||
isLoadingMessages: { type: Boolean},
|
isLoadingMessages: { type: Boolean},
|
||||||
setIsLoadingMessages: {attribute: false},
|
setIsLoadingMessages: { attribute: false },
|
||||||
chatId: { type: String },
|
chatId: { type: String },
|
||||||
|
chatEditor: { type: Object },
|
||||||
setForwardProperties: { attribute: false },
|
setForwardProperties: { attribute: false },
|
||||||
setOpenPrivateMessage: { attribute: false },
|
setOpenPrivateMessage: { attribute: false },
|
||||||
|
openTipUser: { type: Boolean },
|
||||||
|
openUserInfo: { type: Boolean },
|
||||||
|
userName: { type: String },
|
||||||
|
selectedHead: { type: Object }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,13 +61,19 @@ class ChatScroller extends LitElement {
|
|||||||
this.messages = []
|
this.messages = []
|
||||||
this._upObserverhandler = this._upObserverhandler.bind(this)
|
this._upObserverhandler = this._upObserverhandler.bind(this)
|
||||||
this._downObserverHandler = this._downObserverHandler.bind(this)
|
this._downObserverHandler = this._downObserverHandler.bind(this)
|
||||||
|
this.setOpenTipUser = this.setOpenTipUser.bind(this)
|
||||||
|
this.setOpenUserInfo = this.setOpenUserInfo.bind(this)
|
||||||
|
this.setUserName = this.setUserName.bind(this)
|
||||||
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
|
||||||
this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]")
|
this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]")
|
||||||
|
this.openTipUser = false;
|
||||||
|
this.openUserInfo = false;
|
||||||
|
this.userName = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log('this.messages', this.messages)
|
console.log('this.messages', this.messages)
|
||||||
|
console.log(9, "chat scroller here");
|
||||||
let formattedMessages = this.messages.reduce((messageArray, message, index) => {
|
let formattedMessages = this.messages.reduce((messageArray, message, index) => {
|
||||||
const lastGroupedMessage = messageArray[messageArray.length - 1];
|
const lastGroupedMessage = messageArray[messageArray.length - 1];
|
||||||
let timestamp;
|
let timestamp;
|
||||||
@ -119,12 +136,47 @@ class ChatScroller extends LitElement {
|
|||||||
.setToggledMessage=${this.setToggledMessage}
|
.setToggledMessage=${this.setToggledMessage}
|
||||||
.setForwardProperties=${this.setForwardProperties}
|
.setForwardProperties=${this.setForwardProperties}
|
||||||
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
||||||
>
|
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}
|
||||||
|
.setOpenUserInfo=${(val) => this.setOpenUserInfo(val)}
|
||||||
|
.setUserName=${(val) => this.setUserName(val)}>
|
||||||
</message-template>`
|
</message-template>`
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
<div id='downObserver'></div>
|
<div id='downObserver'></div>
|
||||||
</ul>
|
</ul>
|
||||||
|
<wrapper-modal
|
||||||
|
.onClickFunc=${() => {
|
||||||
|
this.openTipUser = false;
|
||||||
|
this.chatEditor.enable();
|
||||||
|
}}
|
||||||
|
style=${this.openTipUser ? "display: block;" : "display: none;"}>
|
||||||
|
<tip-user
|
||||||
|
.closeTipUser=${!this.openTipUser}
|
||||||
|
.chatEditor=${this.chatEditor}
|
||||||
|
.focusChatEditor=${this.focusChatEditor}
|
||||||
|
.userName=${this.userName}
|
||||||
|
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}>
|
||||||
|
</tip-user>
|
||||||
|
</wrapper-modal>
|
||||||
|
<wrapper-modal
|
||||||
|
.onClickFunc=${() => {
|
||||||
|
this.openUserInfo = false;
|
||||||
|
this.chatEditor.enable();
|
||||||
|
this.userName = "";
|
||||||
|
this.selectedHead = {};
|
||||||
|
}}
|
||||||
|
style=${
|
||||||
|
this.openUserInfo ? "display: block" : "display: none"
|
||||||
|
}>
|
||||||
|
<user-info
|
||||||
|
.setOpenUserInfo=${(val) => this.setOpenUserInfo(val)}
|
||||||
|
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}
|
||||||
|
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
||||||
|
.chatEditor=${this.chatEditor}
|
||||||
|
.userName=${this.userName}
|
||||||
|
.selectedHead=${this.selectedHead}
|
||||||
|
></user-info>
|
||||||
|
</wrapper-modal>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +187,12 @@ class ChatScroller extends LitElement {
|
|||||||
if(changedProperties.has('chatId') && changedProperties.get('chatId')){
|
if(changedProperties.has('chatId') && changedProperties.get('chatId')){
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if(changedProperties.has('openTipUser')){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if(changedProperties.has('openUserInfo')){
|
||||||
|
return true
|
||||||
|
}
|
||||||
// Only update element if prop1 changed.
|
// Only update element if prop1 changed.
|
||||||
return changedProperties.has('messages');
|
return changedProperties.has('messages');
|
||||||
}
|
}
|
||||||
@ -150,6 +208,25 @@ class ChatScroller extends LitElement {
|
|||||||
toggledMessage = message;
|
toggledMessage = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setOpenTipUser(props) {
|
||||||
|
this.openTipUser = props;
|
||||||
|
this.chatEditor.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpenUserInfo(props) {
|
||||||
|
this.openUserInfo = props;
|
||||||
|
this.chatEditor.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
setUserName(props) {
|
||||||
|
this.userName = props.senderName ? props.senderName : props.sender;
|
||||||
|
this.selectedHead = {
|
||||||
|
...this.selectedHead,
|
||||||
|
address: props.sender,
|
||||||
|
name: props.senderName,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async firstUpdated() {
|
async firstUpdated() {
|
||||||
this.emojiPicker.on('emoji', selection => {
|
this.emojiPicker.on('emoji', selection => {
|
||||||
|
|
||||||
@ -241,10 +318,13 @@ class MessageTemplate extends LitElement {
|
|||||||
isFirstMessage: { type: Boolean },
|
isFirstMessage: { type: Boolean },
|
||||||
isSingleMessageInGroup: { type: Boolean },
|
isSingleMessageInGroup: { type: Boolean },
|
||||||
isLastMessageInGroup: { type: Boolean },
|
isLastMessageInGroup: { type: Boolean },
|
||||||
setToggledMessage: {attribute: false},
|
setToggledMessage: { attribute: false },
|
||||||
setForwardProperties: {attribute: false},
|
setForwardProperties: { attribute: false },
|
||||||
viewImage: {type: Boolean},
|
viewImage: { type: Boolean },
|
||||||
setOpenPrivateMessage : { attribute: false }
|
setOpenPrivateMessage : { attribute: false },
|
||||||
|
setOpenTipUser: { attribute: false },
|
||||||
|
setOpenUserInfo: { attribute: false },
|
||||||
|
setUserName: { attribute: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -423,7 +503,13 @@ class MessageTemplate extends LitElement {
|
|||||||
(this.isSingleMessageInGroup === true && this.isLastMessageInGroup === true))
|
(this.isSingleMessageInGroup === true && this.isLastMessageInGroup === true))
|
||||||
? (
|
? (
|
||||||
html`
|
html`
|
||||||
<div class="message-data-avatar">
|
<div
|
||||||
|
style=${this.myAddress === this.messageObj.sender ? "cursor: auto;" : "cursor: pointer;"}
|
||||||
|
@click=${() => {
|
||||||
|
if (this.myAddress === this.messageObj.sender) return;
|
||||||
|
this.setOpenUserInfo(true);
|
||||||
|
this.setUserName(this.messageObj);
|
||||||
|
}} class="message-data-avatar">
|
||||||
${avatarImg}
|
${avatarImg}
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
@ -450,7 +536,14 @@ class MessageTemplate extends LitElement {
|
|||||||
<div class="message-user-info">
|
<div class="message-user-info">
|
||||||
${this.isFirstMessage ?
|
${this.isFirstMessage ?
|
||||||
html`
|
html`
|
||||||
<span class="message-data-name">
|
<span
|
||||||
|
style=${this.myAddress === this.messageObj.sender ? "cursor: auto;" : "cursor: pointer;"}
|
||||||
|
@click=${() => {
|
||||||
|
if (this.myAddress === this.messageObj.sender) return;
|
||||||
|
this.setOpenUserInfo(true);
|
||||||
|
this.setUserName(this.messageObj);
|
||||||
|
}}
|
||||||
|
class="message-data-name">
|
||||||
${nameMenu}
|
${nameMenu}
|
||||||
</span>
|
</span>
|
||||||
`
|
`
|
||||||
@ -458,7 +551,7 @@ class MessageTemplate extends LitElement {
|
|||||||
}
|
}
|
||||||
${isForwarded ?
|
${isForwarded ?
|
||||||
html`
|
html`
|
||||||
<span class="message-data-name">
|
<span class="forwarded-text">
|
||||||
${forwarded}
|
${forwarded}
|
||||||
</span>
|
</span>
|
||||||
`
|
`
|
||||||
@ -472,7 +565,14 @@ class MessageTemplate extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
${repliedToData && html`
|
${repliedToData && html`
|
||||||
<div class="original-message">
|
<div class="original-message">
|
||||||
<p class="original-message-sender">
|
<p
|
||||||
|
style=${this.myAddress === repliedToData.sender ? "cursor: auto;" : "cursor: pointer;"}
|
||||||
|
@click=${() => {
|
||||||
|
if (this.myAddress === repliedToData.sender) return;
|
||||||
|
this.setOpenUserInfo(true);
|
||||||
|
this.setUserName(repliedToData)
|
||||||
|
}}
|
||||||
|
class="original-message-sender">
|
||||||
${repliedToData.senderName ?? cropAddress(repliedToData.sender)}
|
${repliedToData.senderName ?? cropAddress(repliedToData.sender)}
|
||||||
</p>
|
</p>
|
||||||
<p class="replied-message">
|
<p class="replied-message">
|
||||||
@ -553,6 +653,8 @@ class MessageTemplate extends LitElement {
|
|||||||
.setForwardProperties=${this.setForwardProperties}
|
.setForwardProperties=${this.setForwardProperties}
|
||||||
?firstMessageInChat=${this.messageObj.firstMessageInChat}
|
?firstMessageInChat=${this.messageObj.firstMessageInChat}
|
||||||
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
|
||||||
|
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}
|
||||||
|
.setUserName=${(val) => this.setUserName(val)}
|
||||||
>
|
>
|
||||||
</chat-menu>
|
</chat-menu>
|
||||||
</div>
|
</div>
|
||||||
@ -657,7 +759,9 @@ class ChatMenu extends LitElement {
|
|||||||
sendMessageForward: { attribute: false },
|
sendMessageForward: { attribute: false },
|
||||||
setForwardProperties: { attribute: false },
|
setForwardProperties: { attribute: false },
|
||||||
firstMessageInChat: { type: Boolean },
|
firstMessageInChat: { type: Boolean },
|
||||||
setOpenPrivateMessage: { attribute: false }
|
setOpenPrivateMessage: { attribute: false },
|
||||||
|
setOpenTipUser: { attribute: false },
|
||||||
|
setUserName: { attribute: false },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -801,6 +905,19 @@ class ChatMenu extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
) : html`<div></div>`}
|
) : html`<div></div>`}
|
||||||
|
${this.myAddress !== this.originalMessage.sender ? (
|
||||||
|
html`
|
||||||
|
<div
|
||||||
|
class=${`menu-icon ${!this.firstMessageInChat ? "tooltip" : ""}`}
|
||||||
|
data-text="${translate("blockpage.bcchange18")}"
|
||||||
|
@click=${() => {
|
||||||
|
this.setOpenTipUser(true);
|
||||||
|
this.setUserName(this.originalMessage);
|
||||||
|
}}>
|
||||||
|
<vaadin-icon icon="vaadin:dollar" slot="icon"></vaadin-icon>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
) : html`<div></div>`}
|
||||||
<div class=${`menu-icon ${!this.firstMessageInChat ? "tooltip" : ""}`} data-text="${translate("blockpage.bcchange10")}" @click="${() => this.showBlockIconFunc(true)}">
|
<div class=${`menu-icon ${!this.firstMessageInChat ? "tooltip" : ""}`} data-text="${translate("blockpage.bcchange10")}" @click="${() => this.showBlockIconFunc(true)}">
|
||||||
<vaadin-icon icon="vaadin:ellipsis-dots-h" slot="icon"></vaadin-icon>
|
<vaadin-icon icon="vaadin:ellipsis-dots-h" slot="icon"></vaadin-icon>
|
||||||
</div>
|
</div>
|
||||||
|
@ -101,8 +101,6 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
imageHTMLRes.src = imageUrl;
|
imageHTMLRes.src = imageUrl;
|
||||||
}, 500);
|
}, 500);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
||||||
this.isImageLoaded = false
|
this.isImageLoaded = false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -110,24 +108,53 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let avatarImg = '';
|
let avatarImg = ""
|
||||||
let backupAvatarImg = ''
|
if (this.chatInfo.name) {
|
||||||
if(this.chatInfo.name){
|
|
||||||
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;
|
||||||
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`;
|
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`;
|
||||||
avatarImg= this.createImage(avatarUrl)
|
avatarImg = this.createImage(avatarUrl)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<li @click=${() => this.getUrl(this.chatInfo)} class="clearfix">
|
<li @click=${() => this.getUrl(this.chatInfo)} class="clearfix">
|
||||||
${this.isImageLoaded ? html`${avatarImg}` : html`` }
|
${this.isImageLoaded ? html`${avatarImg}` : html``}
|
||||||
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? html`<mwc-icon class="img-icon">account_circle</mwc-icon>` : html`` }
|
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName
|
||||||
${!this.isImageLoaded && this.chatInfo.name ? html`<div style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadBgActive)' : 'var(--chatHeadBg)' }; color: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadTextActive)' : 'var(--chatHeadText)' }; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize">${this.chatInfo.name.charAt(0)}</div>`: ''}
|
? html`<mwc-icon class="img-icon">account_circle</mwc-icon>`
|
||||||
${!this.isImageLoaded && this.chatInfo.groupName ? html`<div style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadBgActive)' : 'var(--chatHeadBg)' }; color: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadTextActive)' : 'var(--chatHeadText)' }; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize">${this.chatInfo.groupName.charAt(0)}</div>`: ''}
|
: html``}
|
||||||
|
${!this.isImageLoaded && this.chatInfo.name
|
||||||
|
? html`<div
|
||||||
|
style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
|
? "var(--chatHeadBgActive)"
|
||||||
|
: "var(--chatHeadBg)"}; color: ${this.activeChatHeadUrl ===
|
||||||
|
this.chatInfo.url
|
||||||
|
? "var(--chatHeadTextActive)"
|
||||||
|
: "var(--chatHeadText)"}; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize"
|
||||||
|
>
|
||||||
|
${this.chatInfo.name.charAt(0)}
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
|
${!this.isImageLoaded && this.chatInfo.groupName
|
||||||
|
? html`<div
|
||||||
|
style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
|
? "var(--chatHeadBgActive)"
|
||||||
|
: "var(--chatHeadBg)"}; color: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
|
? "var(--chatHeadTextActive)"
|
||||||
|
: "var(--chatHeadText)"}; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize"
|
||||||
|
>
|
||||||
|
${this.chatInfo.groupName.charAt(0)}
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
<div>
|
<div>
|
||||||
<div class="name"><span style="float:left; padding-left: 8px; color: var(--chat-group);">${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} </span> </div>
|
<div class="name">
|
||||||
|
<span style="float:left; padding-left: 8px; color: var(--chat-group);">
|
||||||
|
${this.chatInfo.groupName
|
||||||
|
? this.chatInfo.groupName
|
||||||
|
: this.chatInfo.name !== undefined
|
||||||
|
? this.chatInfo.name
|
||||||
|
: this.chatInfo.address.substr(0, 15)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
`
|
`
|
||||||
@ -149,9 +176,7 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
this.config = JSON.parse(c)
|
this.config = JSON.parse(c)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
parentEpml.imReady()
|
parentEpml.imReady();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldUpdate(changedProperties) {
|
shouldUpdate(changedProperties) {
|
||||||
@ -161,6 +186,9 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
if(changedProperties.has('chatInfo')){
|
if(changedProperties.has('chatInfo')){
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if(changedProperties.has('isImageLoaded')){
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { LitElement, html, css } from 'lit'
|
import { LitElement, html, css } from 'lit'
|
||||||
|
|
||||||
import '@github/time-elements'
|
import './time-elements/index.js'
|
||||||
|
|
||||||
class TimeAgo extends LitElement {
|
class TimeAgo extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
|
85
qortal-ui-plugins/plugins/core/components/TipUser-css.js
Normal file
85
qortal-ui-plugins/plugins/core/components/TipUser-css.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { css } from 'lit'
|
||||||
|
|
||||||
|
export const tipUserStyles = css`
|
||||||
|
.tip-user-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 12px;
|
||||||
|
border-bottom: 1px solid whitesmoke;
|
||||||
|
gap: 25px;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-user-header-font {
|
||||||
|
font-family: Montserrat, sans-serif;
|
||||||
|
font-size: 20px;
|
||||||
|
color: var(--chat-bubble-msg-color);
|
||||||
|
margin: 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-user-body {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
padding: 20px 10px;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-input {
|
||||||
|
width: 300px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
outline: 0;
|
||||||
|
border-width: 0 0 2px;
|
||||||
|
border-color: var(--mdc-theme-primary);
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 10px;
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
font-size: 15px;
|
||||||
|
color: var(--chat-bubble-msg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-input::selection {
|
||||||
|
background-color: var(--mdc-theme-primary);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-input::placeholder {
|
||||||
|
opacity: 0.9;
|
||||||
|
color: var(--black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-available {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
font-size: 17px;
|
||||||
|
color: var(--chat-bubble-msg-color);
|
||||||
|
font-weight: 300;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
margin: 0;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.success-msg {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
margin: 0;
|
||||||
|
user-select: none;
|
||||||
|
color: #10880b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-msg {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 400;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
margin: 0;
|
||||||
|
user-select: none;
|
||||||
|
color: #f30000;
|
||||||
|
}
|
||||||
|
`
|
282
qortal-ui-plugins/plugins/core/components/TipUser.js
Normal file
282
qortal-ui-plugins/plugins/core/components/TipUser.js
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
import { LitElement, html } from 'lit';
|
||||||
|
import { render } from 'lit/html.js';
|
||||||
|
import { get, translate } from 'lit-translate';
|
||||||
|
import { tipUserStyles } from './TipUser-css.js';
|
||||||
|
import { Epml } from '../../../epml';
|
||||||
|
import '@vaadin/button';
|
||||||
|
import '@polymer/paper-progress/paper-progress.js';
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: "WINDOW", source: window.parent });
|
||||||
|
|
||||||
|
export class TipUser extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
userName: { type: String },
|
||||||
|
chatEditor: { type: Object },
|
||||||
|
walletBalance: { type: Number },
|
||||||
|
sendMoneyLoading: { type: Boolean },
|
||||||
|
closeTipUser: { type: Boolean },
|
||||||
|
btnDisable: { type: Boolean },
|
||||||
|
errorMessage: { type: String },
|
||||||
|
successMessage: { type: String },
|
||||||
|
setOpenTipUser: { attribute: false },
|
||||||
|
focusChatEditor: { attribute: false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.sendMoneyLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
this.errorMessage = ""
|
||||||
|
this.successMessage = ""
|
||||||
|
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [tipUserStyles]
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
await this.fetchWalletDetails();
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changedProperties) {
|
||||||
|
if (changedProperties && changedProperties.has("closeTipUser")) {
|
||||||
|
if (this.closeTipUser) {
|
||||||
|
this.shadowRoot.getElementById("amountInput").value = "";
|
||||||
|
this.errorMessage = "";
|
||||||
|
this.successMessage = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLastRef() {
|
||||||
|
let myRef = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
url: `/addresses/lastreference/${this.myAddress.address}`,
|
||||||
|
})
|
||||||
|
return myRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderSuccessText() {
|
||||||
|
return html`${translate("chatpage.cchange55")}`
|
||||||
|
}
|
||||||
|
|
||||||
|
renderReceiverText() {
|
||||||
|
return html`${translate("chatpage.cchange54")}`
|
||||||
|
}
|
||||||
|
|
||||||
|
getApiKey() {
|
||||||
|
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
|
||||||
|
let apiKey = myNode.apiKey;
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchWalletDetails() {
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`,
|
||||||
|
})
|
||||||
|
.then((res) => {
|
||||||
|
if (isNaN(Number(res))) {
|
||||||
|
let snack4string = get("chatpage.cchange48")
|
||||||
|
parentEpml.request('showSnackBar', `${snack4string}`)
|
||||||
|
} else {
|
||||||
|
this.walletBalance = Number(res).toFixed(8);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendQort() {
|
||||||
|
const amount = this.shadowRoot.getElementById("amountInput").value;
|
||||||
|
let recipient = this.userName;
|
||||||
|
this.sendMoneyLoading = true;
|
||||||
|
this.btnDisable = true;
|
||||||
|
|
||||||
|
if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.walletBalance)) {
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
let snack1string = get("chatpage.cchange51");
|
||||||
|
parentEpml.request('showSnackBar', `${snack1string}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parseFloat(amount) <= 0) {
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
let snack2string = get("chatpage.cchange52");
|
||||||
|
parentEpml.request('showSnackBar', `${snack2string}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recipient.length === 0) {
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
let snack3string = get("chatpage.cchange53");
|
||||||
|
parentEpml.request('showSnackBar', `${snack3string}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateName = async (receiverName) => {
|
||||||
|
let myRes;
|
||||||
|
let myNameRes = await parentEpml.request('apiCall', {
|
||||||
|
type: 'api',
|
||||||
|
url: `/names/${receiverName}`,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (myNameRes.error === 401) {
|
||||||
|
myRes = false;
|
||||||
|
} else {
|
||||||
|
myRes = myNameRes;
|
||||||
|
}
|
||||||
|
return myRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateAddress = async (receiverAddress) => {
|
||||||
|
let myAddress = await window.parent.validateAddress(receiverAddress);
|
||||||
|
return myAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateReceiver = async (recipient) => {
|
||||||
|
let lastRef = await this.getLastRef();
|
||||||
|
let isAddress;
|
||||||
|
|
||||||
|
try {
|
||||||
|
isAddress = await validateAddress(recipient);
|
||||||
|
} catch (err) {
|
||||||
|
isAddress = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAddress) {
|
||||||
|
let myTransaction = await makeTransactionRequest(recipient, lastRef);
|
||||||
|
getTxnRequestResponse(myTransaction);
|
||||||
|
} else {
|
||||||
|
let myNameRes = await validateName(recipient);
|
||||||
|
if (myNameRes !== false) {
|
||||||
|
let myNameAddress = myNameRes.owner
|
||||||
|
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
|
||||||
|
getTxnRequestResponse(myTransaction)
|
||||||
|
} else {
|
||||||
|
console.error(this.renderReceiverText())
|
||||||
|
this.errorMessage = this.renderReceiverText();
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const getName = async (recipient)=> {
|
||||||
|
try {
|
||||||
|
const getNames = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
url: `/names/address/${recipient}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (getNames?.length > 0 ) {
|
||||||
|
return getNames[0].name;
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeTransactionRequest = async (receiver, lastRef) => {
|
||||||
|
let myReceiver = receiver;
|
||||||
|
let mylastRef = lastRef;
|
||||||
|
let dialogamount = get("transactions.amount");
|
||||||
|
let dialogAddress = get("login.address");
|
||||||
|
let dialogName = get("login.name");
|
||||||
|
let dialogto = get("transactions.to");
|
||||||
|
let recipientName = await getName(myReceiver);
|
||||||
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
|
type: 2,
|
||||||
|
nonce: this.myAddress.nonce,
|
||||||
|
params: {
|
||||||
|
recipient: myReceiver,
|
||||||
|
recipientName: recipientName,
|
||||||
|
amount: amount,
|
||||||
|
lastReference: mylastRef,
|
||||||
|
fee: 0.001,
|
||||||
|
dialogamount: dialogamount,
|
||||||
|
dialogto: dialogto,
|
||||||
|
dialogAddress,
|
||||||
|
dialogName
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return myTxnrequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
|
if (txnResponse.success === false && txnResponse.message) {
|
||||||
|
this.errorMessage = txnResponse.message;
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
throw new Error(txnResponse);
|
||||||
|
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
||||||
|
this.shadowRoot.getElementById('amountInput').value = '';
|
||||||
|
this.userName = '';
|
||||||
|
this.errorMessage = '';
|
||||||
|
this.successMessage = this.renderSuccessText();
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setOpenTipUser(false);
|
||||||
|
this.chatEditor.enable();
|
||||||
|
this.focusChatEditor();
|
||||||
|
this.successMessage = "";
|
||||||
|
}, 3000);
|
||||||
|
} else {
|
||||||
|
this.errorMessage = txnResponse.data.message;
|
||||||
|
this.sendMoneyLoading = false;
|
||||||
|
this.btnDisable = false;
|
||||||
|
throw new Error(txnResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateReceiver(recipient);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div class="tip-user-header">
|
||||||
|
<img src="/img/qort.png" width="32" height="32">
|
||||||
|
<p class="tip-user-header-font">${translate("chatpage.cchange43")} ${this.userName}</p>
|
||||||
|
</div>
|
||||||
|
<div class="tip-user-body">
|
||||||
|
<p class="tip-available">${translate("chatpage.cchange47")}: ${this.walletBalance} QORT</p>
|
||||||
|
<input id="amountInput" class="tip-input" type="number" placeholder="${translate("chatpage.cchange46")}" />
|
||||||
|
<p class="tip-available">${translate("chatpage.cchange49")}: 0.001 QORT</p>
|
||||||
|
${this.sendMoneyLoading ?
|
||||||
|
html`
|
||||||
|
<paper-progress indeterminate style="width: 100%; margin: 4px;">
|
||||||
|
</paper-progress>`
|
||||||
|
: html`
|
||||||
|
<div style=${"text-align: center;"}>
|
||||||
|
<vaadin-button
|
||||||
|
?disabled=${this.btnDisable}
|
||||||
|
theme="primary medium"
|
||||||
|
style="width: 100%; cursor: pointer"
|
||||||
|
@click=${() => this.sendQort()}>
|
||||||
|
<vaadin-icon icon="vaadin:arrow-forward" slot="prefix"></vaadin-icon>
|
||||||
|
${translate("chatpage.cchange50")} QORT
|
||||||
|
</vaadin-button>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
|
||||||
|
${this.successMessage ?
|
||||||
|
html`
|
||||||
|
<p class="success-msg">
|
||||||
|
${this.successMessage}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: this.errorMessage ?
|
||||||
|
html`
|
||||||
|
<p class="error-msg">
|
||||||
|
${this.errorMessage}
|
||||||
|
</p>
|
||||||
|
`
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define('tip-user', TipUser);
|
@ -0,0 +1,69 @@
|
|||||||
|
import { css } from 'lit'
|
||||||
|
|
||||||
|
export const userInfoStyles = css`
|
||||||
|
.user-info-header {
|
||||||
|
font-family: Montserrat, sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 28px;
|
||||||
|
color: var(--chat-bubble-msg-color);
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding: 10px 0;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info-avatar {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.user-info-no-avatar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 50px;
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
border-radius:50%;
|
||||||
|
background: var(--chatHeadBg);
|
||||||
|
color: var(--chatHeadText);
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-message-button {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 8px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--mdc-theme-primary);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.send-message-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #03a8f485;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 3px;
|
||||||
|
right: 5px;
|
||||||
|
color: #676b71;
|
||||||
|
width: 14px;
|
||||||
|
transition: all 0.1s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.close-icon:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #494c50;
|
||||||
|
}
|
||||||
|
`
|
134
qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo.js
Normal file
134
qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo.js
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
import { LitElement, html } from 'lit';
|
||||||
|
import { render } from 'lit/html.js';
|
||||||
|
import { translate } from 'lit-translate';
|
||||||
|
import { userInfoStyles } from './UserInfo-css.js';
|
||||||
|
import { Epml } from '../../../../epml';
|
||||||
|
import '@vaadin/button';
|
||||||
|
import '@polymer/paper-progress/paper-progress.js';
|
||||||
|
import { cropAddress } from '../../../utils/cropAddress.js';
|
||||||
|
|
||||||
|
// const parentEpml = new Epml({ type: "WINDOW", source: window.parent });
|
||||||
|
|
||||||
|
export class UserInfo extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
setOpenUserInfo: { attribute: false },
|
||||||
|
setOpenTipUser: { attribute: false },
|
||||||
|
setOpenPrivateMessage: { attribute: false },
|
||||||
|
chatEditor: { type: Object },
|
||||||
|
userName: { type: String },
|
||||||
|
selectedHead: { type: Object },
|
||||||
|
isImageLoaded: { type: Boolean }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.isImageLoaded = false
|
||||||
|
this.selectedHead = {}
|
||||||
|
this.imageFetches = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
static styles = [userInfoStyles]
|
||||||
|
|
||||||
|
createImage(imageUrl) {
|
||||||
|
const imageHTMLRes = new Image();
|
||||||
|
imageHTMLRes.src = imageUrl;
|
||||||
|
imageHTMLRes.classList.add("user-info-avatar");
|
||||||
|
// imageHTMLRes.style= "width:30px; height:30px; float: left; border-radius:50%; font-size:14px";
|
||||||
|
imageHTMLRes.onload = () => {
|
||||||
|
this.isImageLoaded = true;
|
||||||
|
}
|
||||||
|
imageHTMLRes.onerror = () => {
|
||||||
|
if (this.imageFetches < 4) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.imageFetches = this.imageFetches + 1;
|
||||||
|
imageHTMLRes.src = imageUrl;
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
this.isImageLoaded = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return imageHTMLRes;
|
||||||
|
}
|
||||||
|
|
||||||
|
updated(changedProperties) {
|
||||||
|
if (changedProperties && changedProperties.has('selectedHead')) {
|
||||||
|
if (this.selectedHead) {
|
||||||
|
console.log(this.selectedHead, "selected head")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let avatarImg = "";
|
||||||
|
if (this.selectedHead.name) {
|
||||||
|
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 avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.selectedHead.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`;
|
||||||
|
avatarImg = this.createImage(avatarUrl);
|
||||||
|
}
|
||||||
|
return html`
|
||||||
|
<div style=${"position: relative;"}>
|
||||||
|
<vaadin-icon
|
||||||
|
class="close-icon"
|
||||||
|
icon="vaadin:close-big"
|
||||||
|
slot="icon"
|
||||||
|
@click=${() => {
|
||||||
|
this.setOpenUserInfo(false)
|
||||||
|
this.chatEditor.enable();
|
||||||
|
}}>
|
||||||
|
</vaadin-icon>
|
||||||
|
${this.isImageLoaded ?
|
||||||
|
html`
|
||||||
|
<div class="avatar-container">
|
||||||
|
${avatarImg}
|
||||||
|
</div>` :
|
||||||
|
html``}
|
||||||
|
${!this.isImageLoaded && this.selectedHead.name ?
|
||||||
|
html`
|
||||||
|
<div class="avatar-container">
|
||||||
|
<div class="user-info-no-avatar">
|
||||||
|
${this.selectedHead.name.charAt(0)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
${!this.isImageLoaded && !this.selectedHead.name ?
|
||||||
|
html`
|
||||||
|
<div
|
||||||
|
class="avatar-container"
|
||||||
|
>
|
||||||
|
<img src="/img/qortal-chat-logo.png" alt="avatar" />
|
||||||
|
</div>`
|
||||||
|
: ""}
|
||||||
|
<div class="user-info-header">
|
||||||
|
${this.selectedHead.name ? this.selectedHead.name : cropAddress(this.selectedHead.address)}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="send-message-button"
|
||||||
|
@click="${() => {
|
||||||
|
this.setOpenPrivateMessage({
|
||||||
|
name: this.userName,
|
||||||
|
open: true
|
||||||
|
})
|
||||||
|
this.setOpenUserInfo(false);
|
||||||
|
}
|
||||||
|
}">
|
||||||
|
${translate("chatpage.cchange58")}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style=${"margin-top: 5px;"}
|
||||||
|
class="send-message-button"
|
||||||
|
@click=${() => {
|
||||||
|
this.setOpenTipUser(true);
|
||||||
|
this.setOpenUserInfo(false);
|
||||||
|
this.chatEditor.disable();
|
||||||
|
}}>
|
||||||
|
${translate("chatpage.cchange59")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
customElements.define('user-info', UserInfo);
|
@ -0,0 +1,87 @@
|
|||||||
|
import { makeFormatter } from './utils';
|
||||||
|
const datetimes = new WeakMap();
|
||||||
|
export default class ExtendedTimeElement extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return [
|
||||||
|
'datetime',
|
||||||
|
'day',
|
||||||
|
'format',
|
||||||
|
'lang',
|
||||||
|
'hour',
|
||||||
|
'minute',
|
||||||
|
'month',
|
||||||
|
'second',
|
||||||
|
'title',
|
||||||
|
'weekday',
|
||||||
|
'year',
|
||||||
|
'time-zone-name'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
const title = this.getFormattedTitle();
|
||||||
|
if (title && !this.hasAttribute('title')) {
|
||||||
|
this.setAttribute('title', title);
|
||||||
|
}
|
||||||
|
const text = this.getFormattedDate();
|
||||||
|
if (text) {
|
||||||
|
this.textContent = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attributeChangedCallback(attrName, oldValue, newValue) {
|
||||||
|
const oldTitle = this.getFormattedTitle();
|
||||||
|
if (attrName === 'datetime') {
|
||||||
|
const millis = Date.parse(newValue);
|
||||||
|
if (isNaN(millis)) {
|
||||||
|
datetimes.delete(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
datetimes.set(this, new Date(millis));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const title = this.getFormattedTitle();
|
||||||
|
const currentTitle = this.getAttribute('title');
|
||||||
|
if (attrName !== 'title' && title && (!currentTitle || currentTitle === oldTitle)) {
|
||||||
|
this.setAttribute('title', title);
|
||||||
|
}
|
||||||
|
const text = this.getFormattedDate();
|
||||||
|
if (text) {
|
||||||
|
this.textContent = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get date() {
|
||||||
|
return datetimes.get(this);
|
||||||
|
}
|
||||||
|
getFormattedTitle() {
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
const formatter = titleFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(date);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
return date.toLocaleString();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof RangeError) {
|
||||||
|
return date.toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getFormattedDate() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const titleFormatter = makeFormatter({
|
||||||
|
day: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
timeZoneName: 'short'
|
||||||
|
});
|
705
qortal-ui-plugins/plugins/core/components/time-elements/index.js
Normal file
705
qortal-ui-plugins/plugins/core/components/time-elements/index.js
Normal file
@ -0,0 +1,705 @@
|
|||||||
|
const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
const months = [
|
||||||
|
'January',
|
||||||
|
'February',
|
||||||
|
'March',
|
||||||
|
'April',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'August',
|
||||||
|
'September',
|
||||||
|
'October',
|
||||||
|
'November',
|
||||||
|
'December'
|
||||||
|
];
|
||||||
|
function pad(num) {
|
||||||
|
return `0${num}`.slice(-2);
|
||||||
|
}
|
||||||
|
function strftime(time, formatString) {
|
||||||
|
const day = time.getDay();
|
||||||
|
const date = time.getDate();
|
||||||
|
const month = time.getMonth();
|
||||||
|
const year = time.getFullYear();
|
||||||
|
const hour = time.getHours();
|
||||||
|
const minute = time.getMinutes();
|
||||||
|
const second = time.getSeconds();
|
||||||
|
return formatString.replace(/%([%aAbBcdeHIlmMpPSwyYZz])/g, function (_arg) {
|
||||||
|
let match;
|
||||||
|
const modifier = _arg[1];
|
||||||
|
switch (modifier) {
|
||||||
|
case '%':
|
||||||
|
return '%';
|
||||||
|
case 'a':
|
||||||
|
return weekdays[day].slice(0, 3);
|
||||||
|
case 'A':
|
||||||
|
return weekdays[day];
|
||||||
|
case 'b':
|
||||||
|
return months[month].slice(0, 3);
|
||||||
|
case 'B':
|
||||||
|
return months[month];
|
||||||
|
case 'c':
|
||||||
|
return time.toString();
|
||||||
|
case 'd':
|
||||||
|
return pad(date);
|
||||||
|
case 'e':
|
||||||
|
return String(date);
|
||||||
|
case 'H':
|
||||||
|
return pad(hour);
|
||||||
|
case 'I':
|
||||||
|
return pad(strftime(time, '%l'));
|
||||||
|
case 'l':
|
||||||
|
if (hour === 0 || hour === 12) {
|
||||||
|
return String(12);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return String((hour + 12) % 12);
|
||||||
|
}
|
||||||
|
case 'm':
|
||||||
|
return pad(month + 1);
|
||||||
|
case 'M':
|
||||||
|
return pad(minute);
|
||||||
|
case 'p':
|
||||||
|
if (hour > 11) {
|
||||||
|
return 'PM';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'AM';
|
||||||
|
}
|
||||||
|
case 'P':
|
||||||
|
if (hour > 11) {
|
||||||
|
return 'pm';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'am';
|
||||||
|
}
|
||||||
|
case 'S':
|
||||||
|
return pad(second);
|
||||||
|
case 'w':
|
||||||
|
return String(day);
|
||||||
|
case 'y':
|
||||||
|
return pad(year % 100);
|
||||||
|
case 'Y':
|
||||||
|
return String(year);
|
||||||
|
case 'Z':
|
||||||
|
match = time.toString().match(/\((\w+)\)$/);
|
||||||
|
return match ? match[1] : '';
|
||||||
|
case 'z':
|
||||||
|
match = time.toString().match(/\w([+-]\d\d\d\d) /);
|
||||||
|
return match ? match[1] : '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function makeFormatter(options) {
|
||||||
|
let format;
|
||||||
|
return function () {
|
||||||
|
if (format)
|
||||||
|
return format;
|
||||||
|
if ('Intl' in window) {
|
||||||
|
try {
|
||||||
|
format = new Intl.DateTimeFormat(undefined, options);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (!(e instanceof RangeError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let dayFirst = null;
|
||||||
|
const dayFirstFormatter = makeFormatter({ day: 'numeric', month: 'short' });
|
||||||
|
function isDayFirst() {
|
||||||
|
if (dayFirst !== null) {
|
||||||
|
return dayFirst;
|
||||||
|
}
|
||||||
|
const formatter = dayFirstFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
const output = formatter.format(new Date(0));
|
||||||
|
dayFirst = !!output.match(/^\d/);
|
||||||
|
return dayFirst;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let yearSeparator = null;
|
||||||
|
const yearFormatter = makeFormatter({ day: 'numeric', month: 'short', year: 'numeric' });
|
||||||
|
function isYearSeparator() {
|
||||||
|
if (yearSeparator !== null) {
|
||||||
|
return yearSeparator;
|
||||||
|
}
|
||||||
|
const formatter = yearFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
const output = formatter.format(new Date(0));
|
||||||
|
yearSeparator = !!output.match(/\d,/);
|
||||||
|
return yearSeparator;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function isThisYear(date) {
|
||||||
|
const now = new Date();
|
||||||
|
return now.getUTCFullYear() === date.getUTCFullYear();
|
||||||
|
}
|
||||||
|
function makeRelativeFormat(locale, options) {
|
||||||
|
if ('Intl' in window && 'RelativeTimeFormat' in window.Intl) {
|
||||||
|
try {
|
||||||
|
return new Intl.RelativeTimeFormat(locale, options);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (!(e instanceof RangeError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function localeFromElement(el) {
|
||||||
|
const container = el.closest('[lang]');
|
||||||
|
if (container instanceof HTMLElement && container.lang) {
|
||||||
|
return container.lang;
|
||||||
|
}
|
||||||
|
return 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
const datetimes = new WeakMap();
|
||||||
|
class ExtendedTimeElement extends HTMLElement {
|
||||||
|
static get observedAttributes() {
|
||||||
|
return [
|
||||||
|
'datetime',
|
||||||
|
'day',
|
||||||
|
'format',
|
||||||
|
'lang',
|
||||||
|
'hour',
|
||||||
|
'minute',
|
||||||
|
'month',
|
||||||
|
'second',
|
||||||
|
'title',
|
||||||
|
'weekday',
|
||||||
|
'year',
|
||||||
|
'time-zone-name'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
const title = this.getFormattedTitle();
|
||||||
|
if (title && !this.hasAttribute('title')) {
|
||||||
|
this.setAttribute('title', title);
|
||||||
|
}
|
||||||
|
const text = this.getFormattedDate();
|
||||||
|
if (text) {
|
||||||
|
this.textContent = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attributeChangedCallback(attrName, oldValue, newValue) {
|
||||||
|
const oldTitle = this.getFormattedTitle();
|
||||||
|
if (attrName === 'datetime') {
|
||||||
|
const millis = Date.parse(newValue);
|
||||||
|
if (isNaN(millis)) {
|
||||||
|
datetimes.delete(this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
datetimes.set(this, new Date(millis));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const title = this.getFormattedTitle();
|
||||||
|
const currentTitle = this.getAttribute('title');
|
||||||
|
if (attrName !== 'title' && title && (!currentTitle || currentTitle === oldTitle)) {
|
||||||
|
this.setAttribute('title', title);
|
||||||
|
}
|
||||||
|
const text = this.getFormattedDate();
|
||||||
|
if (text) {
|
||||||
|
this.textContent = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
get date() {
|
||||||
|
return datetimes.get(this);
|
||||||
|
}
|
||||||
|
getFormattedTitle() {
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
const formatter = titleFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(date);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
return date.toLocaleString();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof RangeError) {
|
||||||
|
return date.toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getFormattedDate() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const titleFormatter = makeFormatter({
|
||||||
|
day: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
year: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: '2-digit',
|
||||||
|
timeZoneName: 'short'
|
||||||
|
});
|
||||||
|
|
||||||
|
const formatters = new WeakMap();
|
||||||
|
class LocalTimeElement extends ExtendedTimeElement {
|
||||||
|
attributeChangedCallback(attrName, oldValue, newValue) {
|
||||||
|
if (attrName === 'hour' || attrName === 'minute' || attrName === 'second' || attrName === 'time-zone-name') {
|
||||||
|
formatters.delete(this);
|
||||||
|
}
|
||||||
|
super.attributeChangedCallback(attrName, oldValue, newValue);
|
||||||
|
}
|
||||||
|
getFormattedDate() {
|
||||||
|
const d = this.date;
|
||||||
|
if (!d)
|
||||||
|
return;
|
||||||
|
const date = formatDate(this, d) || '';
|
||||||
|
const time = formatTime(this, d) || '';
|
||||||
|
return `${date} ${time}`.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatDate(el, date) {
|
||||||
|
const props = {
|
||||||
|
weekday: {
|
||||||
|
short: '%a',
|
||||||
|
long: '%A'
|
||||||
|
},
|
||||||
|
day: {
|
||||||
|
numeric: '%e',
|
||||||
|
'2-digit': '%d'
|
||||||
|
},
|
||||||
|
month: {
|
||||||
|
short: '%b',
|
||||||
|
long: '%B'
|
||||||
|
},
|
||||||
|
year: {
|
||||||
|
numeric: '%Y',
|
||||||
|
'2-digit': '%y'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let format = isDayFirst() ? 'weekday day month year' : 'weekday month day, year';
|
||||||
|
for (const prop in props) {
|
||||||
|
const value = props[prop][el.getAttribute(prop) || ''];
|
||||||
|
format = format.replace(prop, value || '');
|
||||||
|
}
|
||||||
|
format = format.replace(/(\s,)|(,\s$)/, '');
|
||||||
|
return strftime(date, format).replace(/\s+/, ' ').trim();
|
||||||
|
}
|
||||||
|
function formatTime(el, date) {
|
||||||
|
const options = {};
|
||||||
|
const hour = el.getAttribute('hour');
|
||||||
|
if (hour === 'numeric' || hour === '2-digit')
|
||||||
|
options.hour = hour;
|
||||||
|
const minute = el.getAttribute('minute');
|
||||||
|
if (minute === 'numeric' || minute === '2-digit')
|
||||||
|
options.minute = minute;
|
||||||
|
const second = el.getAttribute('second');
|
||||||
|
if (second === 'numeric' || second === '2-digit')
|
||||||
|
options.second = second;
|
||||||
|
const tz = el.getAttribute('time-zone-name');
|
||||||
|
if (tz === 'short' || tz === 'long')
|
||||||
|
options.timeZoneName = tz;
|
||||||
|
if (Object.keys(options).length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let factory = formatters.get(el);
|
||||||
|
if (!factory) {
|
||||||
|
factory = makeFormatter(options);
|
||||||
|
formatters.set(el, factory);
|
||||||
|
}
|
||||||
|
const formatter = factory();
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(date);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const timef = options.second ? '%H:%M:%S' : '%H:%M';
|
||||||
|
return strftime(date, timef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('local-time')) {
|
||||||
|
window.LocalTimeElement = LocalTimeElement;
|
||||||
|
window.customElements.define('local-time', LocalTimeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
class RelativeTime {
|
||||||
|
constructor(date, locale) {
|
||||||
|
this.date = date;
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
const ago = this.timeElapsed();
|
||||||
|
if (ago) {
|
||||||
|
return ago;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const ahead = this.timeAhead();
|
||||||
|
if (ahead) {
|
||||||
|
return ahead;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return `on ${this.formatDate()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeElapsed() {
|
||||||
|
const ms = new Date().getTime() - this.date.getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
if (ms >= 0 && day < 30) {
|
||||||
|
return this.timeAgoFromMs(ms);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeAhead() {
|
||||||
|
const ms = this.date.getTime() - new Date().getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
if (ms >= 0 && day < 30) {
|
||||||
|
return this.timeUntil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeAgo() {
|
||||||
|
const ms = new Date().getTime() - this.date.getTime();
|
||||||
|
return this.timeAgoFromMs(ms);
|
||||||
|
}
|
||||||
|
timeAgoFromMs(ms) {
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (ms < 0) {
|
||||||
|
return formatRelativeTime(this.locale, 0, 'second');
|
||||||
|
}
|
||||||
|
else if (sec < 10) {
|
||||||
|
return formatRelativeTime(this.locale, 0, 'second');
|
||||||
|
}
|
||||||
|
else if (sec < 45) {
|
||||||
|
return formatRelativeTime(this.locale, -sec, 'second');
|
||||||
|
}
|
||||||
|
else if (sec < 90) {
|
||||||
|
return formatRelativeTime(this.locale, -min, 'minute');
|
||||||
|
}
|
||||||
|
else if (min < 45) {
|
||||||
|
return formatRelativeTime(this.locale, -min, 'minute');
|
||||||
|
}
|
||||||
|
else if (min < 90) {
|
||||||
|
return formatRelativeTime(this.locale, -hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (hr < 24) {
|
||||||
|
return formatRelativeTime(this.locale, -hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (hr < 36) {
|
||||||
|
return formatRelativeTime(this.locale, -day, 'day');
|
||||||
|
}
|
||||||
|
else if (day < 30) {
|
||||||
|
return formatRelativeTime(this.locale, -day, 'day');
|
||||||
|
}
|
||||||
|
else if (month < 18) {
|
||||||
|
return formatRelativeTime(this.locale, -month, 'month');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return formatRelativeTime(this.locale, -year, 'year');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
microTimeAgo() {
|
||||||
|
const ms = new Date().getTime() - this.date.getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (min < 1) {
|
||||||
|
return '1m';
|
||||||
|
}
|
||||||
|
else if (min < 60) {
|
||||||
|
return `${min}m`;
|
||||||
|
}
|
||||||
|
else if (hr < 24) {
|
||||||
|
return `${hr}h`;
|
||||||
|
}
|
||||||
|
else if (day < 365) {
|
||||||
|
return `${day}d`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return `${year}y`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeUntil() {
|
||||||
|
const ms = this.date.getTime() - new Date().getTime();
|
||||||
|
return this.timeUntilFromMs(ms);
|
||||||
|
}
|
||||||
|
timeUntilFromMs(ms) {
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (month >= 18) {
|
||||||
|
return formatRelativeTime(this.locale, year, 'year');
|
||||||
|
}
|
||||||
|
else if (month >= 12) {
|
||||||
|
return formatRelativeTime(this.locale, year, 'year');
|
||||||
|
}
|
||||||
|
else if (day >= 45) {
|
||||||
|
return formatRelativeTime(this.locale, month, 'month');
|
||||||
|
}
|
||||||
|
else if (day >= 30) {
|
||||||
|
return formatRelativeTime(this.locale, month, 'month');
|
||||||
|
}
|
||||||
|
else if (hr >= 36) {
|
||||||
|
return formatRelativeTime(this.locale, day, 'day');
|
||||||
|
}
|
||||||
|
else if (hr >= 24) {
|
||||||
|
return formatRelativeTime(this.locale, day, 'day');
|
||||||
|
}
|
||||||
|
else if (min >= 90) {
|
||||||
|
return formatRelativeTime(this.locale, hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (min >= 45) {
|
||||||
|
return formatRelativeTime(this.locale, hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (sec >= 90) {
|
||||||
|
return formatRelativeTime(this.locale, min, 'minute');
|
||||||
|
}
|
||||||
|
else if (sec >= 45) {
|
||||||
|
return formatRelativeTime(this.locale, min, 'minute');
|
||||||
|
}
|
||||||
|
else if (sec >= 10) {
|
||||||
|
return formatRelativeTime(this.locale, sec, 'second');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return formatRelativeTime(this.locale, 0, 'second');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
microTimeUntil() {
|
||||||
|
const ms = this.date.getTime() - new Date().getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (day >= 365) {
|
||||||
|
return `${year}y`;
|
||||||
|
}
|
||||||
|
else if (hr >= 24) {
|
||||||
|
return `${day}d`;
|
||||||
|
}
|
||||||
|
else if (min >= 60) {
|
||||||
|
return `${hr}h`;
|
||||||
|
}
|
||||||
|
else if (min > 1) {
|
||||||
|
return `${min}m`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '1m';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatDate() {
|
||||||
|
let format = isDayFirst() ? '%e %b' : '%b %e';
|
||||||
|
if (!isThisYear(this.date)) {
|
||||||
|
format += isYearSeparator() ? ', %Y' : ' %Y';
|
||||||
|
}
|
||||||
|
return strftime(this.date, format);
|
||||||
|
}
|
||||||
|
formatTime() {
|
||||||
|
const formatter = timeFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(this.date);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return strftime(this.date, '%l:%M%P');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatRelativeTime(locale, value, unit) {
|
||||||
|
const formatter = makeRelativeFormat(locale, { numeric: 'auto' });
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(value, unit);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return formatEnRelativeTime(value, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatEnRelativeTime(value, unit) {
|
||||||
|
if (value === 0) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
return `this ${unit}`;
|
||||||
|
case 'day':
|
||||||
|
return 'today';
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
return `in 0 ${unit}s`;
|
||||||
|
case 'second':
|
||||||
|
return 'now';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value === 1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
return `next ${unit}`;
|
||||||
|
case 'day':
|
||||||
|
return 'tomorrow';
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `in 1 ${unit}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value === -1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
return `last ${unit}`;
|
||||||
|
case 'day':
|
||||||
|
return 'yesterday';
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `1 ${unit} ago`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value > 1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
case 'day':
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `in ${value} ${unit}s`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value < -1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
case 'day':
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `${-value} ${unit}s ago`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RangeError(`Invalid unit argument for format() '${unit}'`);
|
||||||
|
}
|
||||||
|
const timeFormatter = makeFormatter({ hour: 'numeric', minute: '2-digit' });
|
||||||
|
|
||||||
|
class RelativeTimeElement extends ExtendedTimeElement {
|
||||||
|
getFormattedDate() {
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).toString();
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
nowElements.push(this);
|
||||||
|
if (!updateNowElementsId) {
|
||||||
|
updateNowElements();
|
||||||
|
updateNowElementsId = window.setInterval(updateNowElements, 60 * 1000);
|
||||||
|
}
|
||||||
|
super.connectedCallback();
|
||||||
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
const ix = nowElements.indexOf(this);
|
||||||
|
if (ix !== -1) {
|
||||||
|
nowElements.splice(ix, 1);
|
||||||
|
}
|
||||||
|
if (!nowElements.length) {
|
||||||
|
if (updateNowElementsId) {
|
||||||
|
clearInterval(updateNowElementsId);
|
||||||
|
updateNowElementsId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const nowElements = [];
|
||||||
|
let updateNowElementsId;
|
||||||
|
function updateNowElements() {
|
||||||
|
let time, i, len;
|
||||||
|
for (i = 0, len = nowElements.length; i < len; i++) {
|
||||||
|
time = nowElements[i];
|
||||||
|
time.textContent = time.getFormattedDate() || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('relative-time')) {
|
||||||
|
window.RelativeTimeElement = RelativeTimeElement;
|
||||||
|
window.customElements.define('relative-time', RelativeTimeElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeAgoElement extends RelativeTimeElement {
|
||||||
|
getFormattedDate() {
|
||||||
|
const format = this.getAttribute('format');
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
if (format === 'micro') {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).microTimeAgo();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).timeAgo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('time-ago')) {
|
||||||
|
window.TimeAgoElement = TimeAgoElement;
|
||||||
|
window.customElements.define('time-ago', TimeAgoElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeUntilElement extends RelativeTimeElement {
|
||||||
|
getFormattedDate() {
|
||||||
|
const format = this.getAttribute('format');
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
if (format === 'micro') {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).microTimeUntil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).timeUntil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('time-until')) {
|
||||||
|
window.TimeUntilElement = TimeUntilElement;
|
||||||
|
window.customElements.define('time-until', TimeUntilElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { LocalTimeElement, RelativeTimeElement, TimeAgoElement, TimeUntilElement };
|
@ -0,0 +1,81 @@
|
|||||||
|
import { strftime, makeFormatter, isDayFirst } from './utils';
|
||||||
|
import ExtendedTimeElement from './extended-time-element';
|
||||||
|
const formatters = new WeakMap();
|
||||||
|
export default class LocalTimeElement extends ExtendedTimeElement {
|
||||||
|
attributeChangedCallback(attrName, oldValue, newValue) {
|
||||||
|
if (attrName === 'hour' || attrName === 'minute' || attrName === 'second' || attrName === 'time-zone-name') {
|
||||||
|
formatters.delete(this);
|
||||||
|
}
|
||||||
|
super.attributeChangedCallback(attrName, oldValue, newValue);
|
||||||
|
}
|
||||||
|
getFormattedDate() {
|
||||||
|
const d = this.date;
|
||||||
|
if (!d)
|
||||||
|
return;
|
||||||
|
const date = formatDate(this, d) || '';
|
||||||
|
const time = formatTime(this, d) || '';
|
||||||
|
return `${date} ${time}`.trim();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatDate(el, date) {
|
||||||
|
const props = {
|
||||||
|
weekday: {
|
||||||
|
short: '%a',
|
||||||
|
long: '%A'
|
||||||
|
},
|
||||||
|
day: {
|
||||||
|
numeric: '%e',
|
||||||
|
'2-digit': '%d'
|
||||||
|
},
|
||||||
|
month: {
|
||||||
|
short: '%b',
|
||||||
|
long: '%B'
|
||||||
|
},
|
||||||
|
year: {
|
||||||
|
numeric: '%Y',
|
||||||
|
'2-digit': '%y'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let format = isDayFirst() ? 'weekday day month year' : 'weekday month day, year';
|
||||||
|
for (const prop in props) {
|
||||||
|
const value = props[prop][el.getAttribute(prop) || ''];
|
||||||
|
format = format.replace(prop, value || '');
|
||||||
|
}
|
||||||
|
format = format.replace(/(\s,)|(,\s$)/, '');
|
||||||
|
return strftime(date, format).replace(/\s+/, ' ').trim();
|
||||||
|
}
|
||||||
|
function formatTime(el, date) {
|
||||||
|
const options = {};
|
||||||
|
const hour = el.getAttribute('hour');
|
||||||
|
if (hour === 'numeric' || hour === '2-digit')
|
||||||
|
options.hour = hour;
|
||||||
|
const minute = el.getAttribute('minute');
|
||||||
|
if (minute === 'numeric' || minute === '2-digit')
|
||||||
|
options.minute = minute;
|
||||||
|
const second = el.getAttribute('second');
|
||||||
|
if (second === 'numeric' || second === '2-digit')
|
||||||
|
options.second = second;
|
||||||
|
const tz = el.getAttribute('time-zone-name');
|
||||||
|
if (tz === 'short' || tz === 'long')
|
||||||
|
options.timeZoneName = tz;
|
||||||
|
if (Object.keys(options).length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let factory = formatters.get(el);
|
||||||
|
if (!factory) {
|
||||||
|
factory = makeFormatter(options);
|
||||||
|
formatters.set(el, factory);
|
||||||
|
}
|
||||||
|
const formatter = factory();
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(date);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const timef = options.second ? '%H:%M:%S' : '%H:%M';
|
||||||
|
return strftime(date, timef);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('local-time')) {
|
||||||
|
window.LocalTimeElement = LocalTimeElement;
|
||||||
|
window.customElements.define('local-time', LocalTimeElement);
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
import RelativeTime from './relative-time';
|
||||||
|
import ExtendedTimeElement from './extended-time-element';
|
||||||
|
import { localeFromElement } from './utils';
|
||||||
|
export default class RelativeTimeElement extends ExtendedTimeElement {
|
||||||
|
getFormattedDate() {
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).toString();
|
||||||
|
}
|
||||||
|
connectedCallback() {
|
||||||
|
nowElements.push(this);
|
||||||
|
if (!updateNowElementsId) {
|
||||||
|
updateNowElements();
|
||||||
|
updateNowElementsId = window.setInterval(updateNowElements, 60 * 1000);
|
||||||
|
}
|
||||||
|
super.connectedCallback();
|
||||||
|
}
|
||||||
|
disconnectedCallback() {
|
||||||
|
const ix = nowElements.indexOf(this);
|
||||||
|
if (ix !== -1) {
|
||||||
|
nowElements.splice(ix, 1);
|
||||||
|
}
|
||||||
|
if (!nowElements.length) {
|
||||||
|
if (updateNowElementsId) {
|
||||||
|
clearInterval(updateNowElementsId);
|
||||||
|
updateNowElementsId = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const nowElements = [];
|
||||||
|
let updateNowElementsId;
|
||||||
|
function updateNowElements() {
|
||||||
|
let time, i, len;
|
||||||
|
for (i = 0, len = nowElements.length; i < len; i++) {
|
||||||
|
time = nowElements[i];
|
||||||
|
time.textContent = time.getFormattedDate() || '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('relative-time')) {
|
||||||
|
window.RelativeTimeElement = RelativeTimeElement;
|
||||||
|
window.customElements.define('relative-time', RelativeTimeElement);
|
||||||
|
}
|
@ -0,0 +1,290 @@
|
|||||||
|
import { strftime, makeFormatter, makeRelativeFormat, isDayFirst, isThisYear, isYearSeparator } from './utils';
|
||||||
|
export default class RelativeTime {
|
||||||
|
constructor(date, locale) {
|
||||||
|
this.date = date;
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
toString() {
|
||||||
|
const ago = this.timeElapsed();
|
||||||
|
if (ago) {
|
||||||
|
return ago;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const ahead = this.timeAhead();
|
||||||
|
if (ahead) {
|
||||||
|
return ahead;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return `on ${this.formatDate()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeElapsed() {
|
||||||
|
const ms = new Date().getTime() - this.date.getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
if (ms >= 0 && day < 30) {
|
||||||
|
return this.timeAgoFromMs(ms);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeAhead() {
|
||||||
|
const ms = this.date.getTime() - new Date().getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
if (ms >= 0 && day < 30) {
|
||||||
|
return this.timeUntil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeAgo() {
|
||||||
|
const ms = new Date().getTime() - this.date.getTime();
|
||||||
|
return this.timeAgoFromMs(ms);
|
||||||
|
}
|
||||||
|
timeAgoFromMs(ms) {
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (ms < 0) {
|
||||||
|
return formatRelativeTime(this.locale, 0, 'second');
|
||||||
|
}
|
||||||
|
else if (sec < 10) {
|
||||||
|
return formatRelativeTime(this.locale, 0, 'second');
|
||||||
|
}
|
||||||
|
else if (sec < 45) {
|
||||||
|
return formatRelativeTime(this.locale, -sec, 'second');
|
||||||
|
}
|
||||||
|
else if (sec < 90) {
|
||||||
|
return formatRelativeTime(this.locale, -min, 'minute');
|
||||||
|
}
|
||||||
|
else if (min < 45) {
|
||||||
|
return formatRelativeTime(this.locale, -min, 'minute');
|
||||||
|
}
|
||||||
|
else if (min < 90) {
|
||||||
|
return formatRelativeTime(this.locale, -hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (hr < 24) {
|
||||||
|
return formatRelativeTime(this.locale, -hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (hr < 36) {
|
||||||
|
return formatRelativeTime(this.locale, -day, 'day');
|
||||||
|
}
|
||||||
|
else if (day < 30) {
|
||||||
|
return formatRelativeTime(this.locale, -day, 'day');
|
||||||
|
}
|
||||||
|
else if (month < 18) {
|
||||||
|
return formatRelativeTime(this.locale, -month, 'month');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return formatRelativeTime(this.locale, -year, 'year');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
microTimeAgo() {
|
||||||
|
const ms = new Date().getTime() - this.date.getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (min < 1) {
|
||||||
|
return '1m';
|
||||||
|
}
|
||||||
|
else if (min < 60) {
|
||||||
|
return `${min}m`;
|
||||||
|
}
|
||||||
|
else if (hr < 24) {
|
||||||
|
return `${hr}h`;
|
||||||
|
}
|
||||||
|
else if (day < 365) {
|
||||||
|
return `${day}d`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return `${year}y`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timeUntil() {
|
||||||
|
const ms = this.date.getTime() - new Date().getTime();
|
||||||
|
return this.timeUntilFromMs(ms);
|
||||||
|
}
|
||||||
|
timeUntilFromMs(ms) {
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (month >= 18) {
|
||||||
|
return formatRelativeTime(this.locale, year, 'year');
|
||||||
|
}
|
||||||
|
else if (month >= 12) {
|
||||||
|
return formatRelativeTime(this.locale, year, 'year');
|
||||||
|
}
|
||||||
|
else if (day >= 45) {
|
||||||
|
return formatRelativeTime(this.locale, month, 'month');
|
||||||
|
}
|
||||||
|
else if (day >= 30) {
|
||||||
|
return formatRelativeTime(this.locale, month, 'month');
|
||||||
|
}
|
||||||
|
else if (hr >= 36) {
|
||||||
|
return formatRelativeTime(this.locale, day, 'day');
|
||||||
|
}
|
||||||
|
else if (hr >= 24) {
|
||||||
|
return formatRelativeTime(this.locale, day, 'day');
|
||||||
|
}
|
||||||
|
else if (min >= 90) {
|
||||||
|
return formatRelativeTime(this.locale, hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (min >= 45) {
|
||||||
|
return formatRelativeTime(this.locale, hr, 'hour');
|
||||||
|
}
|
||||||
|
else if (sec >= 90) {
|
||||||
|
return formatRelativeTime(this.locale, min, 'minute');
|
||||||
|
}
|
||||||
|
else if (sec >= 45) {
|
||||||
|
return formatRelativeTime(this.locale, min, 'minute');
|
||||||
|
}
|
||||||
|
else if (sec >= 10) {
|
||||||
|
return formatRelativeTime(this.locale, sec, 'second');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return formatRelativeTime(this.locale, 0, 'second');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
microTimeUntil() {
|
||||||
|
const ms = this.date.getTime() - new Date().getTime();
|
||||||
|
const sec = Math.round(ms / 1000);
|
||||||
|
const min = Math.round(sec / 60);
|
||||||
|
const hr = Math.round(min / 60);
|
||||||
|
const day = Math.round(hr / 24);
|
||||||
|
const month = Math.round(day / 30);
|
||||||
|
const year = Math.round(month / 12);
|
||||||
|
if (day >= 365) {
|
||||||
|
return `${year}y`;
|
||||||
|
}
|
||||||
|
else if (hr >= 24) {
|
||||||
|
return `${day}d`;
|
||||||
|
}
|
||||||
|
else if (min >= 60) {
|
||||||
|
return `${hr}h`;
|
||||||
|
}
|
||||||
|
else if (min > 1) {
|
||||||
|
return `${min}m`;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return '1m';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
formatDate() {
|
||||||
|
let format = isDayFirst() ? '%e %b' : '%b %e';
|
||||||
|
if (!isThisYear(this.date)) {
|
||||||
|
format += isYearSeparator() ? ', %Y' : ' %Y';
|
||||||
|
}
|
||||||
|
return strftime(this.date, format);
|
||||||
|
}
|
||||||
|
formatTime() {
|
||||||
|
const formatter = timeFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(this.date);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return strftime(this.date, '%l:%M%P');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatRelativeTime(locale, value, unit) {
|
||||||
|
const formatter = makeRelativeFormat(locale, { numeric: 'auto' });
|
||||||
|
if (formatter) {
|
||||||
|
return formatter.format(value, unit);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return formatEnRelativeTime(value, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function formatEnRelativeTime(value, unit) {
|
||||||
|
if (value === 0) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
return `this ${unit}`;
|
||||||
|
case 'day':
|
||||||
|
return 'today';
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
return `in 0 ${unit}s`;
|
||||||
|
case 'second':
|
||||||
|
return 'now';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value === 1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
return `next ${unit}`;
|
||||||
|
case 'day':
|
||||||
|
return 'tomorrow';
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `in 1 ${unit}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value === -1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
return `last ${unit}`;
|
||||||
|
case 'day':
|
||||||
|
return 'yesterday';
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `1 ${unit} ago`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value > 1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
case 'day':
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `in ${value} ${unit}s`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value < -1) {
|
||||||
|
switch (unit) {
|
||||||
|
case 'year':
|
||||||
|
case 'quarter':
|
||||||
|
case 'month':
|
||||||
|
case 'week':
|
||||||
|
case 'day':
|
||||||
|
case 'hour':
|
||||||
|
case 'minute':
|
||||||
|
case 'second':
|
||||||
|
return `${-value} ${unit}s ago`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new RangeError(`Invalid unit argument for format() '${unit}'`);
|
||||||
|
}
|
||||||
|
const timeFormatter = makeFormatter({ hour: 'numeric', minute: '2-digit' });
|
@ -0,0 +1,21 @@
|
|||||||
|
import RelativeTime from './relative-time';
|
||||||
|
import RelativeTimeElement from './relative-time-element';
|
||||||
|
import { localeFromElement } from './utils';
|
||||||
|
export default class TimeAgoElement extends RelativeTimeElement {
|
||||||
|
getFormattedDate() {
|
||||||
|
const format = this.getAttribute('format');
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
if (format === 'micro') {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).microTimeAgo();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).timeAgo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('time-ago')) {
|
||||||
|
window.TimeAgoElement = TimeAgoElement;
|
||||||
|
window.customElements.define('time-ago', TimeAgoElement);
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
import RelativeTime from './relative-time';
|
||||||
|
import RelativeTimeElement from './relative-time-element';
|
||||||
|
import { localeFromElement } from './utils';
|
||||||
|
export default class TimeUntilElement extends RelativeTimeElement {
|
||||||
|
getFormattedDate() {
|
||||||
|
const format = this.getAttribute('format');
|
||||||
|
const date = this.date;
|
||||||
|
if (!date)
|
||||||
|
return;
|
||||||
|
if (format === 'micro') {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).microTimeUntil();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new RelativeTime(date, localeFromElement(this)).timeUntil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!window.customElements.get('time-until')) {
|
||||||
|
window.TimeUntilElement = TimeUntilElement;
|
||||||
|
window.customElements.define('time-until', TimeUntilElement);
|
||||||
|
}
|
166
qortal-ui-plugins/plugins/core/components/time-elements/utils.js
Normal file
166
qortal-ui-plugins/plugins/core/components/time-elements/utils.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
const weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||||
|
const months = [
|
||||||
|
'January',
|
||||||
|
'February',
|
||||||
|
'March',
|
||||||
|
'April',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'August',
|
||||||
|
'September',
|
||||||
|
'October',
|
||||||
|
'November',
|
||||||
|
'December'
|
||||||
|
];
|
||||||
|
function pad(num) {
|
||||||
|
return `0${num}`.slice(-2);
|
||||||
|
}
|
||||||
|
export function strftime(time, formatString) {
|
||||||
|
const day = time.getDay();
|
||||||
|
const date = time.getDate();
|
||||||
|
const month = time.getMonth();
|
||||||
|
const year = time.getFullYear();
|
||||||
|
const hour = time.getHours();
|
||||||
|
const minute = time.getMinutes();
|
||||||
|
const second = time.getSeconds();
|
||||||
|
return formatString.replace(/%([%aAbBcdeHIlmMpPSwyYZz])/g, function (_arg) {
|
||||||
|
let match;
|
||||||
|
const modifier = _arg[1];
|
||||||
|
switch (modifier) {
|
||||||
|
case '%':
|
||||||
|
return '%';
|
||||||
|
case 'a':
|
||||||
|
return weekdays[day].slice(0, 3);
|
||||||
|
case 'A':
|
||||||
|
return weekdays[day];
|
||||||
|
case 'b':
|
||||||
|
return months[month].slice(0, 3);
|
||||||
|
case 'B':
|
||||||
|
return months[month];
|
||||||
|
case 'c':
|
||||||
|
return time.toString();
|
||||||
|
case 'd':
|
||||||
|
return pad(date);
|
||||||
|
case 'e':
|
||||||
|
return String(date);
|
||||||
|
case 'H':
|
||||||
|
return pad(hour);
|
||||||
|
case 'I':
|
||||||
|
return pad(strftime(time, '%l'));
|
||||||
|
case 'l':
|
||||||
|
if (hour === 0 || hour === 12) {
|
||||||
|
return String(12);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return String((hour + 12) % 12);
|
||||||
|
}
|
||||||
|
case 'm':
|
||||||
|
return pad(month + 1);
|
||||||
|
case 'M':
|
||||||
|
return pad(minute);
|
||||||
|
case 'p':
|
||||||
|
if (hour > 11) {
|
||||||
|
return 'PM';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'AM';
|
||||||
|
}
|
||||||
|
case 'P':
|
||||||
|
if (hour > 11) {
|
||||||
|
return 'pm';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 'am';
|
||||||
|
}
|
||||||
|
case 'S':
|
||||||
|
return pad(second);
|
||||||
|
case 'w':
|
||||||
|
return String(day);
|
||||||
|
case 'y':
|
||||||
|
return pad(year % 100);
|
||||||
|
case 'Y':
|
||||||
|
return String(year);
|
||||||
|
case 'Z':
|
||||||
|
match = time.toString().match(/\((\w+)\)$/);
|
||||||
|
return match ? match[1] : '';
|
||||||
|
case 'z':
|
||||||
|
match = time.toString().match(/\w([+-]\d\d\d\d) /);
|
||||||
|
return match ? match[1] : '';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
export function makeFormatter(options) {
|
||||||
|
let format;
|
||||||
|
return function () {
|
||||||
|
if (format)
|
||||||
|
return format;
|
||||||
|
if ('Intl' in window) {
|
||||||
|
try {
|
||||||
|
format = new Intl.DateTimeFormat(undefined, options);
|
||||||
|
return format;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (!(e instanceof RangeError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let dayFirst = null;
|
||||||
|
const dayFirstFormatter = makeFormatter({ day: 'numeric', month: 'short' });
|
||||||
|
export function isDayFirst() {
|
||||||
|
if (dayFirst !== null) {
|
||||||
|
return dayFirst;
|
||||||
|
}
|
||||||
|
const formatter = dayFirstFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
const output = formatter.format(new Date(0));
|
||||||
|
dayFirst = !!output.match(/^\d/);
|
||||||
|
return dayFirst;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let yearSeparator = null;
|
||||||
|
const yearFormatter = makeFormatter({ day: 'numeric', month: 'short', year: 'numeric' });
|
||||||
|
export function isYearSeparator() {
|
||||||
|
if (yearSeparator !== null) {
|
||||||
|
return yearSeparator;
|
||||||
|
}
|
||||||
|
const formatter = yearFormatter();
|
||||||
|
if (formatter) {
|
||||||
|
const output = formatter.format(new Date(0));
|
||||||
|
yearSeparator = !!output.match(/\d,/);
|
||||||
|
return yearSeparator;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function isThisYear(date) {
|
||||||
|
const now = new Date();
|
||||||
|
return now.getUTCFullYear() === date.getUTCFullYear();
|
||||||
|
}
|
||||||
|
export function makeRelativeFormat(locale, options) {
|
||||||
|
if ('Intl' in window && 'RelativeTimeFormat' in window.Intl) {
|
||||||
|
try {
|
||||||
|
return new Intl.RelativeTimeFormat(locale, options);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (!(e instanceof RangeError)) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function localeFromElement(el) {
|
||||||
|
const container = el.closest('[lang]');
|
||||||
|
if (container instanceof HTMLElement && container.lang) {
|
||||||
|
return container.lang;
|
||||||
|
}
|
||||||
|
return 'default';
|
||||||
|
}
|
@ -7,6 +7,7 @@ registerTranslateConfig({
|
|||||||
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
})
|
})
|
||||||
|
|
||||||
|
import '../components/time-elements/index.js'
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-dialog'
|
import '@material/mwc-dialog'
|
||||||
import '@material/mwc-formfield'
|
import '@material/mwc-formfield'
|
||||||
@ -21,7 +22,6 @@ import '@vaadin/icon'
|
|||||||
import '@vaadin/icons'
|
import '@vaadin/icons'
|
||||||
import '@vaadin/grid'
|
import '@vaadin/grid'
|
||||||
import '@vaadin/grid/vaadin-grid-filter-column.js'
|
import '@vaadin/grid/vaadin-grid-filter-column.js'
|
||||||
import '@github/time-elements'
|
|
||||||
|
|
||||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
@ -38,6 +38,7 @@ class GroupManagement extends LitElement {
|
|||||||
newAdminsList: { type: Array },
|
newAdminsList: { type: Array },
|
||||||
newBannedList: { type: Array },
|
newBannedList: { type: Array },
|
||||||
newGroupInvitesList: { type: Array },
|
newGroupInvitesList: { type: Array },
|
||||||
|
newGroupJoinsList: { type: Array },
|
||||||
recipientPublicKey: { type: String },
|
recipientPublicKey: { type: String },
|
||||||
selectedAddress: { type: Object },
|
selectedAddress: { type: Object },
|
||||||
manageGroupObj: { type: Object },
|
manageGroupObj: { type: Object },
|
||||||
@ -155,6 +156,11 @@ class GroupManagement extends LitElement {
|
|||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.success-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
color: #198754;
|
||||||
|
}
|
||||||
|
|
||||||
.close-icon {
|
.close-icon {
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
}
|
}
|
||||||
@ -436,6 +442,7 @@ class GroupManagement extends LitElement {
|
|||||||
this.newAdminsList = []
|
this.newAdminsList = []
|
||||||
this.newBannedList = []
|
this.newBannedList = []
|
||||||
this.newGroupInvitesList = []
|
this.newGroupInvitesList = []
|
||||||
|
this.newGroupJoinsList = []
|
||||||
this.manageGroupObj = {}
|
this.manageGroupObj = {}
|
||||||
this.joinGroupObj = {}
|
this.joinGroupObj = {}
|
||||||
this.leaveGroupObj = {}
|
this.leaveGroupObj = {}
|
||||||
@ -836,6 +843,7 @@ class GroupManagement extends LitElement {
|
|||||||
|
|
||||||
groupInviteTemplate() {
|
groupInviteTemplate() {
|
||||||
return html`
|
return html`
|
||||||
|
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">${translate("managegroup.mg36")}</h3>
|
||||||
<vaadin-grid theme="large" id="groupInvitesGrid" ?hidden="${this.isEmptyArray(this.newGroupInvitesList)}" .items="${this.newGroupInvitesList}" aria-label="Group Invites" all-rows-visible>
|
<vaadin-grid theme="large" id="groupInvitesGrid" ?hidden="${this.isEmptyArray(this.newGroupInvitesList)}" .items="${this.newGroupInvitesList}" aria-label="Group Invites" all-rows-visible>
|
||||||
<vaadin-grid-column
|
<vaadin-grid-column
|
||||||
width="6rem"
|
width="6rem"
|
||||||
@ -880,6 +888,54 @@ class GroupManagement extends LitElement {
|
|||||||
${this.isEmptyArray(this.newGroupInvitesList) ? html`
|
${this.isEmptyArray(this.newGroupInvitesList) ? html`
|
||||||
<span style="color: var(--black);">${translate("managegroup.mg35")}</span>
|
<span style="color: var(--black);">${translate("managegroup.mg35")}</span>
|
||||||
` : html``}
|
` : html``}
|
||||||
|
<br><hr><br>
|
||||||
|
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">${translate("managegroup.mg53")}</h3>
|
||||||
|
<vaadin-grid theme="large" id="groupJoinsGrid" ?hidden="${this.isEmptyArray(this.newGroupJoinsList)}" .items="${this.newGroupJoinsList}" aria-label="Group Join Requests" all-rows-visible>
|
||||||
|
<vaadin-grid-column
|
||||||
|
width="6rem"
|
||||||
|
flex-grow="0"
|
||||||
|
header="${translate("websitespage.schange5")}"
|
||||||
|
.renderer=${(root, column, data) => {
|
||||||
|
render(html`${this.renderAvatar(data.item)}`, root)
|
||||||
|
}}
|
||||||
|
></vaadin-grid-column>
|
||||||
|
<vaadin-grid-column
|
||||||
|
auto-width
|
||||||
|
resizable
|
||||||
|
header="${translate("puzzlepage.pchange4")}"
|
||||||
|
.renderer=${(root, column, data) => {
|
||||||
|
render(html`${data.item.name}`, root)
|
||||||
|
}}
|
||||||
|
></vaadin-grid-column>
|
||||||
|
<vaadin-grid-column
|
||||||
|
auto-width
|
||||||
|
resizable
|
||||||
|
header="${translate("login.address")}"
|
||||||
|
.renderer=${(root, column, data) => {
|
||||||
|
render(html`${data.item.owner}`, root)
|
||||||
|
}}
|
||||||
|
></vaadin-grid-column>
|
||||||
|
<vaadin-grid-column
|
||||||
|
width="12rem"
|
||||||
|
flex-grow="0"
|
||||||
|
header="${translate("websitespage.schange8")}"
|
||||||
|
.renderer=${(root, column, data) => {
|
||||||
|
render(html`${this.renderConfirmRequestButton(data.item)}`, root)
|
||||||
|
}}
|
||||||
|
></vaadin-grid-column>
|
||||||
|
<vaadin-grid-column
|
||||||
|
width="12rem"
|
||||||
|
flex-grow="0"
|
||||||
|
.renderer=${(root, column, data) => {
|
||||||
|
render(html`${this.renderDeclineRequestButton(data.item)}`, root)
|
||||||
|
}}
|
||||||
|
></vaadin-grid-column>
|
||||||
|
</vaadin-grid>
|
||||||
|
${this.isEmptyArray(this.newGroupJoinsList) ? html`
|
||||||
|
<span style="color: var(--black);">${translate("managegroup.mg54")}</span>
|
||||||
|
` : html``}
|
||||||
|
<br>
|
||||||
|
<hr>
|
||||||
<div style="padding-top: 20px;">
|
<div style="padding-top: 20px;">
|
||||||
<vaadin-button theme="primary medium" @click=${() => this.openInviteMemberToGroupDialog()}>
|
<vaadin-button theme="primary medium" @click=${() => this.openInviteMemberToGroupDialog()}>
|
||||||
${translate("managegroup.mg2")}
|
${translate("managegroup.mg2")}
|
||||||
@ -1033,6 +1089,72 @@ class GroupManagement extends LitElement {
|
|||||||
${translate("general.close")}
|
${translate("general.close")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
|
|
||||||
|
<mwc-dialog id="successJoinDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
|
<div class="card-container">
|
||||||
|
<mwc-icon class="success-icon">group_add</mwc-icon>
|
||||||
|
<h2>${translate("managegroup.mg57")}</h2>
|
||||||
|
<h4>${translate("walletpage.wchange43")}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${() => this.closeSuccessJoinDialog()}
|
||||||
|
class="red"
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</mwc-button>
|
||||||
|
</mwc-dialog>
|
||||||
|
|
||||||
|
<mwc-dialog id="errorJoinDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
|
<div class="card-container">
|
||||||
|
<mwc-icon class="error-icon">warning</mwc-icon>
|
||||||
|
<h2>${translate("managegroup.mg58")}</h2>
|
||||||
|
<h4>${this.errorMessage}</h4>
|
||||||
|
<h4>${translate("walletpage.wchange44")}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${() => this.closeErrorJoinDialog()}
|
||||||
|
class="red"
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</mwc-button>
|
||||||
|
</mwc-dialog>
|
||||||
|
|
||||||
|
<mwc-dialog id="cancelSuccessJoinDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
|
<div class="card-container">
|
||||||
|
<mwc-icon class="success-icon">person_remove</mwc-icon>
|
||||||
|
<h2>${translate("managegroup.mg59")}</h2>
|
||||||
|
<h4>${translate("walletpage.wchange43")}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${() => this.closeCancelSuccessJoinDialog()}
|
||||||
|
class="red"
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</mwc-button>
|
||||||
|
</mwc-dialog>
|
||||||
|
|
||||||
|
<mwc-dialog id="cancelErrorJoinDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
|
<div class="card-container">
|
||||||
|
<mwc-icon class="error-icon">warning</mwc-icon>
|
||||||
|
<h2>${translate("managegroup.mg58")}</h2>
|
||||||
|
<h4>${this.errorMessage}</h4>
|
||||||
|
<h4>${translate("walletpage.wchange44")}</h4>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<mwc-button
|
||||||
|
slot="primaryAction"
|
||||||
|
@click=${() => this.closeCancelErrorJoinDialog()}
|
||||||
|
class="red"
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</mwc-button>
|
||||||
|
</mwc-dialog>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1987,6 +2109,38 @@ class GroupManagement extends LitElement {
|
|||||||
this.errorMessage = ''
|
this.errorMessage = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderConfirmRequestButton(joinObj) {
|
||||||
|
return html`<mwc-button class="green" @click=${() => this.createAcceptJoinGroupMember(joinObj)}><mwc-icon>add_task</mwc-icon> ${translate("transpage.tchange3")}</mwc-button>`
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDeclineRequestButton(joinObj) {
|
||||||
|
return html`<mwc-button class="red" @click=${() => this.kickJoinGroupMember(joinObj)}><mwc-icon>cancel</mwc-icon> ${translate("transpage.tchange2")}</mwc-button>`
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSuccessJoinDialog() {
|
||||||
|
this.shadowRoot.querySelector('#successJoinDialog').close()
|
||||||
|
this.successMessage = ''
|
||||||
|
this.errorMessage = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
closeErrorJoinDialog() {
|
||||||
|
this.shadowRoot.querySelector('#errorJoinDialog').close()
|
||||||
|
this.successMessage = ''
|
||||||
|
this.errorMessage = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
closeCancelSuccessJoinDialog() {
|
||||||
|
this.shadowRoot.querySelector('#cancelSuccessJoinDialog').close()
|
||||||
|
this.successMessage = ''
|
||||||
|
this.errorMessage = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
closeCancelErrorJoinDialog() {
|
||||||
|
this.shadowRoot.querySelector('#cancelErrorJoinDialog').close()
|
||||||
|
this.successMessage = ''
|
||||||
|
this.errorMessage = ''
|
||||||
|
}
|
||||||
|
|
||||||
openMemberInfo(inviteGroupId) {
|
openMemberInfo(inviteGroupId) {
|
||||||
const _inviteMemberInfo = this.shadowRoot.getElementById('toInviteMemberToGroup').value
|
const _inviteMemberInfo = this.shadowRoot.getElementById('toInviteMemberToGroup').value
|
||||||
const _nviteMemberTime = this.shadowRoot.getElementById("inviteMemberTime").value
|
const _nviteMemberTime = this.shadowRoot.getElementById("inviteMemberTime").value
|
||||||
@ -2362,6 +2516,57 @@ class GroupManagement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getNewGroupJoinList(theGroup) {
|
||||||
|
let callGroupID = theGroup
|
||||||
|
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||||
|
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
|
||||||
|
let joinObj = []
|
||||||
|
this.groupJoinMembers = []
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: `/groups/joinrequests/${callGroupID}`
|
||||||
|
}).then(res => {
|
||||||
|
this.groupJoinMembers = res
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.groupJoinMembers.length === 0) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
this.groupJoinMembers.map(a => {
|
||||||
|
let callTheJoinMember = a.joiner
|
||||||
|
let callSingleJoinMemberUrl = `${nodeUrl}/names/address/${callTheJoinMember}`
|
||||||
|
fetch(callSingleJoinMemberUrl).then(res => {
|
||||||
|
return res.json()
|
||||||
|
}).then(jsonRes => {
|
||||||
|
if (jsonRes.length) {
|
||||||
|
jsonRes.map(b => {
|
||||||
|
const joinObjToAdd = {
|
||||||
|
groupId: a.groupId,
|
||||||
|
name: b.name,
|
||||||
|
owner: b.owner,
|
||||||
|
time: '86400',
|
||||||
|
reason: 'NotAllowed'
|
||||||
|
}
|
||||||
|
joinObj.push(joinObjToAdd)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const noName = 'No registered name'
|
||||||
|
const noNameObj = {
|
||||||
|
groupId: a.groupId,
|
||||||
|
name: noName,
|
||||||
|
owner: a.joiner,
|
||||||
|
time: '86400',
|
||||||
|
reason: 'NotAllowed'
|
||||||
|
}
|
||||||
|
joinObj.push(noNameObj)
|
||||||
|
}
|
||||||
|
this.newGroupJoinsList = joinObj
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
closeManageGroupOwnerDialog() {
|
closeManageGroupOwnerDialog() {
|
||||||
this.resetDefaultSettings()
|
this.resetDefaultSettings()
|
||||||
this.shadowRoot.getElementById('manageGroupOwnerDialog').close()
|
this.shadowRoot.getElementById('manageGroupOwnerDialog').close()
|
||||||
@ -2390,6 +2595,7 @@ class GroupManagement extends LitElement {
|
|||||||
await this.getNewMemberList(groupObj.groupId)
|
await this.getNewMemberList(groupObj.groupId)
|
||||||
await this.getNewBannedList(groupObj.groupId)
|
await this.getNewBannedList(groupObj.groupId)
|
||||||
await this.getNewGroupInvitesList(groupObj.groupId)
|
await this.getNewGroupInvitesList(groupObj.groupId)
|
||||||
|
await this.getNewGroupJoinList(groupObj.groupId)
|
||||||
await manageGroupDelay(1000)
|
await manageGroupDelay(1000)
|
||||||
this.shadowRoot.getElementById('manageGroupOwnerDialog').open()
|
this.shadowRoot.getElementById('manageGroupOwnerDialog').open()
|
||||||
}
|
}
|
||||||
@ -3058,6 +3264,148 @@ class GroupManagement extends LitElement {
|
|||||||
validateReceiver()
|
validateReceiver()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createAcceptJoinGroupMember(joinObj) {
|
||||||
|
const member = joinObj.owner
|
||||||
|
const inviteTime = joinObj.time
|
||||||
|
const inviteGroupMemberFeeInput = this.inviteGroupMemberFee
|
||||||
|
const theGroupId = joinObj.groupId
|
||||||
|
this.isLoading = true
|
||||||
|
this.btnDisable = true
|
||||||
|
|
||||||
|
const getLastRef = async () => {
|
||||||
|
let myRef = await parentEpml.request('apiCall', {
|
||||||
|
type: 'api',
|
||||||
|
url: `/addresses/lastreference/${this.selectedAddress.address}`
|
||||||
|
})
|
||||||
|
return myRef
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateReceiver = async () => {
|
||||||
|
let lastRef = await getLastRef()
|
||||||
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
getTxnRequestResponse(myTransaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
const myMember = member
|
||||||
|
const myLastRef = lastRef
|
||||||
|
const myGroupId = theGroupId
|
||||||
|
const myFee = inviteGroupMemberFeeInput
|
||||||
|
const myInviteTime = inviteTime
|
||||||
|
const myInviteMemberDialog1 = get("managegroup.mg55")
|
||||||
|
const myInviteMemberDialog2 = get("managegroup.mg56")
|
||||||
|
|
||||||
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
|
type: 29,
|
||||||
|
nonce: this.selectedAddress.nonce,
|
||||||
|
params: {
|
||||||
|
fee: myFee,
|
||||||
|
recipient: myMember,
|
||||||
|
rGroupId: myGroupId,
|
||||||
|
rInviteTime: myInviteTime,
|
||||||
|
lastReference: myLastRef,
|
||||||
|
inviteMemberDialog1: myInviteMemberDialog1,
|
||||||
|
inviteMemberDialog2: myInviteMemberDialog2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return myTxnrequest
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
|
if (txnResponse.success === false && txnResponse.message) {
|
||||||
|
this.errorMessage = txnResponse.message
|
||||||
|
this.shadowRoot.querySelector('#errorJoinDialog').show()
|
||||||
|
this.isLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
||||||
|
this.shadowRoot.querySelector('#successJoinDialog').show()
|
||||||
|
this.errorMessage = ''
|
||||||
|
this.successMessage = this.renderSuccessText()
|
||||||
|
this.isLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
} else {
|
||||||
|
this.errorMessage = txnResponse.data.message
|
||||||
|
this.shadowRoot.querySelector('#errorJoinDialog').show()
|
||||||
|
this.isLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
async kickJoinGroupMember(joinObj) {
|
||||||
|
const member = joinObj.owner
|
||||||
|
const reason = joinObj.reason
|
||||||
|
const kickGroupMemberFeeInput = this.kickGroupMemberFee
|
||||||
|
const theGroupId = joinObj.groupId
|
||||||
|
this.isLoading = true
|
||||||
|
this.btnDisable = true
|
||||||
|
|
||||||
|
const getLastRef = async () => {
|
||||||
|
let myRef = await parentEpml.request('apiCall', {
|
||||||
|
type: 'api',
|
||||||
|
url: `/addresses/lastreference/${this.selectedAddress.address}`
|
||||||
|
})
|
||||||
|
return myRef
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateReceiver = async () => {
|
||||||
|
let lastRef = await getLastRef()
|
||||||
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
getTxnRequestResponse(myTransaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
const myMember = member
|
||||||
|
const myLastRef = lastRef
|
||||||
|
const myGroupId = theGroupId
|
||||||
|
const myFee = kickGroupMemberFeeInput
|
||||||
|
const myReason = reason
|
||||||
|
const myKickMemberDialog1 = get("managegroup.mg60")
|
||||||
|
const myKickMemberDialog2 = get("managegroup.mg61")
|
||||||
|
|
||||||
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
|
type: 28,
|
||||||
|
nonce: this.selectedAddress.nonce,
|
||||||
|
params: {
|
||||||
|
fee: myFee,
|
||||||
|
recipient: myMember,
|
||||||
|
rGroupId: myGroupId,
|
||||||
|
rBanReason: myReason,
|
||||||
|
lastReference: myLastRef,
|
||||||
|
kickMemberDialog1: myKickMemberDialog1,
|
||||||
|
kickMemberDialog2: myKickMemberDialog2
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return myTxnrequest
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
|
if (txnResponse.success === false && txnResponse.message) {
|
||||||
|
this.errorMessage = txnResponse.message
|
||||||
|
this.shadowRoot.querySelector('#cancelErrorJoinDialog').show()
|
||||||
|
this.isLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
||||||
|
this.shadowRoot.querySelector('#cancelSuccessJoinDialog').show()
|
||||||
|
this.errorMessage = ''
|
||||||
|
this.successMessage = this.renderSuccessText()
|
||||||
|
this.isLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
} else {
|
||||||
|
this.errorMessage = txnResponse.data.message
|
||||||
|
this.shadowRoot.querySelector('#cancelErrorJoinDialog').show()
|
||||||
|
this.isLoading = false
|
||||||
|
this.btnDisable = false
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
async addGroupAdmin(groupId) {
|
async addGroupAdmin(groupId) {
|
||||||
const member = this.shadowRoot.getElementById('memberToAdmin').value
|
const member = this.shadowRoot.getElementById('memberToAdmin').value
|
||||||
const addGroupAdminFeeInput = this.addGroupAdminFee
|
const addGroupAdminFeeInput = this.addGroupAdminFee
|
||||||
|
@ -94,7 +94,7 @@ export const qchatStyles = css`
|
|||||||
}
|
}
|
||||||
|
|
||||||
.people-list ul {
|
.people-list ul {
|
||||||
padding: 0;
|
padding: 0px 0px 60px 0px;
|
||||||
height: 85vh;
|
height: 85vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
@ -0,0 +1,214 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { render } from 'lit/html.js'
|
||||||
|
import { Epml } from '../../../../epml.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
registerTranslateConfig({
|
||||||
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
|
})
|
||||||
|
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
import * as Highcharts from 'highcharts'
|
||||||
|
import Exporting from 'highcharts/modules/exporting'
|
||||||
|
Exporting(Highcharts)
|
||||||
|
import StockChart from 'highcharts/modules/stock'
|
||||||
|
StockChart(Highcharts)
|
||||||
|
import 'highcharts/highcharts-more.js'
|
||||||
|
import 'highcharts/modules/accessibility.js'
|
||||||
|
import 'highcharts/modules/boost.js'
|
||||||
|
import 'highcharts/modules/data.js'
|
||||||
|
import 'highcharts/modules/export-data.js'
|
||||||
|
import 'highcharts/modules/offline-exporting.js'
|
||||||
|
|
||||||
|
let arrrChartDialog
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class ArrrCharts extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoadingTradesChart: { type: Boolean },
|
||||||
|
arrrTrades: { type: Array },
|
||||||
|
arrrPrice: { type: Array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
.loadingContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trades-chart {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
color: var(--black);
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 30vh;
|
||||||
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
height: 38vh;
|
||||||
|
width: 83vw;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-loading-wrapper {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.arrrTrades = []
|
||||||
|
this.arrrPrice = []
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<paper-dialog id="loadChartDialog" class="chart-loading-wrapper" modal>
|
||||||
|
<div class="loadingContainer" style="display:${this.isLoadingTradesChart ? 'inline-block' : 'none'}">
|
||||||
|
<span style="color: var(--black);">${translate("login.loading")}</span>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
<paper-dialog id="arrrChartDialog" class="chart-info-wrapper">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div id='arrrStockPriceContainer' class='trades-chart'></div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.changeTheme()
|
||||||
|
this.changeLanguage()
|
||||||
|
|
||||||
|
window.addEventListener('storage', () => {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
|
||||||
|
use(checkLanguage)
|
||||||
|
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTradesChart() {
|
||||||
|
this.isLoadingTradesChart = true
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').open()
|
||||||
|
await this.getArrrTrades()
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').close()
|
||||||
|
this.enableArrrStockPriceChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getArrrTrades() {
|
||||||
|
let currentArrrTimestamp = Date.now()
|
||||||
|
const monthBackArrr = currentArrrTimestamp - 31556952000
|
||||||
|
await parentEpml.request("apiCall", { url: `/crosschain/trades?foreignBlockchain=PIRATECHAIN&minimumTimestamp=${monthBackArrr}&limit=0&reverse=false` }).then((res) => {
|
||||||
|
this.arrrTrades = res
|
||||||
|
})
|
||||||
|
this.arrrPrice = this.arrrTrades.map(item => {
|
||||||
|
const arrrSellPrice = this.round(parseFloat(item.foreignAmount) / parseFloat(item.qortAmount))
|
||||||
|
return [item.tradeTimestamp, parseFloat(arrrSellPrice)]
|
||||||
|
}).filter(item => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
enableArrrStockPriceChart() {
|
||||||
|
const arrrStockPriceData = this.arrrPrice
|
||||||
|
const header = 'QORT / ARRR ' + get("tradepage.tchange49")
|
||||||
|
Highcharts.stockChart(this.shadowRoot.querySelector('#arrrStockPriceContainer'), {
|
||||||
|
accessibility: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
selected: 1,
|
||||||
|
labelStyle: {color: 'var(--black)'},
|
||||||
|
inputStyle: {color: '#03a9f4'}
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: header,
|
||||||
|
style: {color: 'var(--black)'}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'QORT / ARRR',
|
||||||
|
data: arrrStockPriceData,
|
||||||
|
tooltip: {
|
||||||
|
valueDecimals: 8
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.loadTradesChart()
|
||||||
|
this.shadowRoot.getElementById('arrrChartDialog').open()
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage() {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
|
if (checkLanguage === null || checkLanguage.length === 0) {
|
||||||
|
localStorage.setItem('qortalLanguage', 'us')
|
||||||
|
use('us')
|
||||||
|
} else {
|
||||||
|
use(checkLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('arrr-charts', ArrrCharts)
|
||||||
|
|
||||||
|
const chartsarrr = document.createElement('arrr-charts')
|
||||||
|
arrrChartDialog = document.body.appendChild(chartsarrr)
|
||||||
|
|
||||||
|
export default arrrChartDialog
|
215
qortal-ui-plugins/plugins/core/trade-portal/charts/btc-charts.js
Normal file
215
qortal-ui-plugins/plugins/core/trade-portal/charts/btc-charts.js
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { render } from 'lit/html.js'
|
||||||
|
import { Epml } from '../../../../epml.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
registerTranslateConfig({
|
||||||
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
|
})
|
||||||
|
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
import * as Highcharts from 'highcharts'
|
||||||
|
import Exporting from 'highcharts/modules/exporting'
|
||||||
|
Exporting(Highcharts)
|
||||||
|
import StockChart from 'highcharts/modules/stock'
|
||||||
|
StockChart(Highcharts)
|
||||||
|
import 'highcharts/highcharts-more.js'
|
||||||
|
import 'highcharts/modules/accessibility.js'
|
||||||
|
import 'highcharts/modules/boost.js'
|
||||||
|
import 'highcharts/modules/data.js'
|
||||||
|
import 'highcharts/modules/export-data.js'
|
||||||
|
import 'highcharts/modules/offline-exporting.js'
|
||||||
|
|
||||||
|
let btcChartDialog
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class BtcCharts extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoadingTradesChart: { type: Boolean },
|
||||||
|
btcTrades: { type: Array },
|
||||||
|
btcPrice: { type: Array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
.loadingContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trades-chart {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
color: var(--black);
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 30vh;
|
||||||
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
height: 38vh;
|
||||||
|
width: 83vw;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-loading-wrapper {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.btcTrades = []
|
||||||
|
this.btcPrice = []
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<paper-dialog id="loadChartDialog" class="chart-loading-wrapper" modal>
|
||||||
|
<div class="loadingContainer" style="display:${this.isLoadingTradesChart ? 'inline-block' : 'none'}">
|
||||||
|
<span style="color: var(--black);">${translate("login.loading")}</span>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
<paper-dialog id="btcChartDialog" class="chart-info-wrapper">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div id='btcStockPriceContainer' class='trades-chart'></div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.changeTheme()
|
||||||
|
this.changeLanguage()
|
||||||
|
|
||||||
|
window.addEventListener('storage', () => {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
|
||||||
|
use(checkLanguage)
|
||||||
|
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTradesChart() {
|
||||||
|
this.isLoadingTradesChart = true
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').open()
|
||||||
|
await this.getBtcTrades()
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').close()
|
||||||
|
this.enableBtcStockPriceChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBtcTrades() {
|
||||||
|
let currentBtcTimestamp = Date.now()
|
||||||
|
const monthBackBtc = currentBtcTimestamp - 31556952000
|
||||||
|
await parentEpml.request("apiCall", { url: `/crosschain/trades?foreignBlockchain=BITCOIN&minimumTimestamp=${monthBackBtc}&limit=0&reverse=false` }).then((res) => {
|
||||||
|
this.btcTrades = res
|
||||||
|
})
|
||||||
|
|
||||||
|
this.btcPrice = this.btcTrades.map(item => {
|
||||||
|
const btcSellPrice = this.round(parseFloat(item.foreignAmount) / parseFloat(item.qortAmount))
|
||||||
|
return [item.tradeTimestamp, parseFloat(btcSellPrice)]
|
||||||
|
}).filter(item => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
enableBtcStockPriceChart() {
|
||||||
|
const btcStockPriceData = this.btcPrice
|
||||||
|
const header = 'QORT / BTC ' + get("tradepage.tchange49")
|
||||||
|
Highcharts.stockChart(this.shadowRoot.querySelector('#btcStockPriceContainer'), {
|
||||||
|
accessibility: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
selected: 1,
|
||||||
|
labelStyle: {color: 'var(--black)'},
|
||||||
|
inputStyle: {color: '#03a9f4'}
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: header,
|
||||||
|
style: {color: 'var(--black)'}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'QORT / BTC',
|
||||||
|
data: btcStockPriceData,
|
||||||
|
tooltip: {
|
||||||
|
valueDecimals: 8
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.loadTradesChart()
|
||||||
|
this.shadowRoot.getElementById('btcChartDialog').open()
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage() {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
|
if (checkLanguage === null || checkLanguage.length === 0) {
|
||||||
|
localStorage.setItem('qortalLanguage', 'us')
|
||||||
|
use('us')
|
||||||
|
} else {
|
||||||
|
use(checkLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('btc-charts', BtcCharts)
|
||||||
|
|
||||||
|
const chartsbtc = document.createElement('btc-charts')
|
||||||
|
btcChartDialog = document.body.appendChild(chartsbtc)
|
||||||
|
|
||||||
|
export default btcChartDialog
|
214
qortal-ui-plugins/plugins/core/trade-portal/charts/dgb-charts.js
Normal file
214
qortal-ui-plugins/plugins/core/trade-portal/charts/dgb-charts.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { render } from 'lit/html.js'
|
||||||
|
import { Epml } from '../../../../epml.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
registerTranslateConfig({
|
||||||
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
|
})
|
||||||
|
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
import * as Highcharts from 'highcharts'
|
||||||
|
import Exporting from 'highcharts/modules/exporting'
|
||||||
|
Exporting(Highcharts)
|
||||||
|
import StockChart from 'highcharts/modules/stock'
|
||||||
|
StockChart(Highcharts)
|
||||||
|
import 'highcharts/highcharts-more.js'
|
||||||
|
import 'highcharts/modules/accessibility.js'
|
||||||
|
import 'highcharts/modules/boost.js'
|
||||||
|
import 'highcharts/modules/data.js'
|
||||||
|
import 'highcharts/modules/export-data.js'
|
||||||
|
import 'highcharts/modules/offline-exporting.js'
|
||||||
|
|
||||||
|
let dgbChartDialog
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class DgbCharts extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoadingTradesChart: { type: Boolean },
|
||||||
|
dgbTrades: { type: Array },
|
||||||
|
dgbPrice: { type: Array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
.loadingContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trades-chart {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
color: var(--black);
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 30vh;
|
||||||
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
height: 38vh;
|
||||||
|
width: 83vw;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-loading-wrapper {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.dgbTrades = []
|
||||||
|
this.dgbPrice = []
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<paper-dialog id="loadChartDialog" class="chart-loading-wrapper" modal>
|
||||||
|
<div class="loadingContainer" style="display:${this.isLoadingTradesChart ? 'inline-block' : 'none'}">
|
||||||
|
<span style="color: var(--black);">${translate("login.loading")}</span>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
<paper-dialog id="dgbChartDialog" class="chart-info-wrapper">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div id='dgbStockPriceContainer' class='trades-chart'></div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.changeTheme()
|
||||||
|
this.changeLanguage()
|
||||||
|
|
||||||
|
window.addEventListener('storage', () => {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
|
||||||
|
use(checkLanguage)
|
||||||
|
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTradesChart() {
|
||||||
|
this.isLoadingTradesChart = true
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').open()
|
||||||
|
await this.getDgbTrades()
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').close()
|
||||||
|
this.enableDgbStockPriceChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDgbTrades() {
|
||||||
|
let currentDgbTimestamp = Date.now()
|
||||||
|
const monthBackDgb = currentDgbTimestamp - 31556952000
|
||||||
|
await parentEpml.request("apiCall", { url: `/crosschain/trades?foreignBlockchain=DIGIBYTE&minimumTimestamp=${monthBackDgb}&limit=0&reverse=false` }).then((res) => {
|
||||||
|
this.dgbTrades = res
|
||||||
|
})
|
||||||
|
this.dgbPrice = this.dgbTrades.map(item => {
|
||||||
|
const dgbSellPrice = this.round(parseFloat(item.foreignAmount) / parseFloat(item.qortAmount))
|
||||||
|
return [item.tradeTimestamp, parseFloat(dgbSellPrice)]
|
||||||
|
}).filter(item => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
enableDgbStockPriceChart() {
|
||||||
|
const dgbStockPriceData = this.dgbPrice
|
||||||
|
const header = 'QORT / DGB ' + get("tradepage.tchange49")
|
||||||
|
Highcharts.stockChart(this.shadowRoot.querySelector('#dgbStockPriceContainer'), {
|
||||||
|
accessibility: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
selected: 1,
|
||||||
|
labelStyle: {color: 'var(--black)'},
|
||||||
|
inputStyle: {color: '#03a9f4'}
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: header,
|
||||||
|
style: {color: 'var(--black)'}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'QORT / DGB',
|
||||||
|
data: dgbStockPriceData,
|
||||||
|
tooltip: {
|
||||||
|
valueDecimals: 8
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.loadTradesChart()
|
||||||
|
this.shadowRoot.getElementById('dgbChartDialog').open()
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage() {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
|
if (checkLanguage === null || checkLanguage.length === 0) {
|
||||||
|
localStorage.setItem('qortalLanguage', 'us')
|
||||||
|
use('us')
|
||||||
|
} else {
|
||||||
|
use(checkLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('dgb-charts', DgbCharts)
|
||||||
|
|
||||||
|
const chartsdgb = document.createElement('dgb-charts')
|
||||||
|
dgbChartDialog = document.body.appendChild(chartsdgb)
|
||||||
|
|
||||||
|
export default dgbChartDialog
|
@ -0,0 +1,214 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { render } from 'lit/html.js'
|
||||||
|
import { Epml } from '../../../../epml.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
registerTranslateConfig({
|
||||||
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
|
})
|
||||||
|
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
import * as Highcharts from 'highcharts'
|
||||||
|
import Exporting from 'highcharts/modules/exporting'
|
||||||
|
Exporting(Highcharts)
|
||||||
|
import StockChart from 'highcharts/modules/stock'
|
||||||
|
StockChart(Highcharts)
|
||||||
|
import 'highcharts/highcharts-more.js'
|
||||||
|
import 'highcharts/modules/accessibility.js'
|
||||||
|
import 'highcharts/modules/boost.js'
|
||||||
|
import 'highcharts/modules/data.js'
|
||||||
|
import 'highcharts/modules/export-data.js'
|
||||||
|
import 'highcharts/modules/offline-exporting.js'
|
||||||
|
|
||||||
|
let dogeChartDialog
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class DogeCharts extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoadingTradesChart: { type: Boolean },
|
||||||
|
dogeTrades: { type: Array },
|
||||||
|
dogePrice: { type: Array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
.loadingContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trades-chart {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
color: var(--black);
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 30vh;
|
||||||
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
height: 38vh;
|
||||||
|
width: 83vw;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-loading-wrapper {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.dogeTrades = []
|
||||||
|
this.dogePrice = []
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<paper-dialog id="loadChartDialog" class="chart-loading-wrapper" modal>
|
||||||
|
<div class="loadingContainer" style="display:${this.isLoadingTradesChart ? 'inline-block' : 'none'}">
|
||||||
|
<span style="color: var(--black);">${translate("login.loading")}</span>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
<paper-dialog id="dogeChartDialog" class="chart-info-wrapper">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div id='dogeStockPriceContainer' class='trades-chart'></div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.changeTheme()
|
||||||
|
this.changeLanguage()
|
||||||
|
|
||||||
|
window.addEventListener('storage', () => {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
|
||||||
|
use(checkLanguage)
|
||||||
|
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTradesChart() {
|
||||||
|
this.isLoadingTradesChart = true
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').open()
|
||||||
|
await this.getDogeTrades()
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').close()
|
||||||
|
this.enableDogeStockPriceChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getDogeTrades() {
|
||||||
|
let currentDogeTimestamp = Date.now()
|
||||||
|
const monthBackDoge = currentDogeTimestamp - 31556952000
|
||||||
|
await parentEpml.request("apiCall", { url: `/crosschain/trades?foreignBlockchain=DOGECOIN&minimumTimestamp=${monthBackDoge}&limit=0&reverse=false` }).then((res) => {
|
||||||
|
this.dogeTrades = res
|
||||||
|
})
|
||||||
|
this.dogePrice = this.dogeTrades.map(item => {
|
||||||
|
const dogeSellPrice = this.round(parseFloat(item.foreignAmount) / parseFloat(item.qortAmount))
|
||||||
|
return [item.tradeTimestamp, parseFloat(dogeSellPrice)]
|
||||||
|
}).filter(item => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
enableDogeStockPriceChart() {
|
||||||
|
const dogeStockPriceData = this.dogePrice
|
||||||
|
const header = 'QORT / DOGE ' + get("tradepage.tchange49")
|
||||||
|
Highcharts.stockChart(this.shadowRoot.querySelector('#dogeStockPriceContainer'), {
|
||||||
|
accessibility: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
selected: 1,
|
||||||
|
labelStyle: {color: 'var(--black)'},
|
||||||
|
inputStyle: {color: '#03a9f4'}
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: header,
|
||||||
|
style: {color: 'var(--black)'}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'QORT / DOGE',
|
||||||
|
data: dogeStockPriceData,
|
||||||
|
tooltip: {
|
||||||
|
valueDecimals: 8
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.loadTradesChart()
|
||||||
|
this.shadowRoot.getElementById('dogeChartDialog').open()
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage() {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
|
if (checkLanguage === null || checkLanguage.length === 0) {
|
||||||
|
localStorage.setItem('qortalLanguage', 'us')
|
||||||
|
use('us')
|
||||||
|
} else {
|
||||||
|
use(checkLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('doge-charts', DogeCharts)
|
||||||
|
|
||||||
|
const chartsdoge = document.createElement('doge-charts')
|
||||||
|
dogeChartDialog = document.body.appendChild(chartsdoge)
|
||||||
|
|
||||||
|
export default dogeChartDialog
|
214
qortal-ui-plugins/plugins/core/trade-portal/charts/ltc-charts.js
Normal file
214
qortal-ui-plugins/plugins/core/trade-portal/charts/ltc-charts.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { render } from 'lit/html.js'
|
||||||
|
import { Epml } from '../../../../epml.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
registerTranslateConfig({
|
||||||
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
|
})
|
||||||
|
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
import * as Highcharts from 'highcharts'
|
||||||
|
import Exporting from 'highcharts/modules/exporting'
|
||||||
|
Exporting(Highcharts)
|
||||||
|
import StockChart from 'highcharts/modules/stock'
|
||||||
|
StockChart(Highcharts)
|
||||||
|
import 'highcharts/highcharts-more.js'
|
||||||
|
import 'highcharts/modules/accessibility.js'
|
||||||
|
import 'highcharts/modules/boost.js'
|
||||||
|
import 'highcharts/modules/data.js'
|
||||||
|
import 'highcharts/modules/export-data.js'
|
||||||
|
import 'highcharts/modules/offline-exporting.js'
|
||||||
|
|
||||||
|
let ltcChartDialog
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class LtcCharts extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoadingTradesChart: { type: Boolean },
|
||||||
|
ltcTrades: { type: Array },
|
||||||
|
ltcPrice: { type: Array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
.loadingContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trades-chart {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
color: var(--black);
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 30vh;
|
||||||
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
height: 38vh;
|
||||||
|
width: 83vw;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-loading-wrapper {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.ltcTrades = []
|
||||||
|
this.ltcPrice = []
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<paper-dialog id="loadChartDialog" class="chart-loading-wrapper" modal>
|
||||||
|
<div class="loadingContainer" style="display:${this.isLoadingTradesChart ? 'inline-block' : 'none'}">
|
||||||
|
<span style="color: var(--black);">${translate("login.loading")}</span>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
<paper-dialog id="ltcChartDialog" class="chart-info-wrapper">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div id='ltcStockPriceContainer' class='trades-chart'></div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.changeTheme()
|
||||||
|
this.changeLanguage()
|
||||||
|
|
||||||
|
window.addEventListener('storage', () => {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
|
||||||
|
use(checkLanguage)
|
||||||
|
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTradesChart() {
|
||||||
|
this.isLoadingTradesChart = true
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').open()
|
||||||
|
await this.getLtcTrades()
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').close()
|
||||||
|
this.enableLtcStockPriceChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLtcTrades() {
|
||||||
|
let currentLtcTimestamp = Date.now()
|
||||||
|
const monthBackLtc = currentLtcTimestamp - 31556952000
|
||||||
|
await parentEpml.request("apiCall", { url: `/crosschain/trades?foreignBlockchain=LITECOIN&minimumTimestamp=${monthBackLtc}&limit=0&reverse=false` }).then((res) => {
|
||||||
|
this.ltcTrades = res
|
||||||
|
})
|
||||||
|
this.ltcPrice = this.ltcTrades.map(item => {
|
||||||
|
const ltcSellPrice = this.round(parseFloat(item.foreignAmount) / parseFloat(item.qortAmount))
|
||||||
|
return [item.tradeTimestamp, parseFloat(ltcSellPrice)]
|
||||||
|
}).filter(item => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
enableLtcStockPriceChart() {
|
||||||
|
const ltcStockPriceData = this.ltcPrice
|
||||||
|
const header = 'QORT / LTC ' + get("tradepage.tchange49")
|
||||||
|
Highcharts.stockChart(this.shadowRoot.querySelector('#ltcStockPriceContainer'), {
|
||||||
|
accessibility: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
selected: 1,
|
||||||
|
labelStyle: {color: 'var(--black)'},
|
||||||
|
inputStyle: {color: '#03a9f4'}
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: header,
|
||||||
|
style: {color: 'var(--black)'}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'QORT / LTC',
|
||||||
|
data: ltcStockPriceData,
|
||||||
|
tooltip: {
|
||||||
|
valueDecimals: 8
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.loadTradesChart()
|
||||||
|
this.shadowRoot.getElementById('ltcChartDialog').open()
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage() {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
|
if (checkLanguage === null || checkLanguage.length === 0) {
|
||||||
|
localStorage.setItem('qortalLanguage', 'us')
|
||||||
|
use('us')
|
||||||
|
} else {
|
||||||
|
use(checkLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('ltc-charts', LtcCharts)
|
||||||
|
|
||||||
|
const chartsltc = document.createElement('ltc-charts')
|
||||||
|
ltcChartDialog = document.body.appendChild(chartsltc)
|
||||||
|
|
||||||
|
export default ltcChartDialog
|
214
qortal-ui-plugins/plugins/core/trade-portal/charts/rvn-charts.js
Normal file
214
qortal-ui-plugins/plugins/core/trade-portal/charts/rvn-charts.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
import { LitElement, html, css } from 'lit'
|
||||||
|
import { render } from 'lit/html.js'
|
||||||
|
import { Epml } from '../../../../epml.js'
|
||||||
|
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
|
||||||
|
|
||||||
|
registerTranslateConfig({
|
||||||
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
|
})
|
||||||
|
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
import * as Highcharts from 'highcharts'
|
||||||
|
import Exporting from 'highcharts/modules/exporting'
|
||||||
|
Exporting(Highcharts)
|
||||||
|
import StockChart from 'highcharts/modules/stock'
|
||||||
|
StockChart(Highcharts)
|
||||||
|
import 'highcharts/highcharts-more.js'
|
||||||
|
import 'highcharts/modules/accessibility.js'
|
||||||
|
import 'highcharts/modules/boost.js'
|
||||||
|
import 'highcharts/modules/data.js'
|
||||||
|
import 'highcharts/modules/export-data.js'
|
||||||
|
import 'highcharts/modules/offline-exporting.js'
|
||||||
|
|
||||||
|
let rvnChartDialog
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class RvnCharts extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoadingTradesChart: { type: Boolean },
|
||||||
|
rvnTrades: { type: Array },
|
||||||
|
rvnPrice: { type: Array }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
.loadingContainer {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trades-chart {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 25px;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
margin: auto;
|
||||||
|
color: var(--black);
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px;
|
||||||
|
height: 30vh;
|
||||||
|
width: 80vw;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-info-wrapper {
|
||||||
|
background: transparent;
|
||||||
|
height: 38vh;
|
||||||
|
width: 83vw;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-loading-wrapper {
|
||||||
|
color: var(--black);
|
||||||
|
background: var(--white);
|
||||||
|
border: 1px solid var(--black);
|
||||||
|
border-radius: 15px;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.rvnTrades = []
|
||||||
|
this.rvnPrice = []
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<paper-dialog id="loadChartDialog" class="chart-loading-wrapper" modal>
|
||||||
|
<div class="loadingContainer" style="display:${this.isLoadingTradesChart ? 'inline-block' : 'none'}">
|
||||||
|
<span style="color: var(--black);">${translate("login.loading")}</span>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
<paper-dialog id="rvnChartDialog" class="chart-info-wrapper">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div id='rvnStockPriceContainer' class='trades-chart'></div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.changeTheme()
|
||||||
|
this.changeLanguage()
|
||||||
|
|
||||||
|
window.addEventListener('storage', () => {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
|
||||||
|
use(checkLanguage)
|
||||||
|
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadTradesChart() {
|
||||||
|
this.isLoadingTradesChart = true
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').open()
|
||||||
|
await this.getRvnTrades()
|
||||||
|
this.isLoadingTradesChart = false
|
||||||
|
this.shadowRoot.getElementById('loadChartDialog').close()
|
||||||
|
this.enableRvnStockPriceChart()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRvnTrades() {
|
||||||
|
let currentRvnTimestamp = Date.now()
|
||||||
|
const monthBackRvn = currentRvnTimestamp - 31556952000
|
||||||
|
await parentEpml.request("apiCall", { url: `/crosschain/trades?foreignBlockchain=RAVENCOIN&minimumTimestamp=${monthBackRvn}&limit=0&reverse=false` }).then((res) => {
|
||||||
|
this.rvnTrades = res
|
||||||
|
})
|
||||||
|
this.rvnPrice = this.rvnTrades.map(item => {
|
||||||
|
const rvnSellPrice = this.round(parseFloat(item.foreignAmount) / parseFloat(item.qortAmount))
|
||||||
|
return [item.tradeTimestamp, parseFloat(rvnSellPrice)]
|
||||||
|
}).filter(item => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
enableRvnStockPriceChart() {
|
||||||
|
const rvnStockPriceData = this.rvnPrice
|
||||||
|
const header = 'QORT / RVN ' + get("tradepage.tchange49")
|
||||||
|
Highcharts.stockChart(this.shadowRoot.querySelector('#rvnStockPriceContainer'), {
|
||||||
|
accessibility: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
credits: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
rangeSelector: {
|
||||||
|
selected: 1,
|
||||||
|
labelStyle: {color: 'var(--black)'},
|
||||||
|
inputStyle: {color: '#03a9f4'}
|
||||||
|
},
|
||||||
|
chart: {
|
||||||
|
backgroundColor: 'transparent'
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: header,
|
||||||
|
style: {color: 'var(--black)'}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
labels: {
|
||||||
|
style: {
|
||||||
|
color: '#03a9f4'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: 'QORT / RVN',
|
||||||
|
data: rvnStockPriceData,
|
||||||
|
tooltip: {
|
||||||
|
valueDecimals: 8
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async open() {
|
||||||
|
await this.loadTradesChart()
|
||||||
|
this.shadowRoot.getElementById('rvnChartDialog').open()
|
||||||
|
}
|
||||||
|
|
||||||
|
changeTheme() {
|
||||||
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
|
this.theme = (checkTheme === 'dark') ? 'dark' : 'light'
|
||||||
|
document.querySelector('html').setAttribute('theme', this.theme);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeLanguage() {
|
||||||
|
const checkLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
|
if (checkLanguage === null || checkLanguage.length === 0) {
|
||||||
|
localStorage.setItem('qortalLanguage', 'us')
|
||||||
|
use('us')
|
||||||
|
} else {
|
||||||
|
use(checkLanguage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
let result = (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('rvn-charts', RvnCharts)
|
||||||
|
|
||||||
|
const chartsrvn = document.createElement('rvn-charts')
|
||||||
|
rvnChartDialog = document.body.appendChild(chartsrvn)
|
||||||
|
|
||||||
|
export default rvnChartDialog
|
@ -21,6 +21,12 @@ import '@polymer/paper-icon-button/paper-icon-button.js'
|
|||||||
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
import '@vaadin/grid'
|
import '@vaadin/grid'
|
||||||
import '@vaadin/grid/vaadin-grid-sorter'
|
import '@vaadin/grid/vaadin-grid-sorter'
|
||||||
|
import chartsbtc from './charts/btc-charts.js'
|
||||||
|
import chartsltc from './charts/ltc-charts.js'
|
||||||
|
import chartsdoge from './charts/doge-charts.js'
|
||||||
|
import chartsdgb from './charts/dgb-charts.js'
|
||||||
|
import chartsrvn from './charts/rvn-charts.js'
|
||||||
|
import chartsarrr from './charts/arrr-charts.js'
|
||||||
|
|
||||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
@ -1162,6 +1168,9 @@ class TradePortal extends LitElement {
|
|||||||
<mwc-list-item value="RAVENCOIN"><span class="coinName rvn" style="color: var(--black);">QORT / RVN</span></mwc-list-item>
|
<mwc-list-item value="RAVENCOIN"><span class="coinName rvn" style="color: var(--black);">QORT / RVN</span></mwc-list-item>
|
||||||
<mwc-list-item value="PIRATECHAIN"><span class="coinName arrr" style="color: var(--black);">QORT / ARRR</span></mwc-list-item>
|
<mwc-list-item value="PIRATECHAIN"><span class="coinName arrr" style="color: var(--black);">QORT / ARRR</span></mwc-list-item>
|
||||||
</mwc-select>
|
</mwc-select>
|
||||||
|
<div style="padding-left: 25px; padding-top: 15px;">
|
||||||
|
${this.chartShowCoin()}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="trade-portal">
|
<div id="trade-portal">
|
||||||
<div id="first-trade-section">
|
<div id="first-trade-section">
|
||||||
@ -1412,6 +1421,31 @@ class TradePortal extends LitElement {
|
|||||||
return html`<span class="warning-text">NOT ENOUGH ${this.listedCoins.get(this.selectedCoin).coinCode}</span>`
|
return html`<span class="warning-text">NOT ENOUGH ${this.listedCoins.get(this.selectedCoin).coinCode}</span>`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chartShowCoin() {
|
||||||
|
switch(this.listedCoins.get(this.selectedCoin).coinCode) {
|
||||||
|
case "BTC":
|
||||||
|
return html`<mwc-button dense unelevated label="BTC ${translate("tradepage.tchange49")}" @click=${() => chartsbtc.open()}></mwc-button>`
|
||||||
|
break
|
||||||
|
case "LTC":
|
||||||
|
return html`<mwc-button dense unelevated label="LTC ${translate("tradepage.tchange49")}" @click=${() => chartsltc.open()}></mwc-button>`
|
||||||
|
break
|
||||||
|
case "DOGE":
|
||||||
|
return html`<mwc-button dense unelevated label="DOGE ${translate("tradepage.tchange49")}" @click=${() => chartsdoge.open()}></mwc-button>`
|
||||||
|
break
|
||||||
|
case "DGB":
|
||||||
|
return html`<mwc-button dense unelevated label="DGB ${translate("tradepage.tchange49")}" @click=${() => chartsdgb.open()}></mwc-button>`
|
||||||
|
break
|
||||||
|
case "RVN":
|
||||||
|
return html`<mwc-button dense unelevated label="RVN ${translate("tradepage.tchange49")}" @click=${() => chartsrvn.open()}></mwc-button>`
|
||||||
|
break
|
||||||
|
case "ARRR":
|
||||||
|
return html`<mwc-button dense unelevated label="ARRR ${translate("tradepage.tchange49")}" @click=${() => chartsarrr.open()}></mwc-button>`
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
exchangeRateQort() {
|
exchangeRateQort() {
|
||||||
switch(this.listedCoins.get(this.selectedCoin).coinCode) {
|
switch(this.listedCoins.get(this.selectedCoin).coinCode) {
|
||||||
case "BTC":
|
case "BTC":
|
||||||
|
@ -10,8 +10,8 @@ registerTranslateConfig({
|
|||||||
import '../components/ButtonIconCopy.js'
|
import '../components/ButtonIconCopy.js'
|
||||||
import '../components/QortalQrcodeGenerator.js'
|
import '../components/QortalQrcodeGenerator.js'
|
||||||
import '../components/frag-file-input.js'
|
import '../components/frag-file-input.js'
|
||||||
|
import '../components/time-elements/index.js'
|
||||||
import FileSaver from 'file-saver'
|
import FileSaver from 'file-saver'
|
||||||
import '@github/time-elements'
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-checkbox'
|
import '@material/mwc-checkbox'
|
||||||
import '@material/mwc-dialog'
|
import '@material/mwc-dialog'
|
||||||
|
21
qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js
Normal file
21
qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { Epml } from '../../epml.js';
|
||||||
|
import { cropAddress } from './cropAddress.js';
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
export const getUserNameFromAddress = async (address) => {
|
||||||
|
try {
|
||||||
|
const getNames = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
url: `/names/address/${address}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (Array.isArray(getNames) && getNames.length > 0 ) {
|
||||||
|
return getNames[0].name;
|
||||||
|
} else {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user