Merge remote-tracking branch 'upstream/master' into feature/implement-logic-edit-reply-messages
This commit is contained in:
commit
50cd17caba
@ -128,7 +128,11 @@
|
||||
"snack2":"UI mit Knoten verbunden",
|
||||
"snack3":"Benutzerdefinierter Knoten erfolgreich hinzugefügt und gespeichert",
|
||||
"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":{
|
||||
"blockheight":"Blockhöhe",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Fortsetzen",
|
||||
"save":"Speichern",
|
||||
"balance":"Guthaben",
|
||||
"balances":"IHR WALLET-GUTHABEN"
|
||||
"balances":"IHR WALLET-GUTHABEN",
|
||||
"update":"AKTUALISIERE WALLET-GUTHABEN"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Prägekonten können nicht abgerufen werden",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTO KAUFEN MIT",
|
||||
"tchange46":"AUTOKAUF",
|
||||
"tchange47":"Verkaufe für diesen Preis",
|
||||
"tchange48":"NICHT GENUG"
|
||||
"tchange48":"NICHT GENUG",
|
||||
"tchange49":"Preisdiagramm"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Belohnungsanteile",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Beitreten",
|
||||
"gchange52":"Administrator",
|
||||
"gchange53":"Mitglied",
|
||||
"gchange54":"Mitglieder"
|
||||
"gchange54":"Mitglieder",
|
||||
"gchange55":"Private Gruppe suchen",
|
||||
"gchange56":"Zu suchender Gruppenname",
|
||||
"gchange57":"Privater Gruppenname nicht gefunden",
|
||||
"gchange58":"Beachten Sie, dass der Gruppenname genau übereinstimmen muss."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Rätsel",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"Beim Drücken auf Bestätigen wird die Anfrage zum Abbrechen der Einladung gesendet!",
|
||||
"mg50":"Kommt bald...",
|
||||
"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",
|
||||
"snack3":"Nodo personalizado agregado y guardado con éxito",
|
||||
"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":{
|
||||
"blockheight":"Altura del Bloque",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Continuar",
|
||||
"save":"Guardar",
|
||||
"balance":"Saldo",
|
||||
"balances":"LOS SALDOS DE TU BILLETERA"
|
||||
"balances":"LOS SALDOS DE TU BILLETERA",
|
||||
"update":"ACTUALIZAR SALDOS DE CARTERA"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"No se pueden obtener cuentas de acuñación",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTO COMPRAR CON",
|
||||
"tchange46":"COMPRA AUTOMÁTICA",
|
||||
"tchange47":"Vender por este precio",
|
||||
"tchange48":"NO ES SUFICIENTE"
|
||||
"tchange48":"NO ES SUFICIENTE",
|
||||
"tchange49":"Gráfico de precios"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Rewardshares",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Unirse",
|
||||
"gchange52":"Aministrador",
|
||||
"gchange53":"Miembro",
|
||||
"gchange54":"Miembros"
|
||||
"gchange54":"Miembros",
|
||||
"gchange55":"Buscar grupo privado",
|
||||
"gchange56":"Nombre del grupo a buscar",
|
||||
"gchange57":"Nombre de grupo privado no encontrado",
|
||||
"gchange58":"Tenga en cuenta que el nombre del grupo debe coincidir exactamente."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Rompecabezas",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"¡Al presionar confirmar, se enviará la solicitud de cancelación de invitación!",
|
||||
"mg50":"Próximamente...",
|
||||
"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",
|
||||
"snack3":"Noeud personnalisé ajouté et enregistré avec succès",
|
||||
"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":{
|
||||
"blockheight":"Hauteur de bloc",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Continuer",
|
||||
"save":"Sauvegarder",
|
||||
"balance":"Solde",
|
||||
"balances":"VOS SOLDES DE PORTEFEUILLE"
|
||||
"balances":"VOS SOLDES DE PORTEFEUILLE",
|
||||
"update":"METTRE À JOUR LES SOLDES DES PORTEFEUILLES"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Impossible de récupérer les comptes de frappe",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"ACHAT AUTO AVEC",
|
||||
"tchange46":"ACHAT AUTOMATIQUE",
|
||||
"tchange47":"Vendre à ce prix",
|
||||
"tchange48":"PAS ASSEZ"
|
||||
"tchange48":"PAS ASSEZ",
|
||||
"tchange49":"Tableau des prix"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Récompenses",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Rejoindre",
|
||||
"gchange52":"Admin",
|
||||
"gchange53":"Membre",
|
||||
"gchange54":"Membres"
|
||||
"gchange54":"Membres",
|
||||
"gchange55":"Rechercher un groupe privé",
|
||||
"gchange56":"Nom du groupe à rechercher",
|
||||
"gchange57":"Nom de groupe privé introuvable",
|
||||
"gchange58":"Notez que le nom du groupe doit correspondre exactement."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Puzzles",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"En appuyant sur confirmer, la demande d'annulation d'invitation sera envoyée !",
|
||||
"mg50":"Bientôt disponible...",
|
||||
"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":"यूआई नोड से जुड़ा",
|
||||
"snack3":"कस्टम नोड को सफलतापूर्वक जोड़ा और सहेजा गया",
|
||||
"snack4":"नोड्स सफलतापूर्वक सहेजे गए",
|
||||
"snack5":"नोड्स सफलतापूर्वक आयात किए गए"
|
||||
"snack5":"नोड्स सफलतापूर्वक आयात किए गए",
|
||||
"exp1":"निजी मास्टर कुंजी निर्यात करें",
|
||||
"exp2":"निर्यात मास्टर कुंजी",
|
||||
"exp3":"निर्यात",
|
||||
"exp4":"निजी मास्टर कुंजी का बैकअप लेने के लिए कृपया एक वॉलेट चुनें।"
|
||||
},
|
||||
"appinfo":{
|
||||
"blockheight":"ब्लॉक ऊँचाई",
|
||||
@ -156,7 +160,8 @@
|
||||
"continue":"जारी रखें",
|
||||
"save":"सहेजें",
|
||||
"balance":"संतुलन",
|
||||
"balances":"आपका वॉलेट बैलेंस"
|
||||
"balances":"आपका वॉलेट बैलेंस",
|
||||
"update":"अपडेट वॉलेट बैलेंस"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"खनन खाते नहीं लाए जा सकते",
|
||||
@ -329,7 +334,8 @@
|
||||
"tchange45":"ऑटो के साथ खरीदें",
|
||||
"tchange46":"ऑटो खरीदें",
|
||||
"tchange47":"इस कीमत पर बेचें",
|
||||
"tchange48":"पर्याप्त नहीं"
|
||||
"tchange48":"पर्याप्त नहीं",
|
||||
"tchange49":"मूल्य चार्ट"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"रिवॉर्डशेयर",
|
||||
@ -607,7 +613,11 @@
|
||||
"gchange51":"शामिल हों",
|
||||
"gchange52":"व्यवस्थापक",
|
||||
"gchange53":"सदस्य",
|
||||
"gchange54":"सदस्यों"
|
||||
"gchange54":"सदस्यों",
|
||||
"gchange55":"निजी समूह खोजें",
|
||||
"gchange56":"खोजने के लिए समूह का नाम",
|
||||
"gchange57":"निजी समूह का नाम नहीं मिला",
|
||||
"gchange58":"ध्यान दें कि समूह का नाम सटीक मेल खाना चाहिए।"
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"पहेलि",
|
||||
@ -794,7 +804,16 @@
|
||||
"mg48":"क्या आप वाकई इस सदस्य के लिए आमंत्रण रद्द करना चाहते हैं?",
|
||||
"mg49":"पुष्टि करें दबाने पर, रद्द आमंत्रण अनुरोध भेजा जाएगा!",
|
||||
"mg50":"जल्द ही आ रहा है ...",
|
||||
"mg51": "न्यूनतम 3 वर्ण / अधिकतम 32 वर्ण",
|
||||
"mg52": "अधिकतम 128 वर्ण"
|
||||
"mg51":"न्यूनतम 3 वर्ण / अधिकतम 32 वर्ण",
|
||||
"mg52":"अधिकतम 128 वर्ण",
|
||||
"mg53":"आपका खुला शामिल होने का अनुरोध",
|
||||
"mg54":"नो ओपन जॉइन रिक्वेस्ट",
|
||||
"mg55":"क्या आप निश्चित रूप से इस सदस्य के शामिल होने के अनुरोध को स्वीकार करना चाहते हैं?",
|
||||
"mg56":"पुष्टि करें दबाने पर, स्वीकार करने का अनुरोध भेजा जाएगा!",
|
||||
"mg57":"जुड़ने का अनुरोध सफलतापूर्वक स्वीकार किया गया",
|
||||
"mg58":"कुछ गलत हो गया",
|
||||
"mg59":"रद्द करें शामिल होने का अनुरोध सफलतापूर्वक स्वीकार किया गया",
|
||||
"mg60":"क्या आप निश्चित रूप से इस सदस्य के शामिल होने के अनुरोध को रद्द करना चाहते हैं?",
|
||||
"mg61":"पुष्टि करें दबाने पर, रद्द करने का अनुरोध भेजा जाएगा!"
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,11 @@
|
||||
"snack2":"UI spojen na čvor",
|
||||
"snack3":"Uspješno dodan i spremljen prilagođeni čvor",
|
||||
"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":{
|
||||
"blockheight":"Visina bloka",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Nastavi",
|
||||
"save":"Spremi",
|
||||
"balance":"Kreditna",
|
||||
"balances":"VAŠ NOVČANIK JE NA SALJU"
|
||||
"balances":"VAŠ NOVČANIK JE NA SALJU",
|
||||
"update":"AŽURIRAJTE STANJE NOVČANIKA"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Nije moguće dohvatiti račune za kovanje",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTO KUPITE SA",
|
||||
"tchange46":"AUTO OTKUP",
|
||||
"tchange47":"Prodaj za ovu cijenu",
|
||||
"tchange48":"NEDOVOLJNO"
|
||||
"tchange48":"NEDOVOLJNO",
|
||||
"tchange49":"Grafikon cijena"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Nagradni udio (Rewardshares)",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Pridruži",
|
||||
"gchange52":"Admin",
|
||||
"gchange53":"Član",
|
||||
"gchange54":"Članovi"
|
||||
"gchange54":"Članovi",
|
||||
"gchange55":"Traži privatnu grupu",
|
||||
"gchange56":"Naziv grupe za pretraživanje",
|
||||
"gchange57":"Ime privatne grupe nije pronađeno",
|
||||
"gchange58":"Imajte na umu da se naziv grupe mora točno podudarati."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Zagonetke",
|
||||
@ -793,7 +803,16 @@
|
||||
"mg48":"Jeste li sigurni da želite otkazati poziv za ovog člana?",
|
||||
"mg49":"Pritiskom na potvrdu, zahtjev za pozivnicu za otkazivanje bit će poslan!",
|
||||
"mg50":"Uskoro...",
|
||||
"mg51": "Minimalno 3 znaka / Maksimalno 32 znaka",
|
||||
"mg52": "Maksimalno 128 znakova"
|
||||
"mg51":"Minimalno 3 znaka / Maksimalno 32 znaka",
|
||||
"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",
|
||||
"snack3":"Az egyéni csomópont sikeresen hozzáadva és mentve",
|
||||
"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":{
|
||||
"blockheight":"Blokk Magassága",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Folytatódik/folytatáshoz",
|
||||
"save":"Mentéshez",
|
||||
"balance":"Hitel",
|
||||
"balances":"A PÉNZTÁRCSA EGYENLEGEK"
|
||||
"balances":"A PÉNZTÁRCSA EGYENLEGEK",
|
||||
"update":"FRISSÍTSE A PÉNZTÁRCSA-EGYENLEGEKET"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Nem lehet lekérni a pénzverési számlákat",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTOMATIKUS VÁSÁRLÁS",
|
||||
"tchange46":"AUTOMATIKUS VÁSÁRLÁS",
|
||||
"tchange47":"Eladni ezen az áron",
|
||||
"tchange48":"NEM ELÉG"
|
||||
"tchange48":"NEM ELÉG",
|
||||
"tchange49":"Árdiagram"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Jutalommegosztások",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Csatlakoz",
|
||||
"gchange52":"Kormányozo",
|
||||
"gchange53":"Tag",
|
||||
"gchange54":"Tagok"
|
||||
"gchange54":"Tagok",
|
||||
"gchange55":"Keresés privát csoportban",
|
||||
"gchange56":"A keresendő csoport neve",
|
||||
"gchange57":"A privát csoport neve nem található",
|
||||
"gchange58":"Ne feledje, hogy a csoport nevének pontosan meg kell egyeznie."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Rejtvények",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"A megerősítés megnyomására a rendszer elküldi a meghívó visszavonási kérelmét!",
|
||||
"mg50":"Hamarosan...",
|
||||
"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",
|
||||
"snack3":"Nodo personalizzato aggiunto e salvato con successo",
|
||||
"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":{
|
||||
"blockheight":"Altezza blocco",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Continua",
|
||||
"save":"Salva",
|
||||
"balance":"Saldo",
|
||||
"balances":"IL TUO SALDO DEL PORTAFOGLIO"
|
||||
"balances":"I SALDI DEL TUO PORTAFOGLIO",
|
||||
"update":"AGGIORNA I SALDI DEL PORTAFOGLIO"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Impossibile recuperare i conti di conio",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"ACQUISTA AUTO CON",
|
||||
"tchange46":"ACQUISTO AUTO",
|
||||
"tchange47":"Vendi a questo prezzo",
|
||||
"tchange48":"NON ABBASTANZA"
|
||||
"tchange48":"NON ABBASTANZA",
|
||||
"tchange49":"Tabella dei prezzi"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Quote di ricompensa",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Unisciti",
|
||||
"gchange52":"Amministratore",
|
||||
"gchange53":"Membro",
|
||||
"gchange54":"Membri"
|
||||
"gchange54":"Membri",
|
||||
"gchange55":"Cerca gruppo privato",
|
||||
"gchange56":"Nome gruppo da cercare",
|
||||
"gchange57":"Nome gruppo privato non trovato",
|
||||
"gchange58":"Nota che il nome del gruppo deve corrispondere esattamente."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Puzzle",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"Premendo conferma, verrà inviata la richiesta di annullamento dell'invito!",
|
||||
"mg50":"Prossimamente...",
|
||||
"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",
|
||||
"snack3":"사용자 정의 노드를 성공적으로 추가하고 저장했습니다.",
|
||||
"snack4":"노드가 다음으로 성공적으로 저장되었습니다",
|
||||
"snack5":"노드를 성공적으로 가져왔습니다."
|
||||
"snack5":"노드를 성공적으로 가져왔습니다.",
|
||||
"exp1":"개인 마스터 키 내보내기",
|
||||
"exp2":"마스터 키 내보내기",
|
||||
"exp3":"내보내기",
|
||||
"exp4":"개인 마스터 키를 백업할 지갑을 선택하세요."
|
||||
},
|
||||
"appinfo":{
|
||||
"blockheight":"블록 높이",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"계속하다",
|
||||
"save":"저장",
|
||||
"balance":"균형",
|
||||
"balances":"지갑 잔액"
|
||||
"balances":"지갑 잔액",
|
||||
"update":"월렛 잔액 업데이트"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"발행 계정을 가져올 수 없습니다",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"자동 구매",
|
||||
"tchange46":"자동 구매",
|
||||
"tchange47":"이 가격에 팔아요",
|
||||
"tchange48":"부족한"
|
||||
"tchange48":"부족한",
|
||||
"tchange49":"가격 차트"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"보상 공유",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"가입",
|
||||
"gchange52":"관리자",
|
||||
"gchange53":"회원",
|
||||
"gchange54":"회원들"
|
||||
"gchange54":"회원들",
|
||||
"gchange55":"비공개 그룹 검색",
|
||||
"gchange56":"검색할 그룹 이름",
|
||||
"gchange57":"비공개 그룹 이름을 찾을 수 없음",
|
||||
"gchange58":"그룹 이름이 정확히 일치해야 합니다."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"퍼즐",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"확인을 누르면 초대 취소 요청이 전송됩니다!",
|
||||
"mg50":"출시 예정...",
|
||||
"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",
|
||||
"snack3":"Egendefinert node er lagt til og lagret",
|
||||
"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":{
|
||||
"blockheight":"Blokkhøyde",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Fortsett",
|
||||
"save":"Lagre",
|
||||
"balance":"Saldo",
|
||||
"balances":"DIN WALLET-SALDO"
|
||||
"balances":"DIN WALLET-SALDO",
|
||||
"update":"OPPDATERT WALLET-SALDOER"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Kan ikke hente myntingkontoer",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTOKJØP MED",
|
||||
"tchange46":"AUTOKJØP",
|
||||
"tchange47":"Selges for denne prisen",
|
||||
"tchange48":"IKKE NOK"
|
||||
"tchange48":"IKKE NOK",
|
||||
"tchange49":"Prisdiagram"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Belønningsdel",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Bli med",
|
||||
"gchange52":"Admin",
|
||||
"gchange53":"Medlem",
|
||||
"gchange54":"Medlemmer"
|
||||
"gchange54":"Medlemmer",
|
||||
"gchange55":"Søk i privat gruppe",
|
||||
"gchange56":"Gruppenavn å søke",
|
||||
"gchange57":"Privat gruppenavn ikke funnet",
|
||||
"gchange58":"Merk at gruppenavnet må samsvare nøyaktig."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Puzzles",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"Når du trykker på bekreftelse, vil forespørselen om kansellering av invitasjon bli sendt!",
|
||||
"mg50":"Kommer snart...",
|
||||
"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",
|
||||
"snack3":"Pomyślnie dodano i zapisano niestandardowy węzeł",
|
||||
"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":{
|
||||
"blockheight":"Wysokość bloku",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Kontynuuj",
|
||||
"save":"Zapisz",
|
||||
"balance":"Saldo",
|
||||
"balances":"SALDO TWOJEGO PORTFELA"
|
||||
"balances":"SALDO TWOJEGO PORTFELA",
|
||||
"update":"AKTUALIZUJ SALDA W PORTFELU"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Nie można pobrać kont menniczych",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTO KUP Z",
|
||||
"tchange46":"AUTO KUP",
|
||||
"tchange47":"Sprzedaj za tę cenę",
|
||||
"tchange48":"NIEWYSTARCZAJĄCO"
|
||||
"tchange48":"NIEWYSTARCZAJĄCO",
|
||||
"tchange49":"Tabela cen"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Podział nagród",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Dołącz",
|
||||
"gchange52":"Administrator",
|
||||
"gchange53":"Członek",
|
||||
"gchange54":"Członkowie"
|
||||
"gchange54":"Członkowie",
|
||||
"gchange55":"Wyszukaj grupę prywatną",
|
||||
"gchange56":"Nazwa grupy do wyszukania",
|
||||
"gchange57":"Nie znaleziono nazwy grupy prywatnej",
|
||||
"gchange58":"Zauważ, że nazwa grupy musi dokładnie pasować."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Zagadki",
|
||||
@ -793,7 +803,16 @@
|
||||
"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!",
|
||||
"mg50":"Już wkrótce...",
|
||||
"mg51": "Minimum 3 znaki / Maksymalnie 32 znaki",
|
||||
"mg52": "Maksymalnie 128 znaków"
|
||||
"mg51":"Minimum 3 znaki / Maksymalnie 32 znaki",
|
||||
"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ó",
|
||||
"snack3":"Nó personalizado adicionado e salvo com sucesso",
|
||||
"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":{
|
||||
"blockheight":"Altura do Bloco",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Continuar",
|
||||
"save":"Salvar",
|
||||
"balance":"Saldo",
|
||||
"balances":"SEUS SALDOS DE CARTEIRA"
|
||||
"balances":"SEUS SALDOS DE CARTEIRA",
|
||||
"update":"ATUALIZAR SALDOS DA CARTEIRA"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Não é possível buscar contas de cunhagem",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"COMPRA AUTOMÁTICA COM",
|
||||
"tchange46":"COMPRA AUTOMÁTICA",
|
||||
"tchange47":"Vendo por este preço",
|
||||
"tchange48":"INSUFICIENTE"
|
||||
"tchange48":"INSUFICIENTE",
|
||||
"tchange49":"Tabela de preços"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Ações de recompensa",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Entrar",
|
||||
"gchange52":"Administrador",
|
||||
"gchange53":"Membro",
|
||||
"gchange54":"Membros"
|
||||
"gchange54":"Membros",
|
||||
"gchange55":"Pesquisar Grupo Privado",
|
||||
"gchange56":"Nome do grupo para pesquisar",
|
||||
"gchange57":"Nome do grupo privado não encontrado",
|
||||
"gchange58":"Observe que o nome do grupo deve corresponder exatamente."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Enigmas",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"Ao pressionar confirmar, a solicitação de cancelamento do convite será enviada!",
|
||||
"mg50":"Em Breve...",
|
||||
"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",
|
||||
"snack3":"Nod personalizat adaugat si salvat cu succes",
|
||||
"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":{
|
||||
"blockheight":"Dimensiunea blocului",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Continua",
|
||||
"save":"Salveza",
|
||||
"balance":"Credit",
|
||||
"balances":"SOLDELE PORTOTELULUI DVS"
|
||||
"balances":"SOLDELE PORTOTELULUI DVS",
|
||||
"update":"ACTUALIZAȚI SOLDELE PORTOTELULUI"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Nu se pot prelua conturile de batere",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"CUMPARA AUTOMATA CU",
|
||||
"tchange46":"CUMPARARE AUTOMATA",
|
||||
"tchange47":"Vinde la acest pret",
|
||||
"tchange48":"INSUFICIENT"
|
||||
"tchange48":"INSUFICIENT",
|
||||
"tchange49":"Diagrama prețurilor"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Cote de recompensa",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Inscriere",
|
||||
"gchange52":"Admin",
|
||||
"gchange53":"Membru",
|
||||
"gchange54":"Membrii"
|
||||
"gchange54":"Membrii",
|
||||
"gchange55":"Căutați grup privat",
|
||||
"gchange56":"Numele grupului de căutat",
|
||||
"gchange57":"Numele grupului privat nu a fost găsit",
|
||||
"gchange58":"Rețineți că numele grupului trebuie să se potrivească exact."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Puzzle-uri",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"La apăsarea confirmării, cererea de anulare a invitației va fi trimisă!",
|
||||
"mg50":"În curând...",
|
||||
"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",
|
||||
"snack3":"Uspešno dodat i sačuvan prilagođeni čvor",
|
||||
"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":{
|
||||
"blockheight":"Visina Bloka",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Nastavite",
|
||||
"save":"Sačuvajte",
|
||||
"balance":"Kredit",
|
||||
"balances":"VAŠI STANJE U NOVČANIKU"
|
||||
"balances":"VAŠI STANJE U NOVČANIKU",
|
||||
"update":"AŽURIRAJTE STANJE NOVČANIKA"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Nije moguće preuzeti naloge za kovanje",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTO KUPI SA",
|
||||
"tchange46":"AUTO BUI",
|
||||
"tchange47":"Prodaj za ovu cenu",
|
||||
"tchange48":"NEDOVOLJNO"
|
||||
"tchange48":"NEDOVOLJNO",
|
||||
"tchange49":"Grafik cena"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Udeo nagrade",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Uđite",
|
||||
"gchange52":"Administrator",
|
||||
"gchange53":"Član",
|
||||
"gchange54":"Članovi"
|
||||
"gchange54":"Članovi",
|
||||
"gchange55":"Pretraži privatnu grupu",
|
||||
"gchange56":"Ime grupe za pretragu",
|
||||
"gchange57":"Ime privatne grupe nije pronađeno",
|
||||
"gchange58":"Imajte na umu da ime grupe mora potpuno da se podudara."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Slagalice",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"Pritiskom na potvrdi, zahtev za otkazivanje pozivnice će biti poslat!",
|
||||
"mg50":"Uskoro...",
|
||||
"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":"Пользовательский интерфейс, подключенный к узлу",
|
||||
"snack3":"Пользовательский узел успешно добавлен и сохранен",
|
||||
"snack4":"Узлы успешно сохранены как",
|
||||
"snack5":"Узлы успешно импортированы"
|
||||
"snack5":"Узлы успешно импортированы",
|
||||
"exp1":"Экспорт закрытого мастер-ключа",
|
||||
"exp2":"Экспорт мастер-ключа",
|
||||
"exp3":"Экспорт",
|
||||
"exp4":"Пожалуйста, выберите кошелек для резервного копирования приватного главного ключа."
|
||||
},
|
||||
"appinfo":{
|
||||
"blockheight":"Высота блока",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Продолжить",
|
||||
"save":"Сохранить",
|
||||
"balance":"кредит",
|
||||
"balances":"БАЛАНС ВАШЕГО КОШЕЛЬКА"
|
||||
"balances":"БАЛАНС ВАШЕГО КОШЕЛЬКА",
|
||||
"update":"ОБНОВИТЬ БАЛАНС КОШЕЛЬКА"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"Не удается получить учетные записи минтинга",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"АВТО КУПИТЬ С",
|
||||
"tchange46":"АВТО КУПИТЬ",
|
||||
"tchange47":"Продать по этой цене",
|
||||
"tchange48":"НЕДОСТАТОЧНО"
|
||||
"tchange48":"НЕДОСТАТОЧНО",
|
||||
"tchange49":"График цен"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"Вознаграждения",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"Присоединиться",
|
||||
"gchange52":"Администратор",
|
||||
"gchange53":"Член",
|
||||
"gchange54":"Члены"
|
||||
"gchange54":"Члены",
|
||||
"gchange55":"Поиск в закрытой группе",
|
||||
"gchange56":"Имя группы для поиска",
|
||||
"gchange57":"Имя частной группы не найдено",
|
||||
"gchange58":"Обратите внимание, что название группы должно точно совпадать."
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"Головоломки",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"При нажатии подтверждения будет отправлен запрос на отмену приглашения!",
|
||||
"mg50":"Скоро...",
|
||||
"mg51":"Минимум 3 символа / максимум 32 символа",
|
||||
"mg52":"Максимум 128 символов"
|
||||
"mg52":"Максимум 128 символов",
|
||||
"mg53":"Ваши открытые запросы на вступление",
|
||||
"mg54":"Открытых запросов на присоединение нет",
|
||||
"mg55":"Вы уверены, что принимаете запрос на вступление от этого участника?",
|
||||
"mg56":"При нажатии подтверждения будет отправлен запрос на присоединение!",
|
||||
"mg57":"Запрос на присоединение успешно принят",
|
||||
"mg58":"ЧТО-ТО ПОШЛО НЕ ТАК",
|
||||
"mg59":"Запрос на отмену присоединения успешно принят",
|
||||
"mg60":"Вы уверены, что отмените запрос на вступление от этого участника?",
|
||||
"mg61":"При нажатии кнопки подтверждения будет отправлен запрос на отмену присоединения!"
|
||||
}
|
||||
}
|
||||
|
@ -93,42 +93,46 @@
|
||||
"selectfile": "Select file",
|
||||
"dragfile": "Drag and drop backup here"
|
||||
},
|
||||
"settings": {
|
||||
"generalinfo": "General Account Info",
|
||||
"address": "Address",
|
||||
"publickey": "Public Key",
|
||||
"settings": "Settings",
|
||||
"account": "Account",
|
||||
"security": "Security",
|
||||
"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_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_2": "Generate login QR code",
|
||||
"notifications": "Notifications",
|
||||
"accountsecurity": "Account Security",
|
||||
"password": "Password",
|
||||
"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)",
|
||||
"block": "Block Notifications (Coming Soon...)",
|
||||
"playsound": "Play Sound",
|
||||
"shownotifications": "Show Notifications",
|
||||
"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",
|
||||
"addcustomnode": "Add Custom Node",
|
||||
"addandsave": "Add And Save",
|
||||
"protocol": "Protocol",
|
||||
"domain": "Domain",
|
||||
"port": "Port",
|
||||
"import": "Import Nodes",
|
||||
"export": "Export Nodes",
|
||||
"deletecustomnode": "Remove All Custom Nodes",
|
||||
"warning": "Your existing nodes will be deleted and from backup new created.",
|
||||
"snack1": "Successfully deleted and added standard nodes",
|
||||
"snack2": "UI conected to node",
|
||||
"snack3": "Successfully added and saved custom node",
|
||||
"snack4": "Nodes successfully saved as",
|
||||
"snack5": "Nodes successfully imported"
|
||||
"settings":{
|
||||
"generalinfo":"General Account Info",
|
||||
"address":"Address",
|
||||
"publickey":"Public Key",
|
||||
"settings":"Settings",
|
||||
"account":"Account",
|
||||
"security":"Security",
|
||||
"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_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_2":"Generate login QR code",
|
||||
"notifications":"Notifications",
|
||||
"accountsecurity":"Account Security",
|
||||
"password":"Password",
|
||||
"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)",
|
||||
"block":"Block Notifications (Coming Soon...)",
|
||||
"playsound":"Play Sound",
|
||||
"shownotifications":"Show Notifications",
|
||||
"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",
|
||||
"addcustomnode":"Add Custom Node",
|
||||
"addandsave":"Add And Save",
|
||||
"protocol":"Protocol",
|
||||
"domain":"Domain",
|
||||
"port":"Port",
|
||||
"import":"Import Nodes",
|
||||
"export":"Export Nodes",
|
||||
"deletecustomnode":"Remove All Custom Nodes",
|
||||
"warning":"Your existing nodes will be deleted and from backup new created.",
|
||||
"snack1":"Successfully deleted and added standard nodes",
|
||||
"snack2":"UI conected to node",
|
||||
"snack3":"Successfully added and saved custom node",
|
||||
"snack4":"Nodes successfully saved as",
|
||||
"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":{
|
||||
"blockheight":"Block Height",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"Continue",
|
||||
"save":"Save",
|
||||
"balance":"Balance",
|
||||
"balances":"YOUR WALLET BALANCES"
|
||||
"balances":"YOUR WALLET BALANCES",
|
||||
"update":"UPDATE WALLET BALANCES"
|
||||
},
|
||||
"startminting": {
|
||||
"smchange1": "Cannot fetch minting accounts",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"AUTO BUY WITH",
|
||||
"tchange46":"AUTO BUY",
|
||||
"tchange47":"Sell for this price",
|
||||
"tchange48":"NOT ENOUGH"
|
||||
"tchange48":"NOT ENOUGH",
|
||||
"tchange49":"Price Chart"
|
||||
},
|
||||
"rewardsharepage": {
|
||||
"rchange1": "Rewardshares",
|
||||
@ -575,61 +581,65 @@
|
||||
"bcchange16": "Choose Recipient or Search for One Below",
|
||||
"bcchange17": "FORWARDED"
|
||||
},
|
||||
"grouppage": {
|
||||
"gchange1": "Qortal Groups",
|
||||
"gchange2": "Create Group",
|
||||
"gchange3": "Your Joined Groups",
|
||||
"gchange4": "Group Name",
|
||||
"gchange5": "Description",
|
||||
"gchange6": "Role",
|
||||
"gchange7": "Action",
|
||||
"gchange8": "Not a member of any group!",
|
||||
"gchange9": "Public Groups",
|
||||
"gchange10": "Owner",
|
||||
"gchange11": "No Open Public Groups available!",
|
||||
"gchange12": "Create a New Group",
|
||||
"gchange13": "Group Type",
|
||||
"gchange14": "This Field is Required",
|
||||
"gchange15": "Select an option",
|
||||
"gchange16": "Public",
|
||||
"gchange17": "Private",
|
||||
"gchange18": "Group Approval Threshold (number / percentage of Admins that must approve a transaction):",
|
||||
"gchange19": "NONE",
|
||||
"gchange20": "ONE",
|
||||
"gchange21": "Minimum Block delay for Group Transaction Approvals:",
|
||||
"gchange22": "minutes",
|
||||
"gchange23": "hour",
|
||||
"gchange24": "hours",
|
||||
"gchange25": "day",
|
||||
"gchange26": "days",
|
||||
"gchange27": "Maximum Block delay for Group Transaction Approvals:",
|
||||
"gchange28": "Creating Group",
|
||||
"gchange29": "Create Group",
|
||||
"gchange30": "Join Group Request",
|
||||
"gchange31": "Date Created",
|
||||
"gchange32": "Date Updated",
|
||||
"gchange33": "Joining",
|
||||
"gchange34": "Join Group",
|
||||
"gchange35": "Leave Group Request",
|
||||
"gchange36": "Leaving",
|
||||
"gchange37": "Leave Group",
|
||||
"gchange38": "Manage Group Owner:",
|
||||
"gchange39": "Manage Group Admin:",
|
||||
"gchange40": "Manage Group",
|
||||
"gchange41": "Group Creation Successful!",
|
||||
"gchange42": "Invalid Group Name",
|
||||
"gchange43": "Invalid Group Description",
|
||||
"gchange44": "Select a Group Typ",
|
||||
"gchange45": "Select a Group Approval Threshold",
|
||||
"gchange46": "Select a Minimum Block delay for Group Transaction Approvals",
|
||||
"gchange47": "Select a Maximum Block delay for Group Transaction Approvals",
|
||||
"gchange48": "Join Group Request Sent Successfully!",
|
||||
"gchange49": "Leave Group Request Sent Successfully!",
|
||||
"gchange50": "Leave",
|
||||
"gchange51": "Join",
|
||||
"gchange52": "Admin",
|
||||
"gchange53": "Member",
|
||||
"gchange54": "Members"
|
||||
"grouppage":{
|
||||
"gchange1":"Qortal Groups",
|
||||
"gchange2":"Create Group",
|
||||
"gchange3":"Your Joined Groups",
|
||||
"gchange4":"Group Name",
|
||||
"gchange5":"Description",
|
||||
"gchange6":"Role",
|
||||
"gchange7":"Action",
|
||||
"gchange8":"Not a member of any group!",
|
||||
"gchange9":"Public Groups",
|
||||
"gchange10":"Owner",
|
||||
"gchange11":"No Open Public Groups available!",
|
||||
"gchange12":"Create a New Group",
|
||||
"gchange13":"Group Type",
|
||||
"gchange14":"This Field is Required",
|
||||
"gchange15":"Select an option",
|
||||
"gchange16":"Public",
|
||||
"gchange17":"Private",
|
||||
"gchange18":"Group Approval Threshold (number / percentage of Admins that must approve a transaction):",
|
||||
"gchange19":"NONE",
|
||||
"gchange20":"ONE",
|
||||
"gchange21":"Minimum Block delay for Group Transaction Approvals:",
|
||||
"gchange22":"minutes",
|
||||
"gchange23":"hour",
|
||||
"gchange24":"hours",
|
||||
"gchange25":"day",
|
||||
"gchange26":"days",
|
||||
"gchange27":"Maximum Block delay for Group Transaction Approvals:",
|
||||
"gchange28":"Creating Group",
|
||||
"gchange29":"Create Group",
|
||||
"gchange30":"Join Group Request",
|
||||
"gchange31":"Date Created",
|
||||
"gchange32":"Date Updated",
|
||||
"gchange33":"Joining",
|
||||
"gchange34":"Join Group",
|
||||
"gchange35":"Leave Group Request",
|
||||
"gchange36":"Leaving",
|
||||
"gchange37":"Leave Group",
|
||||
"gchange38":"Manage Group Owner:",
|
||||
"gchange39":"Manage Group Admin:",
|
||||
"gchange40":"Manage Group",
|
||||
"gchange41":"Group Creation Successful!",
|
||||
"gchange42":"Invalid Group Name",
|
||||
"gchange43":"Invalid Group Description",
|
||||
"gchange44":"Select a Group Typ",
|
||||
"gchange45":"Select a Group Approval Threshold",
|
||||
"gchange46":"Select a Minimum Block delay for Group Transaction Approvals",
|
||||
"gchange47":"Select a Maximum Block delay for Group Transaction Approvals",
|
||||
"gchange48":"Join Group Request Sent Successfully!",
|
||||
"gchange49":"Leave Group Request Sent Successfully!",
|
||||
"gchange50":"Leave",
|
||||
"gchange51":"Join",
|
||||
"gchange52":"Admin",
|
||||
"gchange53":"Member",
|
||||
"gchange54":"Members",
|
||||
"gchange55":"Search Private Group",
|
||||
"gchange56":"Group Name To Search",
|
||||
"gchange57":"Private Group Name Not Found",
|
||||
"gchange58":"Note that group name must exact match."
|
||||
},
|
||||
"puzzlepage": {
|
||||
"pchange1": "Puzzles",
|
||||
@ -817,6 +827,15 @@
|
||||
"mg49":"On pressing confirm, the cancel invite request will be sent!",
|
||||
"mg50":"Coming Soon...",
|
||||
"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",
|
||||
"snack3":"成功添加并保存自定义节点",
|
||||
"snack4":"节点成功保存为",
|
||||
"snack5":"节点成功导入"
|
||||
"snack5":"节点成功导入",
|
||||
"exp1":"导出主密钥",
|
||||
"exp2":"导出主密钥",
|
||||
"exp3":"导出",
|
||||
"exp4":"请选择一个钱包来备份私钥。"
|
||||
},
|
||||
"appinfo":{
|
||||
"blockheight":"区块高度",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"继续",
|
||||
"save":"保存",
|
||||
"balance":"信用",
|
||||
"balances":"您的钱包余额"
|
||||
"balances":"您的钱包余额",
|
||||
"update":"更新钱包余额"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"无法获取铸币帐户",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"自动购买",
|
||||
"tchange46":"自动购买",
|
||||
"tchange47":"以这个价格出售",
|
||||
"tchange48":"不够"
|
||||
"tchange48":"不够",
|
||||
"tchange49":"价格图表"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"铸币密钥",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"加入",
|
||||
"gchange52":"管理员",
|
||||
"gchange53":"成员",
|
||||
"gchange54":"成员数量"
|
||||
"gchange54":"成员数量",
|
||||
"gchange55":"搜索私人群组",
|
||||
"gchange56":"要搜索的组名",
|
||||
"gchange57":"未找到私人组名",
|
||||
"gchange58":"注意组名必须完全匹配。"
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"益智游戏",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"按下确认后,将发送取消邀请请求!",
|
||||
"mg50":"即将推出……",
|
||||
"mg51":"最少 3 个字符 / 最多 32 个字符",
|
||||
"mg52":"最多 128 个字符"
|
||||
"mg52":"最多 128 个字符",
|
||||
"mg53":"您的公开加入请求",
|
||||
"mg54":"没有开放的加入请求",
|
||||
"mg55":"您确定接受该会员的加入请求吗?",
|
||||
"mg56":"按下确认后,将发送接受加入请求!",
|
||||
"mg57":"成功接受加入请求",
|
||||
"mg58":"出了点问题",
|
||||
"mg59":"取消加入请求已成功接受",
|
||||
"mg60":"您确定要取消该会员的加入请求吗?",
|
||||
"mg61":"按下确认后,将发送取消加入请求!"
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,11 @@
|
||||
"snack2":"連接到節點的 UI",
|
||||
"snack3":"成功添加並保存自定義節點",
|
||||
"snack4":"節點成功保存為",
|
||||
"snack5":"節點成功導入"
|
||||
"snack5":"節點成功導入",
|
||||
"exp1":"導出主密鑰",
|
||||
"exp2":"導出主密鑰",
|
||||
"exp3":"導出",
|
||||
"exp4":"請選擇一個錢包來備份私鑰。"
|
||||
},
|
||||
"appinfo":{
|
||||
"blockheight":"區塊高度",
|
||||
@ -155,7 +159,8 @@
|
||||
"continue":"繼續",
|
||||
"save":"保存",
|
||||
"balance":"信用",
|
||||
"balances":"您的錢包餘額"
|
||||
"balances":"您的錢包餘額",
|
||||
"update":"更新錢包餘額"
|
||||
},
|
||||
"startminting":{
|
||||
"smchange1":"無法獲取鑄幣帳戶",
|
||||
@ -328,7 +333,8 @@
|
||||
"tchange45":"自動購買",
|
||||
"tchange46":"自動購買",
|
||||
"tchange47":"以這個價格出售",
|
||||
"tchange48":"不夠"
|
||||
"tchange48":"不夠",
|
||||
"tchange49":"價格圖表"
|
||||
},
|
||||
"rewardsharepage":{
|
||||
"rchange1":"鑄幣密鑰",
|
||||
@ -606,7 +612,11 @@
|
||||
"gchange51":"加入",
|
||||
"gchange52":"管理員",
|
||||
"gchange53":"成員",
|
||||
"gchange54":"成員數量"
|
||||
"gchange54":"成員數量",
|
||||
"gchange55":"搜索私人群組",
|
||||
"gchange56":"要搜索的組名",
|
||||
"gchange57":"未找到私人組名",
|
||||
"gchange58":"注意組名必須完全匹配。"
|
||||
},
|
||||
"puzzlepage":{
|
||||
"pchange1":"益智游戲",
|
||||
@ -794,6 +804,15 @@
|
||||
"mg49":"按下確認後,將發送取消邀請請求!",
|
||||
"mg50":"即將推出……",
|
||||
"mg51":"最少 3 個字符 / 最多 32 個字符",
|
||||
"mg52":"最多 128 個字符"
|
||||
"mg52":"最多 128 個字符",
|
||||
"mg53":"您的公開加入請求",
|
||||
"mg54":"沒有開放的加入請求",
|
||||
"mg55":"您確定接受該會員的加入請求嗎?",
|
||||
"mg56":"按下確認後,將發送接受加入請求!",
|
||||
"mg57":"成功接受加入請求",
|
||||
"mg58":"出了點問題",
|
||||
"mg59":"取消加入請求已成功接受",
|
||||
"mg60":"您確定要取消該會員的加入請求嗎?",
|
||||
"mg61":"按下確認後,將發送取消加入請求!"
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
"sass": "1.57.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.20.7",
|
||||
"@babel/core": "7.20.12",
|
||||
"@material/mwc-button": "0.27.0",
|
||||
"@material/mwc-checkbox": "0.27.0",
|
||||
"@material/mwc-dialog": "0.27.0",
|
||||
@ -74,7 +74,7 @@
|
||||
"random-sentence-generator": "0.0.8",
|
||||
"redux": "4.2.0",
|
||||
"redux-thunk": "2.4.2",
|
||||
"rollup": "3.9.0",
|
||||
"rollup": "3.9.1",
|
||||
"rollup-plugin-node-globals": "1.4.0",
|
||||
"rollup-plugin-progress": "1.1.2",
|
||||
"rollup-plugin-scss": "3.0.0",
|
||||
|
@ -6,6 +6,7 @@ import { addTradeBotRoutes } from '../tradebot/addTradeBotRoutes.js'
|
||||
import { get, translate, translateUnsafeHTML } from 'lit-translate'
|
||||
|
||||
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||
import '@polymer/paper-progress/paper-progress.js'
|
||||
import '@polymer/iron-icons/iron-icons.js'
|
||||
import '@polymer/app-layout/app-layout.js'
|
||||
import '@polymer/paper-ripple'
|
||||
@ -38,6 +39,7 @@ class AppView extends connect(store)(LitElement) {
|
||||
theme: { type: String, reflect: true },
|
||||
addressInfo: { type: Object },
|
||||
searchContentString: { type: String },
|
||||
getAllBalancesLoading: { type: Boolean },
|
||||
botQortWallet: { type: String },
|
||||
botBtcWallet: { type: String },
|
||||
botLtcWallet: { type: String },
|
||||
@ -154,6 +156,10 @@ class AppView extends connect(store)(LitElement) {
|
||||
border-top: var(--border);
|
||||
}
|
||||
|
||||
paper-progress {
|
||||
--paper-progress-active-color: var(--mdc-theme-primary);
|
||||
}
|
||||
|
||||
.s-menu {
|
||||
list-style: none;
|
||||
padding: 0px 0px;
|
||||
@ -207,7 +213,7 @@ class AppView extends connect(store)(LitElement) {
|
||||
.balanceheadertext {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
font-size: 16px;
|
||||
font-size: 14px;
|
||||
font-weight: 400;
|
||||
width: 250px;
|
||||
display: inline;
|
||||
@ -323,11 +329,12 @@ class AppView extends connect(store)(LitElement) {
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||
this.searchContentString = ''
|
||||
this.urls = [];
|
||||
this.nodeType = ''
|
||||
this.addressInfo = {}
|
||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||
this.getAllBalancesLoading = false
|
||||
this.botQortWallet = ''
|
||||
this.botBtcWallet = ''
|
||||
this.botLtcWallet = ''
|
||||
@ -414,13 +421,18 @@ class AppView extends connect(store)(LitElement) {
|
||||
</div>
|
||||
<div id="balanceheader">
|
||||
<span class="balanceheadertext">
|
||||
${translate("general.balances")}
|
||||
<vaadin-button theme="icon" id="reload" @click="${() => this.getAllBalances()}">
|
||||
<vaadin-icon icon="vaadin:refresh"></vaadin-icon>
|
||||
</vaadin-button>
|
||||
<vaadin-tooltip text="Reload Balances" for="reload" position="top"></vaadin-tooltip>
|
||||
${this.getAllBalancesLoading ? html`
|
||||
${translate("general.update")}
|
||||
` : html`
|
||||
${translate("general.balances")}
|
||||
<vaadin-button theme="icon" id="reload" @click="${() => this.getAllBalances()}">
|
||||
<vaadin-icon icon="vaadin:refresh"></vaadin-icon>
|
||||
</vaadin-button>
|
||||
<vaadin-tooltip text="${translate("general.update")}" for="reload" position="top"></vaadin-tooltip>
|
||||
`}
|
||||
</span>
|
||||
</div>
|
||||
${this.getAllBalancesLoading ? html`<paper-progress indeterminate style="width: 100%; margin: 4px;"></paper-progress>` : ''}
|
||||
${this.balanceTicker}
|
||||
<app-info></app-info>
|
||||
</div>
|
||||
@ -1505,6 +1517,7 @@ class AppView extends connect(store)(LitElement) {
|
||||
}
|
||||
|
||||
async getAllBalances() {
|
||||
this.getAllBalancesLoading = true
|
||||
await this.updateQortWalletBalance()
|
||||
await this.updateBtcWalletBalance()
|
||||
await this.updateLtcWalletBalance()
|
||||
@ -1513,6 +1526,7 @@ class AppView extends connect(store)(LitElement) {
|
||||
await this.updateRvnWalletBalance()
|
||||
await this.fetchArrrWalletAddress()
|
||||
await this.updateArrrWalletBalance()
|
||||
this.getAllBalancesLoading = false
|
||||
}
|
||||
|
||||
async renderBalances() {
|
||||
@ -2132,4 +2146,4 @@ class AppView extends connect(store)(LitElement) {
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('app-view', AppView)
|
||||
window.customElements.define('app-view', AppView)
|
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 './notifications-view.js'
|
||||
import './qr-login-view.js'
|
||||
import './export-keys.js'
|
||||
|
||||
import { doLogout } from '../../redux/app/app-actions.js'
|
||||
|
||||
@ -156,6 +157,7 @@ class UserSettings extends connect(store)(LitElement) {
|
||||
font-size: 16px;
|
||||
text-align: center;
|
||||
min-height: 460px;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
@media(max-width:700px) {
|
||||
@ -226,6 +228,7 @@ class UserSettings extends connect(store)(LitElement) {
|
||||
<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('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('notification')} ><a class=${this.selectedView.id === 'notification' ? 'active' : ''} href="javascript:void(0)">${translate("settings.notifications")}</a></li>
|
||||
</ul>
|
||||
@ -247,25 +250,29 @@ class UserSettings extends connect(store)(LitElement) {
|
||||
|
||||
renderSettingViews(selectedView) {
|
||||
if (selectedView.id === 'info') {
|
||||
return html`<account-view></account-view>`;
|
||||
return html`<account-view></account-view>`
|
||||
} 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') {
|
||||
return html`<notifications-view></notifications-view>`;
|
||||
return html`<notifications-view></notifications-view>`
|
||||
} else if (selectedView.id === 'qr-login') {
|
||||
return html`<qr-login-view></qr-login-view>`;
|
||||
return html`<qr-login-view></qr-login-view>`
|
||||
}
|
||||
}
|
||||
|
||||
renderHeaderViews() {
|
||||
if (this.selectedView.id === 'info') {
|
||||
return html`${translate("settings.generalinfo")}`;
|
||||
return html`${translate("settings.generalinfo")}`
|
||||
} 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') {
|
||||
return html`UI ${translate("settings.notifications")}`;
|
||||
return html`UI ${translate("settings.notifications")}`
|
||||
} 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' }
|
||||
} else if (pageId === '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') {
|
||||
return this.selectedView = { id: 'notification', name: 'UI Notifications' }
|
||||
} else if (pageId === 'qr-login') {
|
||||
|
@ -6,8 +6,6 @@ import { doLogout } from '../../redux/app/app-actions.js'
|
||||
import { get, translate, translateUnsafeHTML } from 'lit-translate'
|
||||
|
||||
import '@polymer/paper-dialog/paper-dialog.js'
|
||||
import '@polymer/neon-animation/animations/scale-up-animation.js';
|
||||
import '@polymer/neon-animation/animations/fade-out-animation.js';
|
||||
import '@material/mwc-button'
|
||||
import '@material/mwc-icon'
|
||||
import '@vaadin/grid'
|
||||
@ -1173,7 +1171,7 @@ class UserInfoView extends connect(store)(LitElement) {
|
||||
</div>
|
||||
</paper-dialog>
|
||||
|
||||
<paper-dialog style="background: var(--white); border: 1px solid var(--black); border-radius: 5px;" id="userBoughtDialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop>
|
||||
<paper-dialog style="background: var(--white); border: 1px solid var(--black); border-radius: 5px;" id="userBoughtDialog" modal>
|
||||
<div class="card-explorer-container">
|
||||
<div id="first-explorer-section">
|
||||
${this.boughtBTCTemplate()}
|
||||
@ -1193,7 +1191,7 @@ class UserInfoView extends connect(store)(LitElement) {
|
||||
</div>
|
||||
</paper-dialog>
|
||||
|
||||
<paper-dialog style="background: var(--white); border: 1px solid var(--black); border-radius: 5px; overflow: auto;" id="userSoldDialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop>
|
||||
<paper-dialog style="background: var(--white); border: 1px solid var(--black); border-radius: 5px; overflow: auto;" id="userSoldDialog" modal>
|
||||
<div class="card-explorer-container">
|
||||
<div id="first-explorer-section">
|
||||
${this.soldBTCTemplate()}
|
||||
@ -1213,7 +1211,7 @@ class UserInfoView extends connect(store)(LitElement) {
|
||||
</div>
|
||||
</paper-dialog>
|
||||
|
||||
<paper-dialog style="background: var(--white); border: 1px solid var(--black); border-radius: 5px;" id="showTxDetailsDialog" entry-animation="scale-up-animation" exit-animation="fade-out-animation" with-backdrop>
|
||||
<paper-dialog style="background: var(--white); border: 1px solid var(--black); border-radius: 5px;" id="showTxDetailsDialog" modal>
|
||||
<div style="text-align: center; color: var(--black);">
|
||||
<h1>${translate("walletpage.wchange5")}</h1>
|
||||
<hr />
|
||||
@ -1773,7 +1771,7 @@ class UserInfoView extends connect(store)(LitElement) {
|
||||
|
||||
openTrades() {
|
||||
this.shadowRoot.getElementById('userTrades').open()
|
||||
this.shadowRoot.getElementById('userInfoDialog').close()
|
||||
this.shadowRoot.getElementById('userFullInfoDialog').close()
|
||||
}
|
||||
|
||||
async openUserBoughtDialog() {
|
||||
|
@ -26,8 +26,7 @@
|
||||
"short-unique-id": "^4.4.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.20.7",
|
||||
"@github/time-elements": "3.1.2",
|
||||
"@babel/core": "7.20.12",
|
||||
"@material/mwc-button": "0.27.0",
|
||||
"@material/mwc-checkbox": "0.27.0",
|
||||
"@material/mwc-dialog": "0.27.0",
|
||||
@ -63,7 +62,7 @@
|
||||
"html-escaper": "3.0.3",
|
||||
"lit": "2.5.0",
|
||||
"lit-translate": "2.0.1",
|
||||
"rollup": "3.9.0",
|
||||
"rollup": "3.9.1",
|
||||
"rollup-plugin-node-globals": "1.4.0",
|
||||
"rollup-plugin-progress": "1.1.2",
|
||||
"rollup-plugin-terser": "7.0.2",
|
||||
@ -72,4 +71,4 @@
|
||||
"engines": {
|
||||
"node": ">=16.17.1"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { LitElement, html, css } from 'lit'
|
||||
|
||||
import '@github/time-elements'
|
||||
import './time-elements/index.js'
|
||||
|
||||
class TimeAgo extends LitElement {
|
||||
static get properties() {
|
||||
|
@ -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())
|
||||
})
|
||||
|
||||
import '../components/time-elements/index.js'
|
||||
import '@material/mwc-button'
|
||||
import '@material/mwc-dialog'
|
||||
import '@material/mwc-formfield'
|
||||
@ -21,7 +22,6 @@ import '@vaadin/icon'
|
||||
import '@vaadin/icons'
|
||||
import '@vaadin/grid'
|
||||
import '@vaadin/grid/vaadin-grid-filter-column.js'
|
||||
import '@github/time-elements'
|
||||
|
||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||
|
||||
@ -30,12 +30,15 @@ class GroupManagement extends LitElement {
|
||||
return {
|
||||
loading: { type: Boolean },
|
||||
publicGroups: { type: Array },
|
||||
privateGroups: { type: Array },
|
||||
joinedGroups: { type: Array },
|
||||
groupInvites: { type: Array },
|
||||
privateGroupSearch: { type: Array },
|
||||
newMembersList: { type: Array },
|
||||
newAdminsList: { type: Array },
|
||||
newBannedList: { type: Array },
|
||||
newGroupInvitesList: { type: Array },
|
||||
newGroupJoinsList: { type: Array },
|
||||
recipientPublicKey: { type: String },
|
||||
selectedAddress: { type: Object },
|
||||
manageGroupObj: { type: Object },
|
||||
@ -77,6 +80,7 @@ class GroupManagement extends LitElement {
|
||||
toInviteMemberToGroup: { type: String },
|
||||
toCancelInviteMemberName: { type: String },
|
||||
toCancelInviteMemberAddress: { type: String },
|
||||
searchGroupName: { type: String },
|
||||
errorMessage: { type: String },
|
||||
successMessage: { type: String }
|
||||
}
|
||||
@ -152,6 +156,11 @@ class GroupManagement extends LitElement {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.success-icon {
|
||||
font-size: 48px;
|
||||
color: #198754;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
font-size: 36px;
|
||||
}
|
||||
@ -410,6 +419,13 @@ class GroupManagement extends LitElement {
|
||||
background: var(--white);
|
||||
color: var(--black);
|
||||
}
|
||||
|
||||
#search {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
margin: auto;
|
||||
align-items: center;
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
@ -418,12 +434,15 @@ class GroupManagement extends LitElement {
|
||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||
this.selectedAddress = {}
|
||||
this.publicGroups = []
|
||||
this.privateGroups = []
|
||||
this.joinedGroups = []
|
||||
this.groupInvites = []
|
||||
this.privateGroupSearch = []
|
||||
this.newMembersList = []
|
||||
this.newAdminsList = []
|
||||
this.newBannedList = []
|
||||
this.newGroupInvitesList = []
|
||||
this.newGroupJoinsList = []
|
||||
this.manageGroupObj = {}
|
||||
this.joinGroupObj = {}
|
||||
this.leaveGroupObj = {}
|
||||
@ -458,6 +477,7 @@ class GroupManagement extends LitElement {
|
||||
this.toInviteMemberToGroup = ''
|
||||
this.toCancelInviteMemberName = ''
|
||||
this.toCancelInviteMemberAddress = ''
|
||||
this.searchGroupName = ''
|
||||
this.errorMessage = ''
|
||||
this.successMessage = ''
|
||||
this.selectedView = { id: 'group-members', name: 'Group Members' }
|
||||
@ -823,6 +843,7 @@ class GroupManagement extends LitElement {
|
||||
|
||||
groupInviteTemplate() {
|
||||
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-column
|
||||
width="6rem"
|
||||
@ -867,6 +888,54 @@ class GroupManagement extends LitElement {
|
||||
${this.isEmptyArray(this.newGroupInvitesList) ? html`
|
||||
<span style="color: var(--black);">${translate("managegroup.mg35")}</span>
|
||||
` : 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;">
|
||||
<vaadin-button theme="primary medium" @click=${() => this.openInviteMemberToGroupDialog()}>
|
||||
${translate("managegroup.mg2")}
|
||||
@ -1020,6 +1089,72 @@ class GroupManagement extends LitElement {
|
||||
${translate("general.close")}
|
||||
</mwc-button>
|
||||
</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>
|
||||
`
|
||||
}
|
||||
|
||||
@ -1136,6 +1271,45 @@ class GroupManagement extends LitElement {
|
||||
<mwc-button style="float:right;" @click=${() => this.shadowRoot.querySelector('#createGroupDialog').show()}><mwc-icon>add</mwc-icon>${translate("grouppage.gchange2")}</mwc-button>
|
||||
</div>
|
||||
|
||||
<div class="divCard">
|
||||
<h3 style="margin: 0; margin-bottom: 1em; text-align: left;">${translate("grouppage.gchange55")}</h3>
|
||||
<div id="search">
|
||||
<vaadin-text-field
|
||||
theme="medium"
|
||||
style="width: 20em"
|
||||
minlength="3"
|
||||
maxlength="32"
|
||||
id="searchGroupName"
|
||||
placeholder="${translate("grouppage.gchange56")}"
|
||||
value="${this.searchGroupName}"
|
||||
@keydown="${this.searchGroupListener}"
|
||||
clear-button-visible
|
||||
>
|
||||
<vaadin-icon slot="prefix" icon="vaadin:user"></vaadin-icon>
|
||||
</vaadin-text-field> <br>
|
||||
<vaadin-button theme="medium" @click="${(e) => this.doGroupSearch(e)}">
|
||||
<vaadin-icon icon="vaadin:search" slot="prefix"></vaadin-icon>
|
||||
${translate("websitespage.schange35")}
|
||||
</vaadin-button>
|
||||
</div><br />
|
||||
<vaadin-grid theme="large" id="priveGroupSearchGrid" ?hidden="${this.isEmptyArray(this.privateGroupSearch)}" .items="${this.privateGroupSearch}" aria-label="My Search Result" all-rows-visible>
|
||||
<vaadin-grid-column width="8rem" flex-grow="0" header="${translate("grouppage.gchange54")}" path="memberCount"></vaadin-grid-column>
|
||||
<vaadin-grid-column header="${translate("grouppage.gchange4")}" path="groupName"></vaadin-grid-column>
|
||||
<vaadin-grid-column header="${translate("managegroup.mg42")}" .renderer=${(root, column, data) => {
|
||||
if (data.item.isOpen === true) {
|
||||
render(html`${translate("managegroup.mg44")}`, root)
|
||||
} else {
|
||||
render(html`${translate("managegroup.mg45")}`, root)
|
||||
}
|
||||
}}></vaadin-grid-column>
|
||||
<vaadin-grid-column header="${translate("grouppage.gchange5")}" path="description"></vaadin-grid-column>
|
||||
<vaadin-grid-column header="${translate("grouppage.gchange10")}" path="owner"></vaadin-grid-column>
|
||||
<vaadin-grid-column width="11rem" flex-grow="0" header="${translate("grouppage.gchange7")}" .renderer=${(root, column, data) => {
|
||||
render(html`<mwc-button @click=${() => this.joinGroup(data.item)}><mwc-icon>queue</mwc-icon> ${translate("grouppage.gchange51")}</mwc-button>`, root)
|
||||
}}></vaadin-grid-column>
|
||||
</vaadin-grid>
|
||||
</div>
|
||||
|
||||
<div class="divCard">
|
||||
<h3 style="margin: 0; margin-bottom: 1em; text-align: center;">${translate("grouppage.gchange3")}</h3>
|
||||
<vaadin-grid theme="large" id="joinedGroupsGrid" ?hidden="${this.isEmptyArray(this.joinedGroups)}" .items="${this.joinedGroups}" aria-label="Joined Groups" all-rows-visible>
|
||||
@ -1150,7 +1324,9 @@ class GroupManagement extends LitElement {
|
||||
}}></vaadin-grid-column>
|
||||
</vaadin-grid>
|
||||
${this.isEmptyArray(this.joinedGroups) ? html`
|
||||
<span style="color: var(--black);">${translate("grouppage.gchange8")}</span>
|
||||
<div style="text-align: center;">
|
||||
<span style="color: var(--black);">${translate("grouppage.gchange8")}</span>
|
||||
</div>
|
||||
`: ''}
|
||||
</div>
|
||||
|
||||
@ -1175,7 +1351,9 @@ class GroupManagement extends LitElement {
|
||||
}}></vaadin-grid-column>
|
||||
</vaadin-grid>
|
||||
${this.isEmptyArray(this.groupInvites) ? html`
|
||||
<span style="color: var(--black);">${translate("managegroup.mg35")}</span>
|
||||
<div style="text-align: center;">
|
||||
<span style="color: var(--black);">${translate("managegroup.mg35")}</span>
|
||||
</div>
|
||||
`: ''}
|
||||
</div>
|
||||
|
||||
@ -1477,6 +1655,22 @@ class GroupManagement extends LitElement {
|
||||
${translate("general.close")}
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
|
||||
<mwc-dialog id="privateGroupErrorDialog" scrimClickAction="" escapeKeyAction="">
|
||||
<div style="text-align: center;">
|
||||
<mwc-icon class="error-icon">warning</mwc-icon>
|
||||
<h2>${translate("grouppage.gchange57")}</h2>
|
||||
<h4>${translate("grouppage.gchange58")}</h4>
|
||||
</div>
|
||||
|
||||
<mwc-button
|
||||
slot="primaryAction"
|
||||
@click=${() => this.closePrivateGroupErrorDialog()}
|
||||
class="red"
|
||||
>
|
||||
${translate("general.close")}
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
@ -1504,6 +1698,14 @@ class GroupManagement extends LitElement {
|
||||
return myGs
|
||||
}
|
||||
|
||||
const getPrivateGroups = async () => {
|
||||
let privateG = await parentEpml.request('apiCall', {
|
||||
url: `/groups?limit=0&reverse=true`
|
||||
})
|
||||
let myPgs = privateG.filter(myP => myP.isOpen === false)
|
||||
return myPgs
|
||||
}
|
||||
|
||||
const getJoinedGroups = async () => {
|
||||
let joinedG = await parentEpml.request('apiCall', {
|
||||
url: `/groups/member/${this.selectedAddress.address}`
|
||||
@ -1563,13 +1765,15 @@ class GroupManagement extends LitElement {
|
||||
const getOpen_JoinedGroups = async () => {
|
||||
let _joinedGroups = await getJoinedGroups()
|
||||
let _publicGroups = await getOpenPublicGroups()
|
||||
let _privateGroups = await getPrivateGroups()
|
||||
let results = _publicGroups.filter(myOpenGroup => {
|
||||
let value = _joinedGroups.some(myJoinedGroup => myOpenGroup.groupId === myJoinedGroup.groupId)
|
||||
return !value
|
||||
});
|
||||
this.publicGroups = results
|
||||
this.privateGroups = _privateGroups
|
||||
this.joinedGroups = _joinedGroups
|
||||
setTimeout(getOpen_JoinedGroups, 30000)
|
||||
setTimeout(getOpen_JoinedGroups, 60000)
|
||||
}
|
||||
|
||||
window.addEventListener("contextmenu", (event) => {
|
||||
@ -1722,6 +1926,36 @@ class GroupManagement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
searchGroupListener(e) {
|
||||
if (e.key === 'Enter') {
|
||||
this.doGroupSearch(e)
|
||||
}
|
||||
}
|
||||
|
||||
doGroupSearch(e) {
|
||||
this.renderSearchResult()
|
||||
}
|
||||
|
||||
renderSearchResult() {
|
||||
this.privateGroupSearch = []
|
||||
let searchGroupName = this.shadowRoot.getElementById('searchGroupName').value
|
||||
if (searchGroupName.length === 0) {
|
||||
let err1string = get("websitespage.schange34")
|
||||
parentEpml.request('showSnackBar', `${err1string}`)
|
||||
} else {
|
||||
this.privateGroupSearch = this.privateGroups.filter(myS => myS.groupName === searchGroupName)
|
||||
if (this.privateGroupSearch.length === 0) {
|
||||
this.shadowRoot.querySelector('#privateGroupErrorDialog').show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closePrivateGroupErrorDialog() {
|
||||
this.shadowRoot.querySelector('#privateGroupErrorDialog').close()
|
||||
this.shadowRoot.getElementById('searchGroupName').value = ''
|
||||
this.privateGroupSearch = []
|
||||
}
|
||||
|
||||
renderBanButton(groupObj) {
|
||||
return html`<mwc-button class="warning" @click=${() => this.openCreateBanMemberDialog(groupObj)}><mwc-icon>create</mwc-icon> ${translate("managegroup.mg6")}</mwc-button>`
|
||||
}
|
||||
@ -1874,6 +2108,38 @@ class GroupManagement extends LitElement {
|
||||
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) {
|
||||
const _inviteMemberInfo = this.shadowRoot.getElementById('toInviteMemberToGroup').value
|
||||
const _nviteMemberTime = this.shadowRoot.getElementById("inviteMemberTime").value
|
||||
@ -1939,6 +2205,7 @@ class GroupManagement extends LitElement {
|
||||
closeFieldErrorDialog() {
|
||||
this.shadowRoot.querySelector('#fieldErrorDialog').close()
|
||||
}
|
||||
|
||||
async unitCreateFee() {
|
||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||
@ -2248,6 +2515,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() {
|
||||
this.resetDefaultSettings()
|
||||
this.shadowRoot.getElementById('manageGroupOwnerDialog').close()
|
||||
@ -2276,6 +2594,7 @@ class GroupManagement extends LitElement {
|
||||
await this.getNewMemberList(groupObj.groupId)
|
||||
await this.getNewBannedList(groupObj.groupId)
|
||||
await this.getNewGroupInvitesList(groupObj.groupId)
|
||||
await this.getNewGroupJoinList(groupObj.groupId)
|
||||
await manageGroupDelay(1000)
|
||||
this.shadowRoot.getElementById('manageGroupOwnerDialog').open()
|
||||
}
|
||||
@ -2944,6 +3263,148 @@ class GroupManagement extends LitElement {
|
||||
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) {
|
||||
const member = this.shadowRoot.getElementById('memberToAdmin').value
|
||||
const addGroupAdminFeeInput = this.addGroupAdminFee
|
||||
@ -3178,4 +3639,4 @@ class GroupManagement extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
window.customElements.define('group-management', GroupManagement)
|
||||
window.customElements.define('group-management', GroupManagement)
|
@ -280,7 +280,7 @@ class NameRegistration extends LitElement {
|
||||
}
|
||||
|
||||
async uploadAvatar(nameObj) {
|
||||
let name = nameObj.name
|
||||
let name = encodeURIComponent(nameObj.name)
|
||||
window.location.href = `../qdn/publish/index.html?service=THUMBNAIL&identifier=qortal_avatar&name=${name}&uploadType=file&category=Avatar&showName=false&showService=false&showIdentifier=false`
|
||||
}
|
||||
|
||||
|
@ -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 '@vaadin/grid'
|
||||
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 })
|
||||
|
||||
@ -1160,8 +1166,11 @@ class TradePortal extends LitElement {
|
||||
<mwc-list-item value="DOGECOIN"><span class="coinName doge" style="color: var(--black);">QORT / DOGE</span></mwc-list-item>
|
||||
<mwc-list-item value="DIGIBYTE"><span class="coinName dgb" style="color: var(--black);">QORT / DGB</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>
|
||||
<div style="padding-left: 25px; padding-top: 15px;">
|
||||
${this.chartShowCoin()}
|
||||
</div>
|
||||
</div>
|
||||
<div id="trade-portal">
|
||||
<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>`
|
||||
}
|
||||
|
||||
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() {
|
||||
switch(this.listedCoins.get(this.selectedCoin).coinCode) {
|
||||
case "BTC":
|
||||
|
@ -10,8 +10,8 @@ registerTranslateConfig({
|
||||
import '../components/ButtonIconCopy.js'
|
||||
import '../components/QortalQrcodeGenerator.js'
|
||||
import '../components/frag-file-input.js'
|
||||
import '../components/time-elements/index.js'
|
||||
import FileSaver from 'file-saver'
|
||||
import '@github/time-elements'
|
||||
import '@material/mwc-button'
|
||||
import '@material/mwc-checkbox'
|
||||
import '@material/mwc-dialog'
|
||||
@ -55,7 +55,7 @@ class MultiWallet extends LitElement {
|
||||
dogeAmount: { type: Number },
|
||||
dgbRecipient: { type: String },
|
||||
dgbAmount: { type: Number },
|
||||
rvnRecipient: { type: String },
|
||||
rvnRecipient: { type: String },
|
||||
rvnAmount: { type: Number },
|
||||
arrrRecipient: { type: String },
|
||||
arrrAmount: { type: Number },
|
||||
@ -73,7 +73,7 @@ class MultiWallet extends LitElement {
|
||||
ltcFeePerByte: { type: Number },
|
||||
dogeFeePerByte: { type: Number },
|
||||
dgbFeePerByte: { type: Number },
|
||||
rvnFeePerByte: { type: Number },
|
||||
rvnFeePerByte: { type: Number },
|
||||
qortBook: { type: Array },
|
||||
btcBook: { type: Array },
|
||||
ltcBook: { type: Array },
|
||||
@ -472,7 +472,7 @@ class MultiWallet extends LitElement {
|
||||
background-image: url('/img/dgb.png');
|
||||
}
|
||||
|
||||
.rvn .currency-image {
|
||||
.rvn .currency-image {
|
||||
background-image: url('/img/rvn.png');
|
||||
}
|
||||
|
||||
@ -508,12 +508,12 @@ class MultiWallet extends LitElement {
|
||||
.btn-clear-success {
|
||||
--mdc-icon-button-size: 32px;
|
||||
color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-clear-error {
|
||||
--mdc-icon-button-size: 32px;
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fade-in {
|
||||
0% {
|
||||
@ -680,7 +680,7 @@ class MultiWallet extends LitElement {
|
||||
this.isValidAmount = false
|
||||
this.btnDisable = false
|
||||
this.qortWarning = false
|
||||
this.balance = 0
|
||||
this.balance = 0
|
||||
this.amount = 0
|
||||
this.btcAmount = 0
|
||||
this.ltcAmount = 0
|
||||
@ -1092,7 +1092,7 @@ class MultiWallet extends LitElement {
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
|
||||
<mwc-dialog id="showRvnTransactionDetailsDialog" scrimClickAction="${this.showRvnTransactionDetailsLoading ? '' : 'close'}">
|
||||
<mwc-dialog id="showRvnTransactionDetailsDialog" scrimClickAction="${this.showRvnTransactionDetailsLoading ? '' : 'close'}">
|
||||
<div style="text-align: center;">
|
||||
<h1>${translate("walletpage.wchange5")}</h1>
|
||||
<hr />
|
||||
@ -1577,7 +1577,7 @@ class MultiWallet extends LitElement {
|
||||
</mwc-button>
|
||||
</mwc-dialog>
|
||||
|
||||
<mwc-dialog id="sendRvnDialog" scrimClickAction="" escapeKeyAction="">
|
||||
<mwc-dialog id="sendRvnDialog" scrimClickAction="" escapeKeyAction="">
|
||||
<div class="send-coin-dialog">
|
||||
<div style="text-align: center;">
|
||||
<img src="/img/rvn.png" width="32" height="32">
|
||||
@ -2759,7 +2759,7 @@ class MultiWallet extends LitElement {
|
||||
checkSelectedTextAndShowMenu()
|
||||
})
|
||||
|
||||
this.shadowRoot.getElementById('rvnAmountInput').addEventListener('contextmenu', (event) => {
|
||||
this.shadowRoot.getElementById('rvnAmountInput').addEventListener('contextmenu', (event) => {
|
||||
const getSelectedText = () => {
|
||||
var text = ''
|
||||
if (typeof window.getSelection != 'undefined') {
|
||||
@ -2809,7 +2809,7 @@ class MultiWallet extends LitElement {
|
||||
checkSelectedTextAndShowMenu()
|
||||
})
|
||||
|
||||
this.shadowRoot.getElementById('arrrAmountInput').addEventListener('contextmenu', (event) => {
|
||||
this.shadowRoot.getElementById('arrrAmountInput').addEventListener('contextmenu', (event) => {
|
||||
const getSelectedText = () => {
|
||||
var text = ''
|
||||
if (typeof window.getSelection != 'undefined') {
|
||||
@ -4499,7 +4499,7 @@ class MultiWallet extends LitElement {
|
||||
case 'ltc':
|
||||
case 'doge':
|
||||
case 'dgb':
|
||||
case 'rvn':
|
||||
case 'rvn':
|
||||
this.balanceString = this.renderFetchText()
|
||||
const walletName = `${coin}Wallet`
|
||||
parentEpml.request('apiCall', {
|
||||
@ -4844,9 +4844,9 @@ class MultiWallet extends LitElement {
|
||||
render(this.renderDogeTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM)
|
||||
} else if (this._selectedWallet === 'dgb') {
|
||||
render(this.renderDgbTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM)
|
||||
} else if (this._selectedWallet === 'rvn') {
|
||||
} else if (this._selectedWallet === 'rvn') {
|
||||
render(this.renderRvnTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM)
|
||||
} else if (this._selectedWallet === 'arrr') {
|
||||
} else if (this._selectedWallet === 'arrr') {
|
||||
render(this.renderArrrTransactions(this.wallets.get(this._selectedWallet).transactions, this._selectedWallet), this.transactionsDOM)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user