From e0c44bef69b399ae4af9ad59f9f1e243ea17e6f2 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Tue, 3 Jan 2023 22:19:13 -0500 Subject: [PATCH 01/19] Started Tip User --- qortal-ui-core/language/us.json | 9 +- qortal-ui-core/src/components/app-view.js | 32 +- .../plugins/core/components/ChatPage.js | 48 +- .../plugins/core/components/ChatRightPanel.js | 566 +++++++++++------- .../plugins/utils/getUserNameFromAddress.js | 20 + 5 files changed, 426 insertions(+), 249 deletions(-) create mode 100644 qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index efeca99f..c8fa70b4 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -565,7 +565,7 @@ "gchange32": "Date Updated", "gchange33": "Joining", "gchange34": "Join Group", - "gchange35": "Leave Group Request", + "gchange35": "User Info", "gchange36": "Leaving", "gchange37": "Leave Group", "gchange38": "Manage Group Owner:", @@ -584,7 +584,12 @@ "gchange51": "Join", "gchange52": "Admin", "gchange53": "Member", - "gchange54": "Members" + "gchange54": "Members", + "gchange55": "Tip QORT to", + "gchange56": "SEND MESSAGE", + "gchange57": "TIP USER", + "gchange58": "Tip Amount", + "gchange59": "Available Balance" }, "puzzlepage": { "pchange1": "Puzzles", diff --git a/qortal-ui-core/src/components/app-view.js b/qortal-ui-core/src/components/app-view.js index 51325e36..091bdb5f 100644 --- a/qortal-ui-core/src/components/app-view.js +++ b/qortal-ui-core/src/components/app-view.js @@ -44,7 +44,6 @@ class AppView extends connect(store)(LitElement) { app-drawer { box-shadow: var(--shadow-2); - background: var(--sidetopbar); } app-header { @@ -66,25 +65,32 @@ class AppView extends connect(store)(LitElement) { background: var(--sidetopbar); } - .sideBarMenu{ + .sideBarMenu { overflow-y: auto; flex: 1 1; } - #sideBar::-webkit-scrollbar { - width: 7px; - background-color: transparent; + .sideBarMenu::-webkit-scrollbar-track { + background-color: whitesmoke; + border-radius: 7px; } - - #sideBar::-webkit-scrollbar-track { - background-color: transparent; + + .sideBarMenu::-webkit-scrollbar { + width: 6px; + border-radius: 7px; + background-color: whitesmoke; } - - #sideBar::-webkit-scrollbar-thumb { - background-color: #333; - border-radius: 6px; - border: 3px solid #333; + + .sideBarMenu::-webkit-scrollbar-thumb { + background-color: rgb(180, 176, 176); + border-radius: 7px; + transition: all 0.3s ease-in-out; } + + .sideBarMenu::-webkit-scrollbar-thumb:hover { + background-color: rgb(148, 146, 146); + cursor: pointer; + } ` ] } diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index e93498b3..f37fc94b 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -105,6 +105,7 @@ class ChatPage extends LitElement { flex-direction: column; height: 50vh; overflow-y: auto; + overflow-x: hidden; width: 100%; } @@ -287,7 +288,6 @@ class ChatPage extends LitElement { .chat-container { display: grid; - grid-template-rows: minmax(6%, 92vh) minmax(40px, auto); max-height: 100%; } @@ -575,13 +575,6 @@ class ChatPage extends LitElement { object-fit: contain; } - .chat-container { - display: grid; - grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto); - max-height: 100%; - flex: 3; - } - .chat-right-panel { flex: 0; border-left: 3px solid rgb(221, 221, 221); @@ -845,21 +838,24 @@ class ChatPage extends LitElement { render() { return html`
-
- ${(!this.isReceipient && +this._chatId !== 0) ? html` +
+ ${(!this.isReceipient && +this._chatId !== 0) ? + html`
-
-

${this.groupInfo && this.groupInfo.groupName}

-
-
- - - - - +
+

${this.groupInfo && this.groupInfo.groupName}

+
+
+ + + + +
- ` : html`
`} + ` : null}
${this.isLoadingMessages ? @@ -1145,7 +1141,17 @@ class ChatPage extends LitElement {
- this.getMoreMembers(val)} .toggle=${(val)=> this._toggle(val)} .selectedAddress=${this.selectedAddress} .groupMembers=${this.groupMembers} .groupAdmin=${this.groupAdmin} .leaveGroupObj=${this.groupInfo}> + this.getMoreMembers(val)} + .toggle=${(val)=> this._toggle(val)} + .selectedAddress=${this.selectedAddress} + .groupMembers=${this.groupMembers} + .groupAdmin=${this.groupAdmin} + .leaveGroupObj=${this.groupInfo} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} + .chatEditor=${this.chatEditor} + > +
diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index 2366400e..001bd0f3 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -2,6 +2,7 @@ import { LitElement, html, css } from "lit" import { render } from "lit/html.js" import { get, translate } from "lit-translate" import { Epml } from "../../../epml" +import { getUserNameFromAddress } from "../../utils/getUserNameFromAddress" import snackbar from "./snackbar.js" import "@material/mwc-button" import "@material/mwc-dialog" @@ -15,7 +16,7 @@ class ChatRightPanel extends LitElement { static get properties() { return { isLoading: { type: Boolean }, - isOpenLeaveModal: { type: Boolean }, + openUserInfo: { type: Boolean }, leaveGroupObj: { type: Object }, error: { type: Boolean }, message: { type: String }, @@ -24,14 +25,18 @@ class ChatRightPanel extends LitElement { groupMembers: { attribute: false }, selectedHead: { type: Object }, toggle: { attribute: false }, - getMoreMembers:{ attribute: false } + getMoreMembers:{ attribute: false }, + setOpenPrivateMessage: { attribute: false }, + openTipUser: { type: Boolean }, + userName: { type: String }, + chatEditor: { type: Object } } } constructor() { super() this.isLoading = false - this.isOpenLeaveModal = false + this.openUserInfo = false this.leaveGroupObj = {} this.leaveFee = 0.001 this.error = false @@ -42,144 +47,242 @@ class ChatRightPanel extends LitElement { this.observerHandler = this.observerHandler.bind(this) this.viewElement = '' this.downObserverElement = '' + this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address + this.openTipUser = false + this.userName = {} } -static get styles() { -return css` - .top-bar-icon { + static get styles() { + return css` + .top-bar-icon { + cursor: pointer; + height: 18px; + width: 18px; + transition: 0.2s all; + } + + .top-bar-icon:hover { + color: var(--black); + } + + .modal-button { + font-family: Roboto, sans-serif; + font-size: 16px; + color: var(--mdc-theme-primary); + background-color: transparent; + padding: 8px 10px; + border-radius: 5px; + border: none; + transition: all 0.3s ease-in-out; + } + + .close-row { + width: 100%; + display: flex; + justify-content: flex-end; + height: 50px; + flex:0 + + } + + .container-body { + width: 100%; + display: flex; + flex-direction: column; + flex-grow: 1; + overflow:auto; + margin-top: 5px; + padding: 0px 6px; + box-sizing: border-box; + } + + .container-body::-webkit-scrollbar-track { + background-color: whitesmoke; + border-radius: 7px; + } + + .container-body::-webkit-scrollbar { + width: 6px; + border-radius: 7px; + background-color: whitesmoke; + } + + .container-body::-webkit-scrollbar-thumb { + background-color: rgb(180, 176, 176); + border-radius: 7px; + transition: all 0.3s ease-in-out; + } + + .container-body::-webkit-scrollbar-thumb:hover { + background-color: rgb(148, 146, 146); + cursor: pointer; + } + + p { + color: var(--black); + margin: 0px; + padding: 0px; + word-break: break-all; + } + + .container { + display: flex; + width: 100%; + flex-direction: column; + height: 100%; + } + + .chat-right-panel-label { + font-family: Montserrat, sans-serif; + color: var(--group-header); + padding: 5px; + font-size: 13px; + user-select: none; + } + + .group-info { + display: flex; + flex-direction: column; + justify-content: flex-start; + gap: 10px; + } + + .group-name { + font-family: Raleway, sans-serif; + font-size: 20px; + color: var(--chat-bubble-msg-color); + text-align: center; + user-select: none; + } + + .group-description { + font-family: Roboto, sans-serif; + color: var(--chat-bubble-msg-color); + letter-spacing: 0.3px; + font-weight: 300; + font-size: 14px; + margin-top: 15px; + word-break: break-word; + user-select: none; + } + + .group-subheader { + font-family: Montserrat, sans-serif; + font-size: 14px; + color: var(--chat-bubble-msg-color); + } + + .group-data { + font-family: Roboto, sans-serif; + letter-spacing: 0.3px; + font-weight: 300; + font-size: 14px; + color: var(--chat-bubble-msg-color); + } + + .user-info-header { + font-family: Montserrat, sans-serif; + text-align: center; + font-size: 25px; + color: var(--chat-bubble-msg-color); + margin-bottom: 10px; + padding: 10px 0; + user-select: none; + } + + .send-message-button { + font-family: Roboto, sans-serif; + letter-spacing: 0.3px; + font-weight: 300; + padding: 8px 5px; + border-radius: 3px; + text-align: center; + color: var(--mdc-theme-primary); + transition: all 0.3s ease-in-out; + } + + .send-message-button:hover { cursor: pointer; - height: 18px; - width: 18px; - transition: 0.2s all; - } + background-color: #03a8f485; + } - .top-bar-icon:hover { - color: var(--black); - } + .close-icon { + position: absolute; + top: 3px; + right: 5px; + color: #676b71; + width: 14px; + transition: all 0.1s ease-in-out; + } - .modal-button { - font-family: Roboto, sans-serif; - font-size: 16px; - color: var(--mdc-theme-primary); - background-color: transparent; - padding: 8px 10px; - border-radius: 5px; - border: none; - transition: all 0.3s ease-in-out; - } + .close-icon:hover { + cursor: pointer; + color: #494c50; + } - .close-row { - width: 100%; - display: flex; - justify-content: flex-end; - height: 50px; - flex:0 + .tip-user-header { + display: flex; + justify-content: center; + align-items: center; + padding: 12px; + border-bottom: 1px solid whitesmoke; + gap: 25px; + } - } + .tip-user-header-font { + font-family: Montserrat, sans-serif; + font-size: 20px; + color: var(--chat-bubble-msg-color); + } - .container-body { - width: 100%; - display: flex; - flex-direction: column; - flex-grow: 1; - overflow:auto; - margin-top: 5px; - padding: 0px 6px; - box-sizing: border-box; - } + .tip-user-body { + display: flex; + justify-content: flex-start; + align-items: center; + padding: 15px 10px; + } - .container-body::-webkit-scrollbar-track { - background-color: whitesmoke; - border-radius: 7px; - } - - .container-body::-webkit-scrollbar { - width: 6px; - border-radius: 7px; - background-color: whitesmoke; - } - - .container-body::-webkit-scrollbar-thumb { - background-color: rgb(180, 176, 176); - border-radius: 7px; - transition: all 0.3s ease-in-out; - } + .tip-input { + width: 300px; + margin-bottom: 15px; + outline: 0; + border-width: 0 0 2px; + border-color: var(--mdc-theme-primary); + background-color: transparent; + padding: 10px; + font-family: Roboto, sans-serif; + font-size: 15px; + color: var(--chat-bubble-msg-color); + } - .container-body::-webkit-scrollbar-thumb:hover { - background-color: rgb(148, 146, 146); - cursor: pointer; - } + .tip-input::selection { + background-color: var(--mdc-theme-primary); + color: white; + } - p { - color: var(--black); - margin: 0px; - padding: 0px; - word-break: break-all; - } + .tip-input::placeholder { + opacity: 0.9; + color: var(--black); + } - .container { - display: flex; - width: 100%; - flex-direction: column; - height: 100%; + ` } - .chat-right-panel-label { - font-family: Montserrat, sans-serif; - color: var(--group-header); - padding: 5px; - font-size: 13px; - user-select: none; - } - - .group-info { - display: flex; - flex-direction: column; - justify-content: flex-start; - gap: 10px; - } - - .group-name { - font-family: Raleway, sans-serif; - font-size: 20px; - color: var(--chat-bubble-msg-color); - text-align: center; - user-select: none; - } - - .group-description { - font-family: Roboto, sans-serif; - color: var(--chat-bubble-msg-color); - letter-spacing: 0.3px; - font-weight: 300; - font-size: 14px; - margin-top: 15px; - word-break: break-word; - user-select: none; - } - - .group-subheader { - font-family: Montserrat, sans-serif; - font-size: 14px; - color: var(--chat-bubble-msg-color); - } - - .group-data { - font-family: Roboto, sans-serif; - letter-spacing: 0.3px; - font-weight: 300; - font-size: 14px; - color: var(--chat-bubble-msg-color); - } -` -} - firstUpdated() { this.viewElement = this.shadowRoot.getElementById('viewElement'); this.downObserverElement = this.shadowRoot.getElementById('downObserver'); this.elementObserver(); } + async updated(changedProperties) { + if (changedProperties && changedProperties.has('selectedHead')) { + if (this.selectedHead !== {}) { + const userName = await getUserNameFromAddress(this.selectedHead.address); + this.userName = userName; + } + } + } + timeIsoString(timestamp) { let myTimestamp = timestamp === undefined ? 1587560082346 : timestamp let time = new Date(myTimestamp) @@ -212,7 +315,7 @@ return css` if (myRef && myRef.type) { clearInterval(interval) this.isLoading = false - this.isOpenLeaveModal = false + this.openUserInfo = false } } catch (error) {} stop = false @@ -437,106 +540,143 @@ return css` } render() { console.log('this.groupMembers', this.groupMembers); - console.log(5, "Chat Right Panel Here"); + console.log(18, "Chat Right Panel Here"); const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner) return html`
-
- this.toggle(false)} style="margin: 0px 10px" icon="vaadin:close" slot="icon"> -
-
-

${this.leaveGroupObj && this.leaveGroupObj.groupName}

-
-

${this.leaveGroupObj && this.leaveGroupObj.description}

-

Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}

- -

Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}

+
+ this.toggle(false)} style="margin: 0px 10px" icon="vaadin:close" slot="icon"> +
+
+

${this.leaveGroupObj && this.leaveGroupObj.groupName}

+
+

${this.leaveGroupObj && this.leaveGroupObj.description}

+

Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}

+ +

Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}

+
+
+

GROUP OWNER

+ ${owner.map((item) => { + return html` { + if (val.address === this.myAddress) return; + console.log({ val }); + this.selectedHead = val; + this.openUserInfo = true; + }} + chatInfo=${JSON.stringify(item)} + >` + })} +

ADMINS

+ ${this.groupAdmin.map((item) => { + return html` { + if (val.address === this.myAddress) return; + console.log({ val }); + this.selectedHead = val; + this.openUserInfo = true; + }} + chatInfo=${JSON.stringify(item)} + >` + })} +

MEMBERS

+ ${this.groupMembers.map((item) => { + return html` { + if (val.address === this.myAddress) return; + console.log({ val }); + this.selectedHead = val; + this.openUserInfo = true; + }} + chatInfo=${JSON.stringify(item)} + >` + })} +
-
-

GROUP OWNER

- ${owner.map((item) => { - return html` {}} - chatInfo=${JSON.stringify(item)} - >` - })} -

ADMINS

- ${this.groupAdmin.map((item) => { - return html` {}} - chatInfo=${JSON.stringify(item)} - >` - })} -

MEMBERS

- ${this.groupMembers.map((item) => { - return html` { - console.log({ val }) - this.selectedHead = val - this.isOpenLeaveModal = true - }} - chatInfo=${JSON.stringify(item)} - >` - })} -
-
{ - if (this.isLoading) return - this.isOpenLeaveModal = false - }} - style=${ - this.isOpenLeaveModal ? "display: block" : "display: none" - }> -
-

${translate("grouppage.gchange35")}

-
-
- - - -
- - - ${translate("grouppage.gchange36")}   - - - - - ${this.message} - -
- - - -
+ this.openTipUser = true + this.openUserInfo = false + this.chatEditor.disable(); + }}> + ${translate("grouppage.gchange57")} +
+
+ + + ${translate("grouppage.gchange36")}   + + + + + ${this.message} +
+
+ + { + this.openTipUser = false; + this.chatEditor.enable(); + }} + style=${this.openTipUser ? "display: block" : "display: none"}> +
+ +

${translate("grouppage.gchange55")} ${this.userName}

+
+

${translate("grouppage.gchange59")}

+ +
+
+
+
` } } diff --git a/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js b/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js new file mode 100644 index 00000000..ded1de96 --- /dev/null +++ b/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js @@ -0,0 +1,20 @@ +import { Epml } from '../../epml.js'; + +const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) + +export const getUserNameFromAddress = async (address) => { + try { + const getNames = await parentEpml.request("apiCall", { + type: "api", + url: `/names/address/${address}`, + }); + + if (Array.isArray(getNames) && getNames.length > 0 ) { + return getNames[0].name; + } else { + return address; + } + } catch (error) { + console.error(error); + } +} \ No newline at end of file From b58d3f90a91500889b60d5853a4375ca2366cec7 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Wed, 4 Jan 2023 13:46:19 -0500 Subject: [PATCH 02/19] Continued styling of the tip user --- qortal-ui-core/language/us.json | 3 +- .../plugins/core/components/ChatRightPanel.js | 37 ++++++++++++++++--- .../plugins/utils/getUserNameFromAddress.js | 3 +- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index c8fa70b4..607af4d0 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -589,7 +589,8 @@ "gchange56": "SEND MESSAGE", "gchange57": "TIP USER", "gchange58": "Tip Amount", - "gchange59": "Available Balance" + "gchange59": "Available Balance", + "gchange60": "Failed to Fetch QORT Balance. Try again!" }, "puzzlepage": { "pchange1": "Puzzles", diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index 001bd0f3..4ba79ba6 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -29,7 +29,8 @@ class ChatRightPanel extends LitElement { setOpenPrivateMessage: { attribute: false }, openTipUser: { type: Boolean }, userName: { type: String }, - chatEditor: { type: Object } + chatEditor: { type: Object }, + walletBalance: { type: Number } } } @@ -237,9 +238,11 @@ class ChatRightPanel extends LitElement { .tip-user-body { display: flex; - justify-content: flex-start; - align-items: center; - padding: 15px 10px; + justify-content: center; + align-items: flex-start; + padding: 20px 10px; + flex-direction: column; + gap: 15px; } .tip-input { @@ -272,6 +275,7 @@ class ChatRightPanel extends LitElement { this.viewElement = this.shadowRoot.getElementById('viewElement'); this.downObserverElement = this.shadowRoot.getElementById('downObserver'); this.elementObserver(); + this.fetchWalletDetails(); } async updated(changedProperties) { @@ -538,9 +542,30 @@ class ChatRightPanel extends LitElement { this.getMoreMembers(this.leaveGroupObj.groupId) } } + + getApiKey() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + let apiKey = myNode.apiKey; + return apiKey; + } + + async fetchWalletDetails() { + parentEpml.request('apiCall', { + url: `/addresses/balance/${this.myAddress}?apiKey=${this.getApiKey()}`, + }) + .then((res) => { + if (isNaN(Number(res))) { + let snack4string = get("grouppage.gchange60") + parentEpml.request('showSnackBar', `${snack4string}`) + } else { + this.walletBalance = Number(res).toFixed(8); + } + }) + } + render() { console.log('this.groupMembers', this.groupMembers); - console.log(18, "Chat Right Panel Here"); + console.log(20, "Chat Right Panel Here"); const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner) return html`
@@ -671,7 +696,7 @@ class ChatRightPanel extends LitElement {

${translate("grouppage.gchange55")} ${this.userName}

-

${translate("grouppage.gchange59")}

+

${translate("grouppage.gchange59")}: ${this.walletBalance} QORT

diff --git a/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js b/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js index ded1de96..f8f02a53 100644 --- a/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js +++ b/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js @@ -1,4 +1,5 @@ import { Epml } from '../../epml.js'; +import { cropAddress } from './cropAddress.js'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) @@ -12,7 +13,7 @@ export const getUserNameFromAddress = async (address) => { if (Array.isArray(getNames) && getNames.length > 0 ) { return getNames[0].name; } else { - return address; + return cropAddress(address); } } catch (error) { console.error(error); From 811957d900684f13853c766b216a398745c47a28 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Thu, 5 Jan 2023 16:06:57 +0100 Subject: [PATCH 03/19] Add join requests actions --- qortal-ui-core/language/de.json | 11 +- qortal-ui-core/language/es.json | 11 +- qortal-ui-core/language/fr.json | 11 +- qortal-ui-core/language/hindi.json | 13 +- qortal-ui-core/language/hr.json | 13 +- qortal-ui-core/language/hu.json | 11 +- qortal-ui-core/language/it.json | 11 +- qortal-ui-core/language/ko.json | 11 +- qortal-ui-core/language/no.json | 11 +- qortal-ui-core/language/pl.json | 13 +- qortal-ui-core/language/pt.json | 11 +- qortal-ui-core/language/ro.json | 11 +- qortal-ui-core/language/rs.json | 11 +- qortal-ui-core/language/ru.json | 11 +- qortal-ui-core/language/us.json | 11 +- qortal-ui-core/language/zhc.json | 11 +- qortal-ui-core/language/zht.json | 11 +- .../group-management/group-management.src.js | 348 ++++++++++++++++++ 18 files changed, 521 insertions(+), 20 deletions(-) diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index e197a97e..f10ddfe7 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index 0312fa3f..4ae55367 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index d677edd0..03b21617 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -799,6 +799,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 !" } } diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index a35856f4..02479e0f 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -799,7 +799,16 @@ "mg48":"क्या आप वाकई इस सदस्य के लिए आमंत्रण रद्द करना चाहते हैं?", "mg49":"पुष्टि करें दबाने पर, रद्द आमंत्रण अनुरोध भेजा जाएगा!", "mg50":"जल्द ही आ रहा है ...", - "mg51": "न्यूनतम 3 वर्ण / अधिकतम 32 वर्ण", - "mg52": "अधिकतम 128 वर्ण" + "mg51":"न्यूनतम 3 वर्ण / अधिकतम 32 वर्ण", + "mg52":"अधिकतम 128 वर्ण", + "mg53":"आपका खुला शामिल होने का अनुरोध", + "mg54":"नो ओपन जॉइन रिक्वेस्ट", + "mg55":"क्या आप निश्चित रूप से इस सदस्य के शामिल होने के अनुरोध को स्वीकार करना चाहते हैं?", + "mg56":"पुष्टि करें दबाने पर, स्वीकार करने का अनुरोध भेजा जाएगा!", + "mg57":"जुड़ने का अनुरोध सफलतापूर्वक स्वीकार किया गया", + "mg58":"कुछ गलत हो गया", + "mg59":"रद्द करें शामिल होने का अनुरोध सफलतापूर्वक स्वीकार किया गया", + "mg60":"क्या आप निश्चित रूप से इस सदस्य के शामिल होने के अनुरोध को रद्द करना चाहते हैं?", + "mg61":"पुष्टि करें दबाने पर, रद्द करने का अनुरोध भेजा जाएगा!" } } diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index 8478c342..dc066af8 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -798,7 +798,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!" } } diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index 6fdc4f54..76f9fed4 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index 7cea8646..42e55e2e 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index edd76c68..2124eec4 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -799,6 +799,15 @@ "mg49":"확인을 누르면 초대 취소 요청이 전송됩니다!", "mg50":"출시 예정...", "mg51":"최소 3자 / 최대 32자", - "mg52":"최대 128자" + "mg52":"최대 128자", + "mg53":"귀하의 오픈 조인 요청", + "mg54":"오픈 조인 요청 없음", + "mg55":"이 회원의 가입 요청을 수락하시겠습니까?", + "mg56":"확인을 누르면 가입 수락 요청이 전송됩니다!", + "mg57":"가입 요청이 성공적으로 수락됨", + "mg58":"뭔가 잘못되었습니다", + "mg59":"가입 요청 취소 성공", + "mg60":"이 회원의 가입 요청을 취소하시겠습니까?", + "mg61":"확인을 누르면 가입 취소 요청이 전송됩니다!" } } diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index 24e94b7d..a38abbe8 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index cd4f76c3..aff8fbd4 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -798,7 +798,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!" } } diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index bce9759d..035986c0 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index 97861bf6..891a0be4 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -799,6 +799,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ă!" } } diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index 0670c642..432280f7 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index 1828a4af..e40c5ae3 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -799,6 +799,15 @@ "mg49":"При нажатии подтверждения будет отправлен запрос на отмену приглашения!", "mg50":"Скоро...", "mg51":"Минимум 3 символа / максимум 32 символа", - "mg52":"Максимум 128 символов" + "mg52":"Максимум 128 символов", + "mg53":"Ваши открытые запросы на вступление", + "mg54":"Открытых запросов на присоединение нет", + "mg55":"Вы уверены, что принимаете запрос на вступление от этого участника?", + "mg56":"При нажатии подтверждения будет отправлен запрос на присоединение!", + "mg57":"Запрос на присоединение успешно принят", + "mg58":"ЧТО-ТО ПОШЛО НЕ ТАК", + "mg59":"Запрос на отмену присоединения успешно принят", + "mg60":"Вы уверены, что отмените запрос на вступление от этого участника?", + "mg61":"При нажатии кнопки подтверждения будет отправлен запрос на отмену присоединения!" } } diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index c50aa9ec..7da41ef0 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -799,6 +799,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!" } } diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index c034caf0..dfd1d98d 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -799,6 +799,15 @@ "mg49":"按下确认后,将发送取消邀请请求!", "mg50":"即将推出……", "mg51":"最少 3 个字符 / 最多 32 个字符", - "mg52":"最多 128 个字符" + "mg52":"最多 128 个字符", + "mg53":"您的公开加入请求", + "mg54":"没有开放的加入请求", + "mg55":"您确定接受该会员的加入请求吗?", + "mg56":"按下确认后,将发送接受加入请求!", + "mg57":"成功接受加入请求", + "mg58":"出了点问题", + "mg59":"取消加入请求已成功接受", + "mg60":"您确定要取消该会员的加入请求吗?", + "mg61":"按下确认后,将发送取消加入请求!" } } diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index 94e0c663..7572a9df 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -799,6 +799,15 @@ "mg49":"按下確認後,將發送取消邀請請求!", "mg50":"即將推出……", "mg51":"最少 3 個字符 / 最多 32 個字符", - "mg52":"最多 128 個字符" + "mg52":"最多 128 個字符", + "mg53":"您的公開加入請求", + "mg54":"沒有開放的加入請求", + "mg55":"您確定接受該會員的加入請求嗎?", + "mg56":"按下確認後,將發送接受加入請求!", + "mg57":"成功接受加入請求", + "mg58":"出了點問題", + "mg59":"取消加入請求已成功接受", + "mg60":"您確定要取消該會員的加入請求嗎?", + "mg61":"按下確認後,將發送取消加入請求!" } } diff --git a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js index db52b313..14a0388b 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js +++ b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js @@ -38,6 +38,7 @@ class GroupManagement extends LitElement { newAdminsList: { type: Array }, newBannedList: { type: Array }, newGroupInvitesList: { type: Array }, + newGroupJoinsList: { type: Array }, recipientPublicKey: { type: String }, selectedAddress: { type: Object }, manageGroupObj: { type: Object }, @@ -155,6 +156,11 @@ class GroupManagement extends LitElement { color: red; } + .success-icon { + font-size: 48px; + color: #198754; + } + .close-icon { font-size: 36px; } @@ -436,6 +442,7 @@ class GroupManagement extends LitElement { this.newAdminsList = [] this.newBannedList = [] this.newGroupInvitesList = [] + this.newGroupJoinsList = [] this.manageGroupObj = {} this.joinGroupObj = {} this.leaveGroupObj = {} @@ -836,6 +843,7 @@ class GroupManagement extends LitElement { groupInviteTemplate() { return html` +

${translate("managegroup.mg36")}

${translate("managegroup.mg35")} ` : html``} +


+

${translate("managegroup.mg53")}

+ + { + render(html`${this.renderAvatar(data.item)}`, root) + }} + > + { + render(html`${data.item.name}`, root) + }} + > + { + render(html`${data.item.owner}`, root) + }} + > + { + render(html`${this.renderConfirmRequestButton(data.item)}`, root) + }} + > + { + render(html`${this.renderDeclineRequestButton(data.item)}`, root) + }} + > + + ${this.isEmptyArray(this.newGroupJoinsList) ? html` + ${translate("managegroup.mg54")} + ` : html``} +
+
this.openInviteMemberToGroupDialog()}> ${translate("managegroup.mg2")} @@ -1033,6 +1089,72 @@ class GroupManagement extends LitElement { ${translate("general.close")} + + +
+ group_add +

${translate("managegroup.mg57")}

+

${translate("walletpage.wchange43")}

+
+ + this.closeSuccessJoinDialog()} + class="red" + > + ${translate("general.close")} + +
+ + +
+ warning +

${translate("managegroup.mg58")}

+

${this.errorMessage}

+

${translate("walletpage.wchange44")}

+
+ + this.closeErrorJoinDialog()} + class="red" + > + ${translate("general.close")} + +
+ + +
+ person_remove +

${translate("managegroup.mg59")}

+

${translate("walletpage.wchange43")}

+
+ + this.closeCancelSuccessJoinDialog()} + class="red" + > + ${translate("general.close")} + +
+ + +
+ warning +

${translate("managegroup.mg58")}

+

${this.errorMessage}

+

${translate("walletpage.wchange44")}

+
+ + this.closeCancelErrorJoinDialog()} + class="red" + > + ${translate("general.close")} + +
` } @@ -1986,6 +2108,38 @@ class GroupManagement extends LitElement { this.errorMessage = '' } + renderConfirmRequestButton(joinObj) { + return html` this.createAcceptJoinGroupMember(joinObj)}>add_task ${translate("transpage.tchange3")}` + } + + renderDeclineRequestButton(joinObj) { + return html` this.kickJoinGroupMember(joinObj)}>cancel ${translate("transpage.tchange2")}` + } + + 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 @@ -2361,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() @@ -2389,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() } @@ -3057,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 From abf736c6400b1ed5dd7f989d54ce4cef4ab8c3c7 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Thu, 5 Jan 2023 16:55:34 +0100 Subject: [PATCH 04/19] Add time elements --- qortal-ui-plugins/plugins/core/components/TimeAgo.js | 2 +- .../plugins/core/group-management/group-management.src.js | 2 +- qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/components/TimeAgo.js b/qortal-ui-plugins/plugins/core/components/TimeAgo.js index c212a736..ca3633b7 100644 --- a/qortal-ui-plugins/plugins/core/components/TimeAgo.js +++ b/qortal-ui-plugins/plugins/core/components/TimeAgo.js @@ -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() { diff --git a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js index 14a0388b..edcfd254 100644 --- a/qortal-ui-plugins/plugins/core/group-management/group-management.src.js +++ b/qortal-ui-plugins/plugins/core/group-management/group-management.src.js @@ -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 }) diff --git a/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js b/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js index de4e77ed..197248f4 100644 --- a/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js +++ b/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js @@ -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' From 1a2a877a9dfc06ad1a194f0a6c06767667d36649 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Thu, 5 Jan 2023 16:57:26 +0100 Subject: [PATCH 05/19] JS files --- .../time-elements/extended-time-element.js | 87 +++ .../core/components/time-elements/index.js | 705 ++++++++++++++++++ .../time-elements/local-time-element.js | 81 ++ .../time-elements/relative-time-element.js | 44 ++ .../components/time-elements/relative-time.js | 290 +++++++ .../time-elements/time-ago-element.js | 21 + .../time-elements/time-until-element.js | 21 + .../core/components/time-elements/utils.js | 166 +++++ 8 files changed, 1415 insertions(+) create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/extended-time-element.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/index.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/local-time-element.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/relative-time-element.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/relative-time.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/time-ago-element.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/time-until-element.js create mode 100644 qortal-ui-plugins/plugins/core/components/time-elements/utils.js diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/extended-time-element.js b/qortal-ui-plugins/plugins/core/components/time-elements/extended-time-element.js new file mode 100644 index 00000000..583dee79 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/extended-time-element.js @@ -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' +}); diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/index.js b/qortal-ui-plugins/plugins/core/components/time-elements/index.js new file mode 100644 index 00000000..8b3dbe4c --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/index.js @@ -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 }; diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/local-time-element.js b/qortal-ui-plugins/plugins/core/components/time-elements/local-time-element.js new file mode 100644 index 00000000..3494d218 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/local-time-element.js @@ -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); +} diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/relative-time-element.js b/qortal-ui-plugins/plugins/core/components/time-elements/relative-time-element.js new file mode 100644 index 00000000..5654e08d --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/relative-time-element.js @@ -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); +} diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/relative-time.js b/qortal-ui-plugins/plugins/core/components/time-elements/relative-time.js new file mode 100644 index 00000000..a2b4a6e5 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/relative-time.js @@ -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' }); diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/time-ago-element.js b/qortal-ui-plugins/plugins/core/components/time-elements/time-ago-element.js new file mode 100644 index 00000000..6ac6b25a --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/time-ago-element.js @@ -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); +} diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/time-until-element.js b/qortal-ui-plugins/plugins/core/components/time-elements/time-until-element.js new file mode 100644 index 00000000..2b57a845 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/time-until-element.js @@ -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); +} diff --git a/qortal-ui-plugins/plugins/core/components/time-elements/utils.js b/qortal-ui-plugins/plugins/core/components/time-elements/utils.js new file mode 100644 index 00000000..7bf4b1e7 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/time-elements/utils.js @@ -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'; +} From ec22beb513754066bb57ed2c094180a760ee6b35 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Thu, 5 Jan 2023 17:01:36 +0100 Subject: [PATCH 06/19] Update deps --- qortal-ui-core/package.json | 4 ++-- qortal-ui-plugins/package.json | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index 7cdec4ba..d5b00b64 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -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" diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index 88dfd7af..ad9f149a 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -22,8 +22,7 @@ "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js" }, "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", @@ -59,11 +58,11 @@ "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" }, "engines": { "node": ">=16.17.1" } -} +} \ No newline at end of file From 631cffeb217bacae062b592d8680aaf9087456b0 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Fri, 6 Jan 2023 14:13:13 -0500 Subject: [PATCH 07/19] Tip user completed --- qortal-ui-core/language/us.json | 463 +++++++++--------- qortal-ui-plugins/package.json | 6 +- .../plugins/core/components/ChatPage.js | 28 +- .../plugins/core/components/ChatRightPanel.js | 385 ++------------- .../plugins/core/components/TipUser-css.js | 85 ++++ .../plugins/core/components/TipUser.js | 282 +++++++++++ .../plugins/utils/getUserNameFromAddress.js | 2 +- 7 files changed, 670 insertions(+), 581 deletions(-) create mode 100644 qortal-ui-plugins/plugins/core/components/TipUser-css.js create mode 100644 qortal-ui-plugins/plugins/core/components/TipUser.js diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 7958a057..66517cf1 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -21,22 +21,22 @@ "korean": "Korean" }, "sidemenu": { - "minting":"MINTING", - "mintingdetails":"MINTING DETAILS", - "becomeAMinter":"BECOME A MINTER", - "wallets":"WALLETS", - "tradeportal":"TRADE PORTAL", - "rewardshare":"REWARD SHARE", - "nameregistration":"NAME REGISTRATION", - "websites":"WEBSITES", - "management":"MANAGEMENT", - "datamanagement":"DATA MANAGEMENT", - "qchat":"Q-CHAT", - "groupmanagement":"GROUP MANAGEMENT", - "puzzles":"PUZZLES", - "nodemanagement":"NODE MANAGEMENT", - "trading":"TRADING", - "groups":"GROUPS" + "minting": "MINTING", + "mintingdetails": "MINTING DETAILS", + "becomeAMinter": "BECOME A MINTER", + "wallets": "WALLETS", + "tradeportal": "TRADE PORTAL", + "rewardshare": "REWARD SHARE", + "nameregistration": "NAME REGISTRATION", + "websites": "WEBSITES", + "management": "MANAGEMENT", + "datamanagement": "DATA MANAGEMENT", + "qchat": "Q-CHAT", + "groupmanagement": "GROUP MANAGEMENT", + "puzzles": "PUZZLES", + "nodemanagement": "NODE MANAGEMENT", + "trading": "TRADING", + "groups": "GROUPS" }, "login": { "login": "Login", @@ -130,32 +130,32 @@ "snack4": "Nodes successfully saved as", "snack5": "Nodes successfully imported" }, - "appinfo":{ - "blockheight":"Block Height", - "uiversion":"UI Version", - "coreversion":"Core Version", - "minting":"(Minting)", - "synchronizing":"Synchronizing", - "peers":"Connected Peers" + "appinfo": { + "blockheight": "Block Height", + "uiversion": "UI Version", + "coreversion": "Core Version", + "minting": "(Minting)", + "synchronizing": "Synchronizing", + "peers": "Connected Peers" }, "walletprofile": { "minterlevel": "Minter Level", "blocksminted": "Blocks Minted" }, - "general":{ - "yes":"Yes", - "no":"No", - "confirm":"Confirm", - "decline":"Decline", - "open":"Open", - "close":"Close", - "back":"Back", - "next":"Next", - "create":"Create", - "continue":"Continue", - "save":"Save", - "balance":"Balance", - "balances":"YOUR WALLET BALANCES" + "general": { + "yes": "Yes", + "no": "No", + "confirm": "Confirm", + "decline": "Decline", + "open": "Open", + "close": "Close", + "back": "Back", + "next": "Next", + "create": "Create", + "continue": "Continue", + "save": "Save", + "balance": "Balance", + "balances": "YOUR WALLET BALANCES" }, "startminting": { "smchange1": "Cannot fetch minting accounts", @@ -280,55 +280,55 @@ "wchange56": "WARNING!", "wchange57": "Memo" }, - "tradepage":{ - "tchange1":"Trade Portal", - "tchange2":"Select Trading Pair", - "tchange3":"HISTORIC MARKET TRADES", - "tchange4":"MY TRADE HISTORY", - "tchange5":"OPEN MARKET SELL ORDERS", - "tchange6":"MY ORDERS", - "tchange7":"Stuck Offers", - "tchange8":"Amount", - "tchange9":"Price", - "tchange10":"Total", - "tchange11":"Date", - "tchange12":"Status", - "tchange13":"Seller", - "tchange14":"Price Each", - "tchange15":"Clear Form", - "tchange16":"You have", - "tchange17":"Action", - "tchange18":"BUY", - "tchange19":"SELL", - "tchange20":"Failed to Create Trade. Try again!", - "tchange21":"Failed to Create Trade. Error Code", - "tchange22":"Insufficient Funds!", - "tchange23":"Buy Request Successful!", - "tchange24":"Buy Request Existing!", - "tchange25":"Failed to Create Trade. Error Code", - "tchange26":"Trade Cancelling In Progress!", - "tchange27":"Failed to Cancel Trade. Try again!", - "tchange28":"Failed to Cancel Trade. Error Code", - "tchange29":"CANCEL", - "tchange30":"Failed to Fetch Balance. Try again!", - "tchange31":"SOLD", - "tchange32":"BOUGHT", - "tchange33":"Average", - "tchange34":"Amount can not be 0", - "tchange35":"Price can not be 0", - "tchange36":"PENDING AUTO BUY", - "tchange37":"No auto buy order found !", - "tchange38":"ADD", - "tchange39":"AUTO BUY ORDER", - "tchange40":"Price", - "tchange41":"Successfully removed auto buy order!", - "tchange42":"MARKET OPEN SELL ORDERS", - "tchange43":"MY BUY HISTORY", - "tchange44":"Successfully added auto buy order!", - "tchange45":"AUTO BUY WITH", - "tchange46":"AUTO BUY", - "tchange47":"Sell for this price", - "tchange48":"NOT ENOUGH" + "tradepage": { + "tchange1": "Trade Portal", + "tchange2": "Select Trading Pair", + "tchange3": "HISTORIC MARKET TRADES", + "tchange4": "MY TRADE HISTORY", + "tchange5": "OPEN MARKET SELL ORDERS", + "tchange6": "MY ORDERS", + "tchange7": "Stuck Offers", + "tchange8": "Amount", + "tchange9": "Price", + "tchange10": "Total", + "tchange11": "Date", + "tchange12": "Status", + "tchange13": "Seller", + "tchange14": "Price Each", + "tchange15": "Clear Form", + "tchange16": "You have", + "tchange17": "Action", + "tchange18": "BUY", + "tchange19": "SELL", + "tchange20": "Failed to Create Trade. Try again!", + "tchange21": "Failed to Create Trade. Error Code", + "tchange22": "Insufficient Funds!", + "tchange23": "Buy Request Successful!", + "tchange24": "Buy Request Existing!", + "tchange25": "Failed to Create Trade. Error Code", + "tchange26": "Trade Cancelling In Progress!", + "tchange27": "Failed to Cancel Trade. Try again!", + "tchange28": "Failed to Cancel Trade. Error Code", + "tchange29": "CANCEL", + "tchange30": "Failed to Fetch Balance. Try again!", + "tchange31": "SOLD", + "tchange32": "BOUGHT", + "tchange33": "Average", + "tchange34": "Amount can not be 0", + "tchange35": "Price can not be 0", + "tchange36": "PENDING AUTO BUY", + "tchange37": "No auto buy order found !", + "tchange38": "ADD", + "tchange39": "AUTO BUY ORDER", + "tchange40": "Price", + "tchange41": "Successfully removed auto buy order!", + "tchange42": "MARKET OPEN SELL ORDERS", + "tchange43": "MY BUY HISTORY", + "tchange44": "Successfully added auto buy order!", + "tchange45": "AUTO BUY WITH", + "tchange46": "AUTO BUY", + "tchange47": "Sell for this price", + "tchange48": "NOT ENOUGH" }, "rewardsharepage": { "rchange1": "Rewardshares", @@ -354,47 +354,47 @@ "rchange21": "Reward Share Successful!", "rchange22": "Reward Share Removed Successfully!" }, - "registernamepage":{ - "nchange1":"Name Registration", - "nchange2":"Register Name", - "nchange3":"Registered Names", - "nchange4":"Avatar", - "nchange5":"Name", - "nchange6":"Owner", - "nchange7":"Action", - "nchange8":"No names registered by this account!", - "nchange9":"Register a Name!", - "nchange10":"Description (optional)", - "nchange11":"Doing something delicious", - "nchange12":"Registering Name", - "nchange13":"The current name registration fee is", - "nchange14":"Register", - "nchange15":"Set Avatar", - "nchange16":"Need Core Update", - "nchange17":"Name Already Exists!", - "nchange18":"Name Registration Successful!", - "nchange19":"Sell Name", - "nchange20":"Cancel Sell", - "nchange21":"Buy Name", - "nchange22":"Open Market Names To Sell", - "nchange23":"Sell Price", - "nchange24":"No Names To Sell", - "nchange25":"Name To Sell", - "nchange26":"Are you sure to sell this name ?", - "nchange27":"For this price in QORT", - "nchange28":"On pressing confirm, the sell name request will be sent!", - "nchange29":"Name To Cancel", - "nchange30":"Are you sure to cancel the sell for this name ?", - "nchange31":"On pressing confirm, the cancel sell name request will be sent!", - "nchange32":"Sell Name Request Successful!", - "nchange33":"Cancel Sell Name Request Successful!", - "nchange34":"Buy Name Request Successful!", - "nchange35":"YOU HAVE A NAME!", - "nchange36":"Only accounts with no registered name can buy a name.", - "nchange37":"ATTENTION!", - "nchange38":"You not have enough qort to buy this name.", - "nchange39":"Are you sure to buy this name ?", - "nchange40":"On pressing confirm, the buy name request will be sent!" + "registernamepage": { + "nchange1": "Name Registration", + "nchange2": "Register Name", + "nchange3": "Registered Names", + "nchange4": "Avatar", + "nchange5": "Name", + "nchange6": "Owner", + "nchange7": "Action", + "nchange8": "No names registered by this account!", + "nchange9": "Register a Name!", + "nchange10": "Description (optional)", + "nchange11": "Doing something delicious", + "nchange12": "Registering Name", + "nchange13": "The current name registration fee is", + "nchange14": "Register", + "nchange15": "Set Avatar", + "nchange16": "Need Core Update", + "nchange17": "Name Already Exists!", + "nchange18": "Name Registration Successful!", + "nchange19": "Sell Name", + "nchange20": "Cancel Sell", + "nchange21": "Buy Name", + "nchange22": "Open Market Names To Sell", + "nchange23": "Sell Price", + "nchange24": "No Names To Sell", + "nchange25": "Name To Sell", + "nchange26": "Are you sure to sell this name ?", + "nchange27": "For this price in QORT", + "nchange28": "On pressing confirm, the sell name request will be sent!", + "nchange29": "Name To Cancel", + "nchange30": "Are you sure to cancel the sell for this name ?", + "nchange31": "On pressing confirm, the cancel sell name request will be sent!", + "nchange32": "Sell Name Request Successful!", + "nchange33": "Cancel Sell Name Request Successful!", + "nchange34": "Buy Name Request Successful!", + "nchange35": "YOU HAVE A NAME!", + "nchange36": "Only accounts with no registered name can buy a name.", + "nchange37": "ATTENTION!", + "nchange38": "You not have enough qort to buy this name.", + "nchange39": "Are you sure to buy this name ?", + "nchange40": "On pressing confirm, the buy name request will be sent!" }, "websitespage": { "schange1": "Browse Websites", @@ -541,9 +541,8 @@ "cchange38": "User Verified", "cchange39": "Cannot send an encrypted message to this user since they do not have their publickey on chain.", "cchange40": "IMAGE (click to view)", - "cchange41":"Your Balance Is Under 4.20 QORT", - "cchange42":"Out of the need to combat spam, accounts with under 4.20 Qort balance will take a long time to SEND messages in Q-Chat. If you wish to immediately increase the send speed for Q-Chat messages, obtain over 4.20 QORT to your address. This can be done with trades in the Trade Portal, or by way of another Qortian giving you the QORT. Once you have over 4.20 QORT in your account, Q-Chat messages will be instant and this dialog will no more show. Thank you for your understanding of this necessary spam prevention method, and we hope you enjoy Qortal!" - + "cchange41": "Your Balance Is Under 4.20 QORT", + "cchange42": "Out of the need to combat spam, accounts with under 4.20 Qort balance will take a long time to SEND messages in Q-Chat. If you wish to immediately increase the send speed for Q-Chat messages, obtain over 4.20 QORT to your address. This can be done with trades in the Trade Portal, or by way of another Qortian giving you the QORT. Once you have over 4.20 QORT in your account, Q-Chat messages will be instant and this dialog will no more show. Thank you for your understanding of this necessary spam prevention method, and we hope you enjoy Qortal!" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -635,7 +634,15 @@ "gchange57": "TIP USER", "gchange58": "Tip Amount", "gchange59": "Available Balance", - "gchange60": "Failed to Fetch QORT Balance. Try again!" + "gchange60": "Failed to Fetch QORT Balance. Try again!", + "gchange61": "Current static fee", + "gchange62": "Send", + "gchange63": "Insufficient Funds!", + "gchange64": "Invalid Amount!", + "gchange65": "Receiver cannot be empty!", + "gchange66": "Invalid Receiver!", + "gchange67": "Transaction Successful!", + "gchange68": "Transaction Failed!" }, "puzzlepage": { "pchange1": "Puzzles", @@ -725,104 +732,104 @@ "rewarddialog5": "You are removing a reward share transaction associated with account:", "rewarddialog6": "On pressing confirm, the rewardshare will be removed and the minting key will become invalid." }, - "sponsorshipspage":{ - "schange1":"Active Sponsorships", - "schange2":"Account Address", - "schange3":"Total Sponsorships active", - "schange4":"Next sponsorship ending in", - "schange5":"Sponsor New Minter", - "schange6":"Finished Sponsorships", - "schange7":"Completed", - "schange8":"Addresses", - "schange9":"You currently have no active sponsorships", - "schange10":"Public Key Lookup", - "schange11":"Copy", - "schange12":"Address to Public Key Converter", - "schange13":"Enter address", - "schange14":"In progress", - "schange15":"Finishing up", - "schange16":"Copy the key below and share it with your sponsored person.", - "schange17":"Copied to clipboard", - "schange18":"Warning: do not leave this plugin or close the Qortal UI until completion!", - "schange19":"Copy Sponsorship Key", - "schange20":"Creating relationship", - "schange21":"Remove Sponsorship Key" + "sponsorshipspage": { + "schange1": "Active Sponsorships", + "schange2": "Account Address", + "schange3": "Total Sponsorships active", + "schange4": "Next sponsorship ending in", + "schange5": "Sponsor New Minter", + "schange6": "Finished Sponsorships", + "schange7": "Completed", + "schange8": "Addresses", + "schange9": "You currently have no active sponsorships", + "schange10": "Public Key Lookup", + "schange11": "Copy", + "schange12": "Address to Public Key Converter", + "schange13": "Enter address", + "schange14": "In progress", + "schange15": "Finishing up", + "schange16": "Copy the key below and share it with your sponsored person.", + "schange17": "Copied to clipboard", + "schange18": "Warning: do not leave this plugin or close the Qortal UI until completion!", + "schange19": "Copy Sponsorship Key", + "schange20": "Creating relationship", + "schange21": "Remove Sponsorship Key" }, - "explorerpage":{ - "exp1":"Address or name to search", - "exp2":"Account Balance", - "exp3":"More Info", - "exp4":"Address or Name not found !", - "exp5":"Note that registered names are case-sensitive.", - "exp6":"Founder", - "exp7":"Info", - "exp8":"Show all buy trades", - "exp9":"Show all sell trades", - "exp10":"BUY HISTORY", - "exp11":"SELL HISTORY", - "exp12":"No buy trades made yet.", - "exp13":"No sell trades made yet.", - "exp14":"Show complete info", - "exp15":"Minting Since", - "exp16":"Not Minting", - "exp17":"ALL PAYMENTS", - "exp18":"Payments", - "exp19":"Sent", - "exp20":"Received", - "exp21":"Trades" + "explorerpage": { + "exp1": "Address or name to search", + "exp2": "Account Balance", + "exp3": "More Info", + "exp4": "Address or Name not found !", + "exp5": "Note that registered names are case-sensitive.", + "exp6": "Founder", + "exp7": "Info", + "exp8": "Show all buy trades", + "exp9": "Show all sell trades", + "exp10": "BUY HISTORY", + "exp11": "SELL HISTORY", + "exp12": "No buy trades made yet.", + "exp13": "No sell trades made yet.", + "exp14": "Show complete info", + "exp15": "Minting Since", + "exp16": "Not Minting", + "exp17": "ALL PAYMENTS", + "exp18": "Payments", + "exp19": "Sent", + "exp20": "Received", + "exp21": "Trades" }, - "managegroup":{ - "mg1":"Group Members", - "mg2":"Invite To Group", - "mg3":"Group Admins", - "mg4":"Update Group", - "mg5":"Close Manage Group", - "mg6":"BAN", - "mg7":"KICK", - "mg8":"Group ID", - "mg9":"Joined", - "mg10":"Add Group Admin", - "mg11":"Are you sure to add this member to admins ?", - "mg12":"On pressing confirm, add admin request will be sent!", - "mg13":"Remove Group Admin", - "mg14":"Remove Admin Address", - "mg15":"Are you sure to remove this member from admins ?", - "mg16":"On pressing confirm, remove admin request will be sent!", - "mg17":"Ban Member From Group", - "mg18":"Member Name", - "mg19":"Member Address", - "mg20":"How Long To Ban", - "mg21":"Reason For Ban", - "mg22":"Are you sure to ban this member from the group ?", - "mg23":"On pressing confirm, the ban request will be sent!", - "mg24":"FOREVER", - "mg25":"Banned Members", - "mg26":"CANCEL BAN", - "mg27":"Ban Expiry", - "mg28":"Cancel Ban Member From Group", - "mg29":"Are you sure to cancel the ban for this member from the group ?", - "mg30":"On pressing confirm, the cancel ban request will be sent!", - "mg31":"Kick Member From Group", - "mg32":"Reason For Kick", - "mg33":"Are you sure to kick this member from the group ?", - "mg34":"On pressing confirm, the kick request will be sent!", - "mg35":"No Open Group Invites", - "mg36":"Your Open Group Invites", - "mg37":"Address or name to invite", - "mg38":"Invite Expiry Time", - "mg39":"All Fields Are Required", - "mg40":"Are you sure to invite this member to the group ?", - "mg41":"On pressing confirm, the invite request will be sent!", - "mg42":"Group Type", - "mg43":"Invite Expiry", - "mg44":"Public Group", - "mg45":"Private Group", - "mg46":"Cancel Invite", - "mg47":"Cancel Invite To Group", - "mg48":"Are you sure to cancel the invite for this member ?", - "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" + "managegroup": { + "mg1": "Group Members", + "mg2": "Invite To Group", + "mg3": "Group Admins", + "mg4": "Update Group", + "mg5": "Close Manage Group", + "mg6": "BAN", + "mg7": "KICK", + "mg8": "Group ID", + "mg9": "Joined", + "mg10": "Add Group Admin", + "mg11": "Are you sure to add this member to admins ?", + "mg12": "On pressing confirm, add admin request will be sent!", + "mg13": "Remove Group Admin", + "mg14": "Remove Admin Address", + "mg15": "Are you sure to remove this member from admins ?", + "mg16": "On pressing confirm, remove admin request will be sent!", + "mg17": "Ban Member From Group", + "mg18": "Member Name", + "mg19": "Member Address", + "mg20": "How Long To Ban", + "mg21": "Reason For Ban", + "mg22": "Are you sure to ban this member from the group ?", + "mg23": "On pressing confirm, the ban request will be sent!", + "mg24": "FOREVER", + "mg25": "Banned Members", + "mg26": "CANCEL BAN", + "mg27": "Ban Expiry", + "mg28": "Cancel Ban Member From Group", + "mg29": "Are you sure to cancel the ban for this member from the group ?", + "mg30": "On pressing confirm, the cancel ban request will be sent!", + "mg31": "Kick Member From Group", + "mg32": "Reason For Kick", + "mg33": "Are you sure to kick this member from the group ?", + "mg34": "On pressing confirm, the kick request will be sent!", + "mg35": "No Open Group Invites", + "mg36": "Your Open Group Invites", + "mg37": "Address or name to invite", + "mg38": "Invite Expiry Time", + "mg39": "All Fields Are Required", + "mg40": "Are you sure to invite this member to the group ?", + "mg41": "On pressing confirm, the invite request will be sent!", + "mg42": "Group Type", + "mg43": "Invite Expiry", + "mg44": "Public Group", + "mg45": "Private Group", + "mg46": "Cancel Invite", + "mg47": "Cancel Invite To Group", + "mg48": "Are you sure to cancel the invite for this member ?", + "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" } } \ No newline at end of file diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index 4301c32a..4e813ff4 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -47,8 +47,8 @@ "@polymer/paper-slider": "3.0.1", "@polymer/paper-spinner": "3.0.2", "@polymer/paper-tooltip": "3.0.1", - "@vaadin/horizontal-layout": "23.2.5", - "@vaadin/tabs": "23.2.5", + "@vaadin/horizontal-layout": "23.3.2", + "@vaadin/tabs": "23.3.2", "@rollup/plugin-alias": "4.0.2", "@rollup/plugin-babel": "6.0.3", "@rollup/plugin-commonjs": "24.0.0", @@ -75,4 +75,4 @@ "engines": { "node": ">=16.17.1" } -} +} \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 544db34f..a50cd34c 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -1171,22 +1171,20 @@ class ChatPage extends LitElement {
-
- this.getMoreMembers(val)} - .toggle=${(val)=> this._toggle(val)} - .selectedAddress=${this.selectedAddress} - .groupMembers=${this.groupMembers} - .groupAdmin=${this.groupAdmin} - .leaveGroupObj=${this.groupInfo} - .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} - .chatEditor=${this.chatEditor} - > +
+ this.getMoreMembers(val)} + .toggle=${(val)=> this._toggle(val)} + .selectedAddress=${this.selectedAddress} + .groupMembers=${this.groupMembers} + .groupAdmin=${this.groupAdmin} + .leaveGroupObj=${this.groupInfo} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} + .chatEditor=${this.chatEditor}> - -
-
- ` + + + ` } async getMoreMembers(groupId){ diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index 4ba79ba6..4dbe8cb7 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -1,16 +1,17 @@ -import { LitElement, html, css } from "lit" -import { render } from "lit/html.js" -import { get, translate } from "lit-translate" -import { Epml } from "../../../epml" -import { getUserNameFromAddress } from "../../utils/getUserNameFromAddress" -import snackbar from "./snackbar.js" -import "@material/mwc-button" -import "@material/mwc-dialog" -import "@polymer/paper-spinner/paper-spinner-lite.js" -import "@material/mwc-icon" -import "./WrapperModal" - -const parentEpml = new Epml({ type: "WINDOW", source: window.parent }) +import { LitElement, html, css } from "lit"; +import { render } from "lit/html.js"; +import { get, translate } from "lit-translate"; +import { Epml } from "../../../epml"; +import { getUserNameFromAddress } from "../../utils/getUserNameFromAddress"; +import snackbar from "./snackbar.js"; +import "@material/mwc-button"; +import "@material/mwc-dialog"; +import "@polymer/paper-spinner/paper-spinner-lite.js"; +import '@polymer/paper-progress/paper-progress.js'; +import "@material/mwc-icon"; +import '@vaadin/button'; +import "./WrapperModal"; +import "./TipUser" class ChatRightPanel extends LitElement { static get properties() { @@ -30,7 +31,11 @@ class ChatRightPanel extends LitElement { openTipUser: { type: Boolean }, userName: { type: String }, chatEditor: { type: Object }, - walletBalance: { type: Number } + walletBalance: { type: Number }, + sendMoneyLoading: { type: Boolean }, + btnDisable: { type: Boolean }, + errorMessage: { type: String }, + successMessage: { type: String } } } @@ -50,7 +55,12 @@ class ChatRightPanel extends LitElement { this.downObserverElement = '' this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address this.openTipUser = false - this.userName = {} + this.userName = "" + this.sendMoneyLoading = false + this.btnDisable = false + this.errorMessage = "" + this.successMessage = "" + this.setOpenTipUser = this.setOpenTipUser.bind(this); } static get styles() { @@ -203,8 +213,8 @@ class ChatRightPanel extends LitElement { } .send-message-button:hover { - cursor: pointer; - background-color: #03a8f485; + cursor: pointer; + background-color: #03a8f485; } .close-icon { @@ -220,54 +230,6 @@ class ChatRightPanel extends LitElement { cursor: pointer; color: #494c50; } - - .tip-user-header { - display: flex; - justify-content: center; - align-items: center; - padding: 12px; - border-bottom: 1px solid whitesmoke; - gap: 25px; - } - - .tip-user-header-font { - font-family: Montserrat, sans-serif; - font-size: 20px; - color: var(--chat-bubble-msg-color); - } - - .tip-user-body { - display: flex; - justify-content: center; - align-items: flex-start; - padding: 20px 10px; - flex-direction: column; - gap: 15px; - } - - .tip-input { - width: 300px; - margin-bottom: 15px; - outline: 0; - border-width: 0 0 2px; - border-color: var(--mdc-theme-primary); - background-color: transparent; - padding: 10px; - font-family: Roboto, sans-serif; - font-size: 15px; - color: var(--chat-bubble-msg-color); - } - - .tip-input::selection { - background-color: var(--mdc-theme-primary); - color: white; - } - - .tip-input::placeholder { - opacity: 0.9; - color: var(--black); - } - ` } @@ -275,7 +237,6 @@ class ChatRightPanel extends LitElement { this.viewElement = this.shadowRoot.getElementById('viewElement'); this.downObserverElement = this.shadowRoot.getElementById('downObserver'); this.elementObserver(); - this.fetchWalletDetails(); } async updated(changedProperties) { @@ -287,236 +248,6 @@ class ChatRightPanel extends LitElement { } } - timeIsoString(timestamp) { - let myTimestamp = timestamp === undefined ? 1587560082346 : timestamp - let time = new Date(myTimestamp) - return time.toISOString() - } - - resetDefaultSettings() { - this.error = false - this.message = "" - this.isLoading = false - } - - renderErr9Text() { - return html`${translate("grouppage.gchange49")}` - } - - async confirmRelationship(reference) { - let interval = null - let stop = false - const getAnswer = async () => { - - - if (!stop) { - stop = true - try { - let myRef = await parentEpml.request("apiCall", { - type: "api", - url: `/transactions/reference/${reference}`, - }) - if (myRef && myRef.type) { - clearInterval(interval) - this.isLoading = false - this.openUserInfo = false - } - } catch (error) {} - stop = false - } - } - interval = setInterval(getAnswer, 5000) - } - - async unitFee(txType) { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; - const url = `${nodeUrl}/transactions/unitfee?txType=${txType}`; - let fee = null; - - try { - const res = await fetch(url); - const data = await res.json(); - fee = (Number(data) / 1e8).toFixed(3); - } catch (error) { - fee = null; - } - - return fee; - } - - async getLastRef() { - let myRef = await parentEpml.request("apiCall", { - type: "api", - url: `/addresses/lastreference/${this.selectedAddress.address}`, - }) - return myRef; - } - - getTxnRequestResponse(txnResponse, reference) { - if (txnResponse === true) { - this.message = this.renderErr9Text() - this.error = false - this.confirmRelationship(reference) - } else { - this.error = true - this.message = "" - throw new Error(txnResponse) - } - } - - async convertBytesForSigning(transactionBytesBase58) { - let convertedBytes = await parentEpml.request("apiCall", { - type: "api", - method: "POST", - url: `/transactions/convert`, - body: `${transactionBytesBase58}`, - }) - return convertedBytes - } - - async signTx(body){ - return await parentEpml.request("apiCall", { - type: "api", - method: "POST", - url: `/transactions/sign`, - body: body, - headers: { - 'Content-Type': 'application/json' - } - }) - } - - async process(body){ - return await parentEpml.request("apiCall", { - type: "api", - method: "POST", - url: `/transactions/process`, - body: body, - }) - } - async _addAdmin(groupId) { - this.resetDefaultSettings() - - const leaveFeeInput = await this.unitFee('ADD_GROUP_ADMIN') - if(!leaveFeeInput){ - throw Error() - } - this.isLoading = true - - // Get Last Ref - const getLastRef = async () => { - let myRef = await parentEpml.request('apiCall', { - type: 'api', - url: `/addresses/lastreference/${this.selectedAddress.address}` - }) - return myRef - }; - - const validateReceiver = async () => { - let lastRef = await getLastRef(); - let myTransaction = await makeTransactionRequest(lastRef) - getTxnRequestResponse(myTransaction) - - } - - // Make Transaction Request - const makeTransactionRequest = async (lastRef) => { - let groupdialog3 = get("transactions.groupdialog3") - let groupdialog4 = get("transactions.groupdialog4") - let myTxnrequest = await parentEpml.request('transaction', { - type: 24, - nonce: this.selectedAddress.nonce, - params: { - _groupId: groupId, - fee: leaveFeeInput, - member: this.selectedHead.address, - lastReference: lastRef - } - }) - return myTxnrequest - } - - const getTxnRequestResponse = (txnResponse) => { - - if (txnResponse.success === false && txnResponse.message) { - this.error = true - this.message = txnResponse.message - throw new Error(txnResponse) - } else if (txnResponse.success === true && !txnResponse.data.error) { - this.message = this.renderErr9Text() - this.error = false - this.confirmRelationship() - } else { - this.error = true - this.message = txnResponse.data.message - throw new Error(txnResponse) - } - } - validateReceiver() - } - - async _removeAdmin(groupId) { - this.resetDefaultSettings() - - const leaveFeeInput = await this.unitFee('REMOVE_GROUP_ADMIN') - if(!leaveFeeInput){ - throw Error() - } - this.isLoading = true - - // Get Last Ref - const getLastRef = async () => { - let myRef = await parentEpml.request('apiCall', { - type: 'api', - url: `/addresses/lastreference/${this.selectedAddress.address}` - }) - return myRef - }; - - const validateReceiver = async () => { - let lastRef = await getLastRef(); - let myTransaction = await makeTransactionRequest(lastRef) - getTxnRequestResponse(myTransaction) - - } - - // Make Transaction Request - const makeTransactionRequest = async (lastRef) => { - let groupdialog3 = get("transactions.groupdialog3") - let groupdialog4 = get("transactions.groupdialog4") - let myTxnrequest = await parentEpml.request('transaction', { - type: 25, - nonce: this.selectedAddress.nonce, - params: { - _groupId: groupId, - fee: leaveFeeInput, - member: this.selectedHead.address, - lastReference: lastRef - } - }) - return myTxnrequest - } - - const getTxnRequestResponse = (txnResponse) => { - - if (txnResponse.success === false && txnResponse.message) { - this.error = true - this.message = txnResponse.message - throw new Error(txnResponse) - } else if (txnResponse.success === true && !txnResponse.data.error) { - this.message = this.renderErr9Text() - this.error = false - this.confirmRelationship() - } else { - this.error = true - this.message = txnResponse.data.message - throw new Error(txnResponse) - } - } - validateReceiver() - } - elementObserver() { const options = { root: this.viewElement, @@ -530,42 +261,27 @@ class ChatRightPanel extends LitElement { // call `observe()` on that MutationObserver instance, // passing it the element to observe, and the options object observer.observe(elementToObserve); - } - observerHandler(entries) { - if (!entries[0].isIntersecting) { - return - } else { - if(this.groupMembers.length < 20){ - return - } - console.log('this.leaveGroupObjp', this.leaveGroupObj) - this.getMoreMembers(this.leaveGroupObj.groupId) - } - } - - getApiKey() { - const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; - let apiKey = myNode.apiKey; - return apiKey; } - async fetchWalletDetails() { - parentEpml.request('apiCall', { - url: `/addresses/balance/${this.myAddress}?apiKey=${this.getApiKey()}`, - }) - .then((res) => { - if (isNaN(Number(res))) { - let snack4string = get("grouppage.gchange60") - parentEpml.request('showSnackBar', `${snack4string}`) - } else { - this.walletBalance = Number(res).toFixed(8); + observerHandler(entries) { + if (!entries[0].isIntersecting) { + return + } else { + if(this.groupMembers.length < 20){ + return } - }) + console.log('this.leaveGroupObjp', this.leaveGroupObj) + this.getMoreMembers(this.leaveGroupObj.groupId) + } + } + + setOpenTipUser(props) { + this.openTipUser = props } render() { console.log('this.groupMembers', this.groupMembers); - console.log(20, "Chat Right Panel Here"); + console.log(28, "Chat Right Panel Here"); const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner) return html`
@@ -626,7 +342,9 @@ class ChatRightPanel extends LitElement { { if (this.isLoading) return - this.openUserInfo = false + this.openUserInfo = false; + this.userName = ""; + this.shadowRoot.querySelector("tip-user").shadowRoot.getElementById('amountInput').value = ""; }} style=${ this.openUserInfo ? "display: block" : "display: none" @@ -691,14 +409,13 @@ class ChatRightPanel extends LitElement { this.chatEditor.enable(); }} style=${this.openTipUser ? "display: block" : "display: none"}> -
- -

${translate("grouppage.gchange55")} ${this.userName}

-
-
-

${translate("grouppage.gchange59")}: ${this.walletBalance} QORT

- -
+ this.setOpenTipUser(val)} + > +
diff --git a/qortal-ui-plugins/plugins/core/components/TipUser-css.js b/qortal-ui-plugins/plugins/core/components/TipUser-css.js new file mode 100644 index 00000000..db6727b9 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/TipUser-css.js @@ -0,0 +1,85 @@ +import { css } from 'lit' + +export const tipUserStyles = css` + .tip-user-header { + display: flex; + justify-content: center; + align-items: center; + padding: 12px; + border-bottom: 1px solid whitesmoke; + gap: 25px; + user-select: none; + } + + .tip-user-header-font { + font-family: Montserrat, sans-serif; + font-size: 20px; + color: var(--chat-bubble-msg-color); + margin: 0; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .tip-user-body { + display: flex; + justify-content: center; + align-items: center; + padding: 20px 10px; + flex-direction: column; + gap: 25px; + } + + .tip-input { + width: 300px; + margin-bottom: 15px; + outline: 0; + border-width: 0 0 2px; + border-color: var(--mdc-theme-primary); + background-color: transparent; + padding: 10px; + font-family: Roboto, sans-serif; + font-size: 15px; + color: var(--chat-bubble-msg-color); + } + + .tip-input::selection { + background-color: var(--mdc-theme-primary); + color: white; + } + + .tip-input::placeholder { + opacity: 0.9; + color: var(--black); + } + + .tip-available { + font-family: Roboto, sans-serif; + font-size: 17px; + color: var(--chat-bubble-msg-color); + font-weight: 300; + letter-spacing: 0.3px; + margin: 0; + user-select: none; + } + + .success-msg { + font-family: Roboto, sans-serif; + font-size: 18px; + font-weight: 400; + letter-spacing: 0.3px; + margin: 0; + user-select: none; + color: #10880b; + } + + .error-msg { + font-family: Roboto, sans-serif; + font-size: 18px; + font-weight: 400; + letter-spacing: 0.3px; + margin: 0; + user-select: none; + color: #f30000; + } +` \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/components/TipUser.js b/qortal-ui-plugins/plugins/core/components/TipUser.js new file mode 100644 index 00000000..c0be137f --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/TipUser.js @@ -0,0 +1,282 @@ +import { LitElement, html } from 'lit'; +import { render } from 'lit/html.js'; +import { get, translate } from 'lit-translate'; +import { tipUserStyles } from './TipUser-css.js'; +import { Epml } from '../../../epml'; +import '@vaadin/button'; +import '@polymer/paper-progress/paper-progress.js'; + +const parentEpml = new Epml({ type: "WINDOW", source: window.parent }); + +export class TipUser extends LitElement { + static get properties() { + return { + userName: { type: String }, + chatEditor: { type: Object }, + walletBalance: { type: Number }, + sendMoneyLoading: { type: Boolean }, + openUserInfo: { type: Boolean }, + btnDisable: { type: Boolean }, + errorMessage: { type: String }, + successMessage: { type: String }, + setOpenTipUser: { attribute: false } + } + } + + constructor() { + super() + this.sendMoneyLoading = false + this.btnDisable = false + this.errorMessage = "" + this.successMessage = "" + this.myAddress = window.parent.reduxStore.getState().app.selectedAddress + } + + static styles = [tipUserStyles] + + async firstUpdated() { + await this.fetchWalletDetails(); + } + + updated(changedProperties) { + if (changedProperties && changedProperties.has("openUserInfo")) { + if (this.openUserInfo) { + this.shadowRoot.getElementById("amountInput").value = ""; + this.errorMessage = ""; + this.successMessage = ""; + } + } + } + + async getLastRef() { + let myRef = await parentEpml.request("apiCall", { + type: "api", + url: `/addresses/lastreference/${this.myAddress.address}`, + }) + return myRef; + } + + renderSuccessText() { + return html`${translate("grouppage.gchange67")}` + } + + renderReceiverText() { + return html`${translate("grouppage.gchange66")}` + } + + getApiKey() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + let apiKey = myNode.apiKey; + return apiKey; + } + + async fetchWalletDetails() { + await parentEpml.request('apiCall', { + url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`, + }) + .then((res) => { + if (isNaN(Number(res))) { + let snack4string = get("grouppage.gchange60") + parentEpml.request('showSnackBar', `${snack4string}`) + } else { + this.walletBalance = Number(res).toFixed(8); + } + }) + } + + async sendQort() { + const amount = this.shadowRoot.getElementById("amountInput").value; + let recipient = this.userName; + this.sendMoneyLoading = true; + this.btnDisable = true; + + if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.walletBalance)) { + this.sendMoneyLoading = false; + this.btnDisable = false; + let snack1string = get("grouppage.gchange63"); + parentEpml.request('showSnackBar', `${snack1string}`); + return false; + } + + if (parseFloat(amount) <= 0) { + this.sendMoneyLoading = false; + this.btnDisable = false; + let snack2string = get("grouppage.gchange64"); + parentEpml.request('showSnackBar', `${snack2string}`); + return false; + } + + if (recipient.length === 0) { + this.sendMoneyLoading = false; + this.btnDisable = false; + let snack3string = get("grouppage.gchange65"); + parentEpml.request('showSnackBar', `${snack3string}`); + return false; + } + + const validateName = async (receiverName) => { + let myRes; + let myNameRes = await parentEpml.request('apiCall', { + type: 'api', + url: `/names/${receiverName}`, + }) + + if (myNameRes.error === 401) { + myRes = false; + } else { + myRes = myNameRes; + } + return myRes; + } + + const validateAddress = async (receiverAddress) => { + let myAddress = await window.parent.validateAddress(receiverAddress); + return myAddress; + } + + const validateReceiver = async (recipient) => { + let lastRef = await this.getLastRef(); + let isAddress; + + try { + isAddress = await validateAddress(recipient); + } catch (err) { + isAddress = false; + } + + if (isAddress) { + let myTransaction = await makeTransactionRequest(recipient, lastRef); + getTxnRequestResponse(myTransaction); + } else { + let myNameRes = await validateName(recipient); + if (myNameRes !== false) { + let myNameAddress = myNameRes.owner + let myTransaction = await makeTransactionRequest(myNameAddress, lastRef) + getTxnRequestResponse(myTransaction) + } else { + console.error(this.renderReceiverText()) + this.errorMessage = this.renderReceiverText(); + this.sendMoneyLoading = false; + this.btnDisable = false; + } + } + } + + const getName = async (recipient)=> { + try { + const getNames = await parentEpml.request("apiCall", { + type: "api", + url: `/names/address/${recipient}`, + }); + + if (getNames?.length > 0 ) { + return getNames[0].name; + } else { + return ''; + } + } catch (error) { + return ""; + } + } + + const makeTransactionRequest = async (receiver, lastRef) => { + let myReceiver = receiver; + let mylastRef = lastRef; + let dialogamount = get("transactions.amount"); + let dialogAddress = get("login.address"); + let dialogName = get("login.name"); + let dialogto = get("transactions.to"); + let recipientName = await getName(myReceiver); + let myTxnrequest = await parentEpml.request('transaction', { + type: 2, + nonce: this.myAddress.nonce, + params: { + recipient: myReceiver, + recipientName: recipientName, + amount: amount, + lastReference: mylastRef, + fee: 0.001, + dialogamount: dialogamount, + dialogto: dialogto, + dialogAddress, + dialogName + }, + }) + return myTxnrequest; + } + + const getTxnRequestResponse = (txnResponse) => { + if (txnResponse.success === false && txnResponse.message) { + this.errorMessage = txnResponse.message; + this.sendMoneyLoading = false; + this.btnDisable = false; + throw new Error(txnResponse); + } else if (txnResponse.success === true && !txnResponse.data.error) { + this.shadowRoot.getElementById('amountInput').value = ''; + this.userName = ''; + this.errorMessage = ''; + this.successMessage = this.renderSuccessText(); + this.sendMoneyLoading = false; + this.btnDisable = false; + setTimeout(() => { + this.setOpenTipUser(false); + this.chatEditor.enable(); + this.successMessage = ""; + }, 3000); + } else { + this.errorMessage = txnResponse.data.message; + this.sendMoneyLoading = false; + this.btnDisable = false; + throw new Error(txnResponse); + } + } + validateReceiver(recipient); + } + + render() { + console.log(5, "Tip User Here"); + console.log(this.openUserInfo, "openUserInfo here"); + return html` +
+ +

${translate("grouppage.gchange55")} ${this.userName}

+
+
+

${translate("grouppage.gchange59")}: ${this.walletBalance} QORT

+ +

${translate("grouppage.gchange61")}: 0.001 QORT

+ ${this.sendMoneyLoading ? + html` + + ` + : html` +
+ this.sendQort()}> + + ${translate("grouppage.gchange62")} QORT + +
+ `} + + ${this.successMessage ? + html` +

+ ${this.successMessage} +

+ ` + : this.errorMessage ? + html` +

+ ${this.errorMessage} +

+ ` + : null} +
+ `; + } +} +customElements.define('tip-user', TipUser); diff --git a/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js b/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js index f8f02a53..1d8bf688 100644 --- a/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js +++ b/qortal-ui-plugins/plugins/utils/getUserNameFromAddress.js @@ -13,7 +13,7 @@ export const getUserNameFromAddress = async (address) => { if (Array.isArray(getNames) && getNames.length > 0 ) { return getNames[0].name; } else { - return cropAddress(address); + return address; } } catch (error) { console.error(error); From 238ee3f3f1eb451f8f392c751d47a2c21e171c8e Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Fri, 6 Jan 2023 17:22:19 -0500 Subject: [PATCH 08/19] Made Tip User Reusable --- qortal-ui-core/language/us.json | 3 +- .../plugins/core/components/ChatPage.js | 8 +-- .../plugins/core/components/ChatRightPanel.js | 2 +- .../plugins/core/components/ChatScroller.js | 70 +++++++++++++++++-- .../plugins/core/components/TipUser.js | 13 ++-- 5 files changed, 76 insertions(+), 20 deletions(-) diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index d9efaade..a35ec919 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -587,7 +587,8 @@ "bcchange14": "Forward", "bcchange15": "Message Forwarded", "bcchange16": "Choose Recipient or Search for One Below", - "bcchange17": "FORWARDED" + "bcchange17": "FORWARDED", + "bcchange18": "Tip User" }, "grouppage": { "gchange1": "Qortal Groups", diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 6fd8e544..97ff9f15 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -1462,12 +1462,10 @@ class ChatPage extends LitElement { async updated(changedProperties) { if (changedProperties && changedProperties.has('userLanguage')) { const userLang = changedProperties.get('userLanguage') - - if(userLang){ + if (userLang) { await new Promise(r => setTimeout(r, 100)); this.chatEditorPlaceholder = this.isReceipient === true ? `Message ${this._chatId}` : `${get("chatpage.cchange8")}`; - } - + } } if (changedProperties && changedProperties.has('chatId') && changedProperties.get('chatId')) { @@ -1479,7 +1477,6 @@ class ChatPage extends LitElement { this.chatEditor.disable(); } } - } async getName (recipient) { @@ -1533,6 +1530,7 @@ async getName (recipient) { chatId=${this.chatId} .messages=${this.messagesRendered} .escapeHTML=${escape} + .chatEditor=${this.chatEditor} .getOldMessage=${this.getOldMessage} .setRepliedToMessageObj=${(val) => this.setRepliedToMessageObj(val)} .setEditedMessageObj=${(val) => this.setEditedMessageObj(val)} diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index 4dbe8cb7..ef94570e 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -410,7 +410,7 @@ class ChatRightPanel extends LitElement { }} style=${this.openTipUser ? "display: block" : "display: none"}> this.setOpenTipUser(val)} diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 23d5d191..5d72946b 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -8,6 +8,8 @@ import { Epml } from "../../../epml"; import './LevelFounder.js'; import './NameMenu.js'; import './ChatModals.js'; +import './WrapperModal'; +import './TipUser' import '@vaadin/icons'; import '@vaadin/icon'; import '@material/mwc-button'; @@ -36,8 +38,11 @@ class ChatScroller extends LitElement { isLoadingMessages: { type: Boolean}, setIsLoadingMessages: {attribute: false}, chatId: { type: String }, + chatEditor: { type: Object }, setForwardProperties: { attribute: false }, setOpenPrivateMessage: { attribute: false }, + openTipUser: { type: Boolean }, + userName: { type: String } } } @@ -48,12 +53,17 @@ class ChatScroller extends LitElement { this.messages = [] this._upObserverhandler = this._upObserverhandler.bind(this) this._downObserverHandler = this._downObserverHandler.bind(this) + this.setOpenTipUser = this.setOpenTipUser.bind(this) + this.setUserName = this.setUserName.bind(this) this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]") + this.openTipUser = false; + this.userName = ""; } - render() { + console.log(6, "chat scroller here"); + console.log(this.openTipUser, "openTipUser here"); let formattedMessages = this.messages.reduce((messageArray, message, index) => { const lastGroupedMessage = messageArray[messageArray.length - 1]; let timestamp; @@ -117,12 +127,27 @@ class ChatScroller extends LitElement { .setToggledMessage=${this.setToggledMessage} .setForwardProperties=${this.setForwardProperties} .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} - > + .setOpenTipUser=${(val) => this.setOpenTipUser(val)} + .setUserName=${(val) => this.setUserName(val)}> ` ) })}
+ { + this.openTipUser = false; + this.chatEditor.enable(); + }} + style=${this.openTipUser ? "display: block;" : "display: none;"}> + this.setOpenTipUser(val)}> + + ` } @@ -133,6 +158,9 @@ class ChatScroller extends LitElement { if(changedProperties.has('chatId') && changedProperties.get('chatId')){ return true } + if(changedProperties.has('openTipUser')){ + return true + } // Only update element if prop1 changed. return changedProperties.has('messages'); } @@ -148,6 +176,15 @@ class ChatScroller extends LitElement { toggledMessage = message; } + setOpenTipUser(props) { + this.openTipUser = props; + this.chatEditor.disable(); + } + + setUserName(props) { + this.userName = props; + } + async firstUpdated() { this.emojiPicker.on('emoji', selection => { @@ -240,10 +277,12 @@ class MessageTemplate extends LitElement { isFirstMessage: { type: Boolean }, isSingleMessageInGroup: { type: Boolean }, isLastMessageInGroup: { type: Boolean }, - setToggledMessage: {attribute: false}, - setForwardProperties: {attribute: false}, - viewImage: {type: Boolean}, - setOpenPrivateMessage : { attribute: false } + setToggledMessage: { attribute: false }, + setForwardProperties: { attribute: false }, + viewImage: { type: Boolean }, + setOpenPrivateMessage : { attribute: false }, + setOpenTipUser: { attribute: false }, + setUserName: { attribute: false } } } @@ -538,6 +577,8 @@ class MessageTemplate extends LitElement { .setForwardProperties=${this.setForwardProperties} ?firstMessageInChat=${this.messageObj.firstMessageInChat} .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} + .setOpenTipUser=${(val) => this.setOpenTipUser(val)} + .setUserName=${(val) => this.setUserName(val)} > @@ -643,7 +684,9 @@ class ChatMenu extends LitElement { sendMessageForward: { attribute: false }, setForwardProperties: { attribute: false }, firstMessageInChat: { type: Boolean }, - setOpenPrivateMessage: { attribute: false } + setOpenPrivateMessage: { attribute: false }, + setOpenTipUser: { attribute: false }, + setUserName: { attribute: false }, } } @@ -789,6 +832,19 @@ class ChatMenu extends LitElement { ` ) : html`
`} + ${this.myAddress !== this.originalMessage.sender ? ( + html` +
{ + this.setOpenTipUser(true); + this.setUserName(this.originalMessage.sender); + }}> + +
+ ` + ) : html`
`}
diff --git a/qortal-ui-plugins/plugins/core/components/TipUser.js b/qortal-ui-plugins/plugins/core/components/TipUser.js index 6bc0ffbb..ac389a94 100644 --- a/qortal-ui-plugins/plugins/core/components/TipUser.js +++ b/qortal-ui-plugins/plugins/core/components/TipUser.js @@ -15,11 +15,12 @@ export class TipUser extends LitElement { chatEditor: { type: Object }, walletBalance: { type: Number }, sendMoneyLoading: { type: Boolean }, - openUserInfo: { type: Boolean }, + closeTipUser: { type: Boolean }, btnDisable: { type: Boolean }, errorMessage: { type: String }, successMessage: { type: String }, - setOpenTipUser: { attribute: false } + setOpenTipUser: { attribute: false }, + focusChatEditor: { attribute: false } } } @@ -39,8 +40,8 @@ export class TipUser extends LitElement { } updated(changedProperties) { - if (changedProperties && changedProperties.has("openUserInfo")) { - if (this.openUserInfo) { + if (changedProperties && changedProperties.has("closeTipUser")) { + if (this.closeTipUser) { this.shadowRoot.getElementById("amountInput").value = ""; this.errorMessage = ""; this.successMessage = ""; @@ -221,6 +222,7 @@ export class TipUser extends LitElement { setTimeout(() => { this.setOpenTipUser(false); this.chatEditor.enable(); + this.focusChatEditor(); this.successMessage = ""; }, 3000); } else { @@ -234,8 +236,7 @@ export class TipUser extends LitElement { } render() { - console.log(5, "Tip User Here"); - console.log(this.openUserInfo, "openUserInfo here"); + console.log(7, "Tip User Here"); return html`
From d4e6caaf31e196adea599e7b0615d1530a3fd9af Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Sat, 7 Jan 2023 12:41:39 +0100 Subject: [PATCH 09/19] Add export master key --- qortal-ui-core/language/de.json | 6 +- qortal-ui-core/language/es.json | 6 +- qortal-ui-core/language/fr.json | 6 +- qortal-ui-core/language/hindi.json | 6 +- qortal-ui-core/language/hr.json | 6 +- qortal-ui-core/language/hu.json | 6 +- qortal-ui-core/language/it.json | 6 +- qortal-ui-core/language/ko.json | 6 +- qortal-ui-core/language/no.json | 6 +- qortal-ui-core/language/pl.json | 6 +- qortal-ui-core/language/pt.json | 6 +- qortal-ui-core/language/ro.json | 6 +- qortal-ui-core/language/rs.json | 6 +- qortal-ui-core/language/ru.json | 6 +- qortal-ui-core/language/us.json | 6 +- qortal-ui-core/language/zhc.json | 6 +- qortal-ui-core/language/zht.json | 6 +- .../components/settings-view/export-keys.js | 236 ++++++++++++++++++ .../components/settings-view/user-settings.js | 25 +- 19 files changed, 338 insertions(+), 25 deletions(-) create mode 100644 qortal-ui-core/src/components/settings-view/export-keys.js diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index f10ddfe7..cedb6452 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -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", diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index 4ae55367..adf6d85c 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -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", diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index 03b21617..86b02d49 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -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", diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index 02479e0f..e82ab1b0 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -129,7 +129,11 @@ "snack2":"यूआई नोड से जुड़ा", "snack3":"कस्टम नोड को सफलतापूर्वक जोड़ा और सहेजा गया", "snack4":"नोड्स सफलतापूर्वक सहेजे गए", - "snack5":"नोड्स सफलतापूर्वक आयात किए गए" + "snack5":"नोड्स सफलतापूर्वक आयात किए गए", + "exp1":"निजी मास्टर कुंजी निर्यात करें", + "exp2":"निर्यात मास्टर कुंजी", + "exp3":"निर्यात", + "exp4":"निजी मास्टर कुंजी का बैकअप लेने के लिए कृपया एक वॉलेट चुनें।" }, "appinfo":{ "blockheight":"ब्लॉक ऊँचाई", diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index dc066af8..40689c8f 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -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", diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index 76f9fed4..7b57ad70 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -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", diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index 42e55e2e..e669f6de 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -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", diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index 2124eec4..4eed1cbc 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -128,7 +128,11 @@ "snack2":"노드에 연결된 UI", "snack3":"사용자 정의 노드를 성공적으로 추가하고 저장했습니다.", "snack4":"노드가 다음으로 성공적으로 저장되었습니다", - "snack5":"노드를 성공적으로 가져왔습니다." + "snack5":"노드를 성공적으로 가져왔습니다.", + "exp1":"개인 마스터 키 내보내기", + "exp2":"마스터 키 내보내기", + "exp3":"내보내기", + "exp4":"개인 마스터 키를 백업할 지갑을 선택하세요." }, "appinfo":{ "blockheight":"블록 높이", diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index a38abbe8..7795fa96 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -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", diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index aff8fbd4..5fbd3224 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -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", diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index 035986c0..c731226f 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -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", diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index 891a0be4..60bce846 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -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", diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index 432280f7..c7ad6d88 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -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", diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index e40c5ae3..abad841f 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -128,7 +128,11 @@ "snack2":"Пользовательский интерфейс, подключенный к узлу", "snack3":"Пользовательский узел успешно добавлен и сохранен", "snack4":"Узлы успешно сохранены как", - "snack5":"Узлы успешно импортированы" + "snack5":"Узлы успешно импортированы", + "exp1":"Экспорт закрытого мастер-ключа", + "exp2":"Экспорт мастер-ключа", + "exp3":"Экспорт", + "exp4":"Пожалуйста, выберите кошелек для резервного копирования приватного главного ключа." }, "appinfo":{ "blockheight":"Высота блока", diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 7da41ef0..580d0549 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -128,7 +128,11 @@ "snack2":"UI conected to node", "snack3":"Successfully added and saved custom node", "snack4":"Nodes successfully saved as", - "snack5":"Nodes successfully imported" + "snack5":"Nodes successfully imported", + "exp1":"Export Private Master Key", + "exp2":"Export Master Key", + "exp3":"Export", + "exp4":"Please choose a wallet to backup the private master key." }, "appinfo":{ "blockheight":"Block Height", diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index dfd1d98d..b41114a8 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -128,7 +128,11 @@ "snack2":"连接到节点的 UI", "snack3":"成功添加并保存自定义节点", "snack4":"节点成功保存为", - "snack5":"节点成功导入" + "snack5":"节点成功导入", + "exp1":"导出主密钥", + "exp2":"导出主密钥", + "exp3":"导出", + "exp4":"请选择一个钱包来备份私钥。" }, "appinfo":{ "blockheight":"区块高度", diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index 7572a9df..52fa5400 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -128,7 +128,11 @@ "snack2":"連接到節點的 UI", "snack3":"成功添加並保存自定義節點", "snack4":"節點成功保存為", - "snack5":"節點成功導入" + "snack5":"節點成功導入", + "exp1":"導出主密鑰", + "exp2":"導出主密鑰", + "exp3":"導出", + "exp4":"請選擇一個錢包來備份私鑰。" }, "appinfo":{ "blockheight":"區塊高度", diff --git a/qortal-ui-core/src/components/settings-view/export-keys.js b/qortal-ui-core/src/components/settings-view/export-keys.js new file mode 100644 index 00000000..1456ce3a --- /dev/null +++ b/qortal-ui-core/src/components/settings-view/export-keys.js @@ -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` +
+
+

+ ${translate("settings.exp4")} +

+
+
+
+
+
+   ${this.btcWALLET}
+
+
this.checkForPmkDownload(this.btcWALLET, this.btcPMK, this.btcName, this.btcShort)} class="export-button"> ${translate("settings.exp2")}
+
+
+
+   ${this.ltcWALLET}
+
+
this.checkForPmkDownload(this.ltcWALLET, this.ltcPMK, this.ltcName, this.ltcShort)} class="export-button"> ${translate("settings.exp2")}
+
+
+
+   ${this.dogeWALLET}
+
+
this.checkForPmkDownload(this.dogeWALLET, this.dogePMK, this.dogeName, this.dogeShort)} class="export-button"> ${translate("settings.exp2")}
+
+
+
+   ${this.dgbWALLET}
+
+
this.checkForPmkDownload(this.dgbWALLET, this.dgbPMK, this.dgbName, this.dgbShort)} class="export-button"> ${translate("settings.exp2")}
+
+
+
+   ${this.rvnWALLET}
+
+
this.checkForPmkDownload(this.rvnWALLET, this.rvnPMK, this.rvnName, this.rvnShort)} class="export-button"> ${translate("settings.exp2")}
+
+
+
+ + +

${this.dCoinName} ${translate("settings.exp2")}

+
+

${translate("settings.address")}: ${this.dWalletAddress}

+ + ${translate("general.close")} + + + ${translate("settings.exp3")} + +
+
+ ` + } + + 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) diff --git a/qortal-ui-core/src/components/settings-view/user-settings.js b/qortal-ui-core/src/components/settings-view/user-settings.js index 4d522f17..66a8c887 100644 --- a/qortal-ui-core/src/components/settings-view/user-settings.js +++ b/qortal-ui-core/src/components/settings-view/user-settings.js @@ -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) { @@ -247,25 +250,29 @@ class UserSettings extends connect(store)(LitElement) { renderSettingViews(selectedView) { if (selectedView.id === 'info') { - return html``; + return html`` } else if (selectedView.id === 'security') { - return html``; + return html`` + } else if (selectedView.id === 'export') { + return html`` } else if (selectedView.id === 'notification') { - return html``; + return html`` } else if (selectedView.id === 'qr-login') { - return html``; + return html`` } } 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') { From f19c6ce6734d5e4c048ba9b6c77a2658f357c494 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Sat, 7 Jan 2023 18:16:51 -0500 Subject: [PATCH 10/19] Fixed Avatar Bug + Fixed User Info Translations --- qortal-ui-core/language/us.json | 5 +- .../plugins/core/components/ChatRightPanel.js | 8 +- .../plugins/core/components/ChatScroller.js | 16 ++-- .../core/components/ChatSideNavHeads.js | 75 ++++++++++++++----- .../plugins/core/components/TipUser.js | 1 - .../plugins/core/components/UserInfo.js | 0 6 files changed, 72 insertions(+), 33 deletions(-) create mode 100644 qortal-ui-plugins/plugins/core/components/UserInfo.js diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index a35ec919..c7d90de2 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -557,7 +557,10 @@ "cchange53": "Receiver cannot be empty!", "cchange54": "Invalid Receiver!", "cchange55": "Transaction Successful!", - "cchange56": "Transaction Failed!" + "cchange56": "Transaction Failed!", + "cchange57": "User Info", + "cchange58": "SEND MESSAGE", + "cchange59": "TIP USER" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index ef94570e..ec38a6fd 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -280,8 +280,6 @@ class ChatRightPanel extends LitElement { } render() { - console.log('this.groupMembers', this.groupMembers); - console.log(28, "Chat Right Panel Here"); const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner) return html`
@@ -360,7 +358,7 @@ class ChatRightPanel extends LitElement { ?disabled="${this.isLoading}">
- ${translate("grouppage.gchange56")} + ${translate("chatpage.cchange58")}
- ${translate("grouppage.gchange57")} + ${translate("chatpage.cchange59")}
diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 5d72946b..5c0a7954 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -28,15 +28,15 @@ class ChatScroller extends LitElement { escapeHTML: { attribute: false }, messages: { type: Array }, hideMessages: { type: Array }, - setRepliedToMessageObj: {attribute: false}, - setEditedMessageObj: {attribute: false}, - focusChatEditor: {attribute: false}, - sendMessage: {attribute: false}, - sendMessageForward: {attribute: false}, - showLastMessageRefScroller: { type: Function }, + setRepliedToMessageObj: { attribute: false }, + setEditedMessageObj: { attribute: false }, + focusChatEditor: { attribute: false }, + sendMessage: { attribute: false }, + sendMessageForward: { attribute: false }, + showLastMessageRefScroller: { attribute: false }, emojiPicker: { attribute: false }, isLoadingMessages: { type: Boolean}, - setIsLoadingMessages: {attribute: false}, + setIsLoadingMessages: { attribute: false }, chatId: { type: String }, chatEditor: { type: Object }, setForwardProperties: { attribute: false }, @@ -62,8 +62,6 @@ class ChatScroller extends LitElement { } render() { - console.log(6, "chat scroller here"); - console.log(this.openTipUser, "openTipUser here"); let formattedMessages = this.messages.reduce((messageArray, message, index) => { const lastGroupedMessage = messageArray[messageArray.length - 1]; let timestamp; diff --git a/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js b/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js index daa9e478..220aeb79 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js +++ b/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js @@ -93,6 +93,7 @@ class ChatSideNavHeads extends LitElement { } imageHTMLRes.onload = () => { this.isImageLoaded = true; + this.requestUpdate(); } imageHTMLRes.onerror = () => { if (this.imageFetches < 4) { @@ -101,36 +102,67 @@ class ChatSideNavHeads extends LitElement { imageHTMLRes.src = imageUrl; }, 500); } else { - - - this.isImageLoaded = false + this.isImageLoaded = false } }; + console.log(imageHTMLRes, "here8") return imageHTMLRes; } render() { - let avatarImg = ''; - let backupAvatarImg = '' - if(this.chatInfo.name){ + console.log(9, 'chat side nav head'); + console.log(this.isImageLoaded, 'Is image loaded'); + console.log(this.chatInfo, 'Chat Info Here'); + let avatarImg = "" + if (this.chatInfo.name) { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`; - avatarImg= this.createImage(avatarUrl) - + avatarImg = this.createImage(avatarUrl) } return html`
  • this.getUrl(this.chatInfo)} class="clearfix"> - ${this.isImageLoaded ? html`${avatarImg}` : html`` } - ${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? html`account_circle` : html`` } - ${!this.isImageLoaded && this.chatInfo.name ? html`
    ${this.chatInfo.name.charAt(0)}
    `: ''} - ${!this.isImageLoaded && this.chatInfo.groupName ? html`
    ${this.chatInfo.groupName.charAt(0)}
    `: ''} -
    -
    ${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)}
    -
    -
  • - ` + ${this.isImageLoaded ? html`${avatarImg}` : html``} + ${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName + ? html`account_circle` + : html``} + ${!this.isImageLoaded && this.chatInfo.name + ? html`
    + ${this.chatInfo.name.charAt(0)} +
    ` + : ""} + ${!this.isImageLoaded && this.chatInfo.groupName + ? html`
    + ${this.chatInfo.groupName.charAt(0)} +
    ` + : ""} +
    +
    + + ${this.chatInfo.groupName + ? this.chatInfo.groupName + : this.chatInfo.name !== undefined + ? this.chatInfo.name + : this.chatInfo.address.substr(0, 15)} + +
    +
    + + ` } firstUpdated() { @@ -154,6 +186,12 @@ class ChatSideNavHeads extends LitElement { } + updated(changedProperties) { + if (changedProperties && changedProperties.has("avatarImg")) { + console.log(this.avatarImg, "avatarImg"); + } + } + shouldUpdate(changedProperties) { if(changedProperties.has('activeChatHeadUrl')){ return true @@ -161,6 +199,9 @@ class ChatSideNavHeads extends LitElement { if(changedProperties.has('chatInfo')){ return true } + if(changedProperties.has('isImageLoaded')){ + return true + } return false } diff --git a/qortal-ui-plugins/plugins/core/components/TipUser.js b/qortal-ui-plugins/plugins/core/components/TipUser.js index ac389a94..2beefd48 100644 --- a/qortal-ui-plugins/plugins/core/components/TipUser.js +++ b/qortal-ui-plugins/plugins/core/components/TipUser.js @@ -236,7 +236,6 @@ export class TipUser extends LitElement { } render() { - console.log(7, "Tip User Here"); return html`
    diff --git a/qortal-ui-plugins/plugins/core/components/UserInfo.js b/qortal-ui-plugins/plugins/core/components/UserInfo.js new file mode 100644 index 00000000..e69de29b From 7fdc33cb82587efe46131b19ca3532075d224ac9 Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Mon, 9 Jan 2023 06:50:36 -0500 Subject: [PATCH 11/19] Adjust spacing --- .../plugins/core/wallet/wallet-app.src.js | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js b/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js index 197248f4..e8c6a955 100644 --- a/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js +++ b/qortal-ui-plugins/plugins/core/wallet/wallet-app.src.js @@ -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 { - +

    ${translate("walletpage.wchange5")}


    @@ -1577,7 +1577,7 @@ class MultiWallet extends LitElement { - +
    @@ -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) } } From 6e30bb0c69ae76398d1a1483015b522d0dc4473d Mon Sep 17 00:00:00 2001 From: QuickMythril Date: Mon, 9 Jan 2023 06:55:44 -0500 Subject: [PATCH 12/19] Adjust spacing --- .../core/trade-portal/trade-portal.src.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js index 47a97042..47910961 100644 --- a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js +++ b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js @@ -74,7 +74,7 @@ class TradePortal extends LitElement { displayTradeAddress: { type: String }, displayTradeLevel: { type: String }, displayTradeBalance: { type: String }, - qortRatio: {type: Number} + qortRatio: {type: Number} } } @@ -494,7 +494,7 @@ class TradePortal extends LitElement { .rvn.coinName:before { background-image: url('/img/qortrvn.png'); } - .arrr.coinName:before { + .arrr.coinName:before { background-image: url('/img/qortarrr.png'); } .coinName { @@ -655,7 +655,7 @@ class TradePortal extends LitElement { tradeFee: "~0.0005" } - let ravencoin = { + let ravencoin = { name: "RAVENCOIN", balance: "0", coinCode: "RVN", @@ -721,7 +721,7 @@ class TradePortal extends LitElement { handleStuckTradesConnectedWorker: null }) - workers.set("RAVENCOIN", { + workers.set("RAVENCOIN", { tradesConnectedWorker: null, handleStuckTradesConnectedWorker: null }) @@ -1160,7 +1160,7 @@ class TradePortal extends LitElement { QORT / DOGE QORT / DGB QORT / RVN - QORT / ARRR + QORT / ARRR
    @@ -1504,8 +1504,8 @@ class TradePortal extends LitElement { case 'DIGIBYTE': _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}` _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey - break - case 'RAVENCOIN': + break + case 'RAVENCOIN': _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}` _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey break @@ -2945,4 +2945,4 @@ class TradePortal extends LitElement { } } -window.customElements.define('trade-portal', TradePortal) \ No newline at end of file +window.customElements.define('trade-portal', TradePortal) From 5bb1570a35778c3a41f763709805091631841b27 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Mon, 9 Jan 2023 14:05:13 +0100 Subject: [PATCH 13/19] last child full visible --- qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js index 193883ee..dc59b97f 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat.src.js @@ -122,7 +122,7 @@ class Chat extends LitElement { box-shadow: 0 3px 5px rgba(0, 0, 0, .2); } .people-list ul { - padding: 0; + padding: 0px 0px 60px 0px; height: 85vh; overflow-y: auto; overflow-x: hidden; From f8ceaa56c51eb376b539b29d6e7c15e9bae53558 Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Mon, 9 Jan 2023 15:03:59 +0100 Subject: [PATCH 14/19] Add chart js files --- .../core/trade-portal/charts/arrr-charts.js | 214 +++++++++++++++++ .../core/trade-portal/charts/btc-charts.js | 215 ++++++++++++++++++ .../core/trade-portal/charts/dgb-charts.js | 214 +++++++++++++++++ .../core/trade-portal/charts/doge-charts.js | 214 +++++++++++++++++ .../core/trade-portal/charts/ltc-charts.js | 214 +++++++++++++++++ .../core/trade-portal/charts/rvn-charts.js | 214 +++++++++++++++++ 6 files changed, 1285 insertions(+) create mode 100644 qortal-ui-plugins/plugins/core/trade-portal/charts/arrr-charts.js create mode 100644 qortal-ui-plugins/plugins/core/trade-portal/charts/btc-charts.js create mode 100644 qortal-ui-plugins/plugins/core/trade-portal/charts/dgb-charts.js create mode 100644 qortal-ui-plugins/plugins/core/trade-portal/charts/doge-charts.js create mode 100644 qortal-ui-plugins/plugins/core/trade-portal/charts/ltc-charts.js create mode 100644 qortal-ui-plugins/plugins/core/trade-portal/charts/rvn-charts.js diff --git a/qortal-ui-plugins/plugins/core/trade-portal/charts/arrr-charts.js b/qortal-ui-plugins/plugins/core/trade-portal/charts/arrr-charts.js new file mode 100644 index 00000000..561cd9df --- /dev/null +++ b/qortal-ui-plugins/plugins/core/trade-portal/charts/arrr-charts.js @@ -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` + +
    + ${translate("login.loading")} +
    +
    + +
    +
    +
    +
    + ` + } + + 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 \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/trade-portal/charts/btc-charts.js b/qortal-ui-plugins/plugins/core/trade-portal/charts/btc-charts.js new file mode 100644 index 00000000..c31d272b --- /dev/null +++ b/qortal-ui-plugins/plugins/core/trade-portal/charts/btc-charts.js @@ -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` + +
    + ${translate("login.loading")} +
    +
    + +
    +
    +
    +
    + ` + } + + 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 \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/trade-portal/charts/dgb-charts.js b/qortal-ui-plugins/plugins/core/trade-portal/charts/dgb-charts.js new file mode 100644 index 00000000..5e57aad7 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/trade-portal/charts/dgb-charts.js @@ -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` + +
    + ${translate("login.loading")} +
    +
    + +
    +
    +
    +
    + ` + } + + 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 \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/trade-portal/charts/doge-charts.js b/qortal-ui-plugins/plugins/core/trade-portal/charts/doge-charts.js new file mode 100644 index 00000000..a4267361 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/trade-portal/charts/doge-charts.js @@ -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` + +
    + ${translate("login.loading")} +
    +
    + +
    +
    +
    +
    + ` + } + + 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 \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/trade-portal/charts/ltc-charts.js b/qortal-ui-plugins/plugins/core/trade-portal/charts/ltc-charts.js new file mode 100644 index 00000000..08ffd339 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/trade-portal/charts/ltc-charts.js @@ -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` + +
    + ${translate("login.loading")} +
    +
    + +
    +
    +
    +
    + ` + } + + 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 \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/trade-portal/charts/rvn-charts.js b/qortal-ui-plugins/plugins/core/trade-portal/charts/rvn-charts.js new file mode 100644 index 00000000..1110bdfc --- /dev/null +++ b/qortal-ui-plugins/plugins/core/trade-portal/charts/rvn-charts.js @@ -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` + +
    + ${translate("login.loading")} +
    +
    + +
    +
    +
    +
    + ` + } + + 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 \ No newline at end of file From df9dcd20f942ed106dc5b2669f7648cd12fbf76c Mon Sep 17 00:00:00 2001 From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com> Date: Mon, 9 Jan 2023 15:09:00 +0100 Subject: [PATCH 15/19] Added charts --- qortal-ui-core/language/de.json | 3 +- qortal-ui-core/language/es.json | 3 +- qortal-ui-core/language/fr.json | 3 +- qortal-ui-core/language/hindi.json | 3 +- qortal-ui-core/language/hr.json | 3 +- qortal-ui-core/language/hu.json | 3 +- qortal-ui-core/language/it.json | 3 +- qortal-ui-core/language/ko.json | 3 +- qortal-ui-core/language/no.json | 3 +- qortal-ui-core/language/pl.json | 3 +- qortal-ui-core/language/pt.json | 3 +- qortal-ui-core/language/ro.json | 3 +- qortal-ui-core/language/rs.json | 3 +- qortal-ui-core/language/ru.json | 3 +- qortal-ui-core/language/us.json | 3 +- qortal-ui-core/language/zhc.json | 3 +- qortal-ui-core/language/zht.json | 3 +- .../core/trade-portal/trade-portal.src.js | 48 ++++++++++++++++--- 18 files changed, 75 insertions(+), 24 deletions(-) diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json index cedb6452..518cab5c 100644 --- a/qortal-ui-core/language/de.json +++ b/qortal-ui-core/language/de.json @@ -333,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", diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json index adf6d85c..eab3f6d0 100644 --- a/qortal-ui-core/language/es.json +++ b/qortal-ui-core/language/es.json @@ -333,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", diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json index 86b02d49..f22be6c5 100644 --- a/qortal-ui-core/language/fr.json +++ b/qortal-ui-core/language/fr.json @@ -333,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", diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json index e82ab1b0..617a2b64 100644 --- a/qortal-ui-core/language/hindi.json +++ b/qortal-ui-core/language/hindi.json @@ -334,7 +334,8 @@ "tchange45":"ऑटो के साथ खरीदें", "tchange46":"ऑटो खरीदें", "tchange47":"इस कीमत पर बेचें", - "tchange48":"पर्याप्त नहीं" + "tchange48":"पर्याप्त नहीं", + "tchange49":"मूल्य चार्ट" }, "rewardsharepage":{ "rchange1":"रिवॉर्डशेयर", diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json index 40689c8f..3b369348 100644 --- a/qortal-ui-core/language/hr.json +++ b/qortal-ui-core/language/hr.json @@ -333,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)", diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json index 7b57ad70..c30d020d 100644 --- a/qortal-ui-core/language/hu.json +++ b/qortal-ui-core/language/hu.json @@ -333,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", diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json index e669f6de..6efe10d4 100644 --- a/qortal-ui-core/language/it.json +++ b/qortal-ui-core/language/it.json @@ -333,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", diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json index 4eed1cbc..2dc9b4d6 100644 --- a/qortal-ui-core/language/ko.json +++ b/qortal-ui-core/language/ko.json @@ -333,7 +333,8 @@ "tchange45":"자동 구매", "tchange46":"자동 구매", "tchange47":"이 가격에 팔아요", - "tchange48":"부족한" + "tchange48":"부족한", + "tchange49":"가격 차트" }, "rewardsharepage":{ "rchange1":"보상 공유", diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json index 7795fa96..85054308 100644 --- a/qortal-ui-core/language/no.json +++ b/qortal-ui-core/language/no.json @@ -333,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", diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json index 5fbd3224..0b3ef019 100644 --- a/qortal-ui-core/language/pl.json +++ b/qortal-ui-core/language/pl.json @@ -333,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", diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json index c731226f..41e55557 100644 --- a/qortal-ui-core/language/pt.json +++ b/qortal-ui-core/language/pt.json @@ -333,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", diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json index 60bce846..29efe5b0 100644 --- a/qortal-ui-core/language/ro.json +++ b/qortal-ui-core/language/ro.json @@ -333,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", diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json index c7ad6d88..ccd07326 100644 --- a/qortal-ui-core/language/rs.json +++ b/qortal-ui-core/language/rs.json @@ -333,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", diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json index abad841f..b7539374 100644 --- a/qortal-ui-core/language/ru.json +++ b/qortal-ui-core/language/ru.json @@ -333,7 +333,8 @@ "tchange45":"АВТО КУПИТЬ С", "tchange46":"АВТО КУПИТЬ", "tchange47":"Продать по этой цене", - "tchange48":"НЕДОСТАТОЧНО" + "tchange48":"НЕДОСТАТОЧНО", + "tchange49":"График цен" }, "rewardsharepage":{ "rchange1":"Вознаграждения", diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index 580d0549..e0444893 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -333,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", diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json index b41114a8..b2b1a6b4 100644 --- a/qortal-ui-core/language/zhc.json +++ b/qortal-ui-core/language/zhc.json @@ -333,7 +333,8 @@ "tchange45":"自动购买", "tchange46":"自动购买", "tchange47":"以这个价格出售", - "tchange48":"不够" + "tchange48":"不够", + "tchange49":"价格图表" }, "rewardsharepage":{ "rchange1":"铸币密钥", diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json index 52fa5400..2c5c86f3 100644 --- a/qortal-ui-core/language/zht.json +++ b/qortal-ui-core/language/zht.json @@ -333,7 +333,8 @@ "tchange45":"自動購買", "tchange46":"自動購買", "tchange47":"以這個價格出售", - "tchange48":"不夠" + "tchange48":"不夠", + "tchange49":"價格圖表" }, "rewardsharepage":{ "rchange1":"鑄幣密鑰", diff --git a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js index 47910961..bcfd5130 100644 --- a/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js +++ b/qortal-ui-plugins/plugins/core/trade-portal/trade-portal.src.js @@ -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 }) @@ -74,7 +80,7 @@ class TradePortal extends LitElement { displayTradeAddress: { type: String }, displayTradeLevel: { type: String }, displayTradeBalance: { type: String }, - qortRatio: {type: Number} + qortRatio: {type: Number} } } @@ -494,7 +500,7 @@ class TradePortal extends LitElement { .rvn.coinName:before { background-image: url('/img/qortrvn.png'); } - .arrr.coinName:before { + .arrr.coinName:before { background-image: url('/img/qortarrr.png'); } .coinName { @@ -655,7 +661,7 @@ class TradePortal extends LitElement { tradeFee: "~0.0005" } - let ravencoin = { + let ravencoin = { name: "RAVENCOIN", balance: "0", coinCode: "RVN", @@ -721,7 +727,7 @@ class TradePortal extends LitElement { handleStuckTradesConnectedWorker: null }) - workers.set("RAVENCOIN", { + workers.set("RAVENCOIN", { tradesConnectedWorker: null, handleStuckTradesConnectedWorker: null }) @@ -1162,6 +1168,9 @@ class TradePortal extends LitElement { QORT / RVN QORT / ARRR +
    + ${this.chartShowCoin()} +
    @@ -1412,6 +1421,31 @@ class TradePortal extends LitElement { return html`NOT ENOUGH ${this.listedCoins.get(this.selectedCoin).coinCode}` } + chartShowCoin() { + switch(this.listedCoins.get(this.selectedCoin).coinCode) { + case "BTC": + return html` chartsbtc.open()}>` + break + case "LTC": + return html` chartsltc.open()}>` + break + case "DOGE": + return html` chartsdoge.open()}>` + break + case "DGB": + return html` chartsdgb.open()}>` + break + case "RVN": + return html` chartsrvn.open()}>` + break + case "ARRR": + return html` chartsarrr.open()}>` + break + default: + break + } + } + exchangeRateQort() { switch(this.listedCoins.get(this.selectedCoin).coinCode) { case "BTC": @@ -1504,8 +1538,8 @@ class TradePortal extends LitElement { case 'DIGIBYTE': _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}` _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey - break - case 'RAVENCOIN': + break + case 'RAVENCOIN': _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}` _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey break @@ -2945,4 +2979,4 @@ class TradePortal extends LitElement { } } -window.customElements.define('trade-portal', TradePortal) +window.customElements.define('trade-portal', TradePortal) \ No newline at end of file From 9ac4bb83d8678c147537cf5f85f47ea18915659e Mon Sep 17 00:00:00 2001 From: Phillip Lang Martinez Date: Mon, 9 Jan 2023 17:57:38 -0500 Subject: [PATCH 16/19] change padding --- .../plugins/core/messaging/q-chat/q-chat-css.src.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js index bab60e1d..5856a389 100644 --- a/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js +++ b/qortal-ui-plugins/plugins/core/messaging/q-chat/q-chat-css.src.js @@ -94,7 +94,7 @@ export const qchatStyles = css` } .people-list ul { - padding: 0; + padding: 0px 0px 60px 0px; height: 85vh; overflow-y: auto; overflow-x: hidden; From 9fec8908c1f7380922c8cdb42d0516ecd522f274 Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Mon, 9 Jan 2023 19:37:52 -0500 Subject: [PATCH 17/19] Chat User Info Completed --- .../plugins/core/components/ChatRightPanel.js | 116 +++--------------- .../core/components/ChatScroller-css.js | 7 ++ .../plugins/core/components/ChatScroller.js | 80 ++++++++++-- .../core/components/ChatSideNavHeads.js | 15 +-- .../plugins/core/components/UserInfo.js | 0 5 files changed, 94 insertions(+), 124 deletions(-) delete mode 100644 qortal-ui-plugins/plugins/core/components/UserInfo.js diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index ec38a6fd..fa1734c0 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -12,15 +12,14 @@ import "@material/mwc-icon"; import '@vaadin/button'; import "./WrapperModal"; import "./TipUser" +import "./UserInfo/UserInfo"; class ChatRightPanel extends LitElement { static get properties() { return { - isLoading: { type: Boolean }, openUserInfo: { type: Boolean }, leaveGroupObj: { type: Object }, error: { type: Boolean }, - message: { type: String }, chatHeads: { type: Array }, groupAdmin: { attribute: false }, groupMembers: { attribute: false }, @@ -41,12 +40,10 @@ class ChatRightPanel extends LitElement { constructor() { super() - this.isLoading = false this.openUserInfo = false this.leaveGroupObj = {} this.leaveFee = 0.001 this.error = false - this.message = "" this.chatHeads = [] this.groupAdmin = [] this.groupMembers = [] @@ -61,6 +58,7 @@ class ChatRightPanel extends LitElement { this.errorMessage = "" this.successMessage = "" this.setOpenTipUser = this.setOpenTipUser.bind(this); + this.setOpenUserInfo = this.setOpenUserInfo.bind(this); } static get styles() { @@ -190,46 +188,6 @@ class ChatRightPanel extends LitElement { font-size: 14px; color: var(--chat-bubble-msg-color); } - - .user-info-header { - font-family: Montserrat, sans-serif; - text-align: center; - font-size: 25px; - color: var(--chat-bubble-msg-color); - margin-bottom: 10px; - padding: 10px 0; - user-select: none; - } - - .send-message-button { - font-family: Roboto, sans-serif; - letter-spacing: 0.3px; - font-weight: 300; - padding: 8px 5px; - border-radius: 3px; - text-align: center; - color: var(--mdc-theme-primary); - transition: all 0.3s ease-in-out; - } - - .send-message-button:hover { - cursor: pointer; - background-color: #03a8f485; - } - - .close-icon { - position: absolute; - top: 3px; - right: 5px; - color: #676b71; - width: 14px; - transition: all 0.1s ease-in-out; - } - - .close-icon:hover { - cursor: pointer; - color: #494c50; - } ` } @@ -279,6 +237,10 @@ class ChatRightPanel extends LitElement { this.openTipUser = props } + setOpenUserInfo(props) { + this.openUserInfo = props + } + render() { const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner) return html` @@ -291,7 +253,7 @@ class ChatRightPanel extends LitElement {

    ${this.leaveGroupObj && this.leaveGroupObj.description}

    Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}

    - +

    Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}


    @@ -337,9 +299,8 @@ class ChatRightPanel extends LitElement {
    - { - if (this.isLoading) return this.openUserInfo = false; this.userName = ""; this.shadowRoot.querySelector("tip-user").shadowRoot.getElementById('amountInput').value = ""; @@ -347,59 +308,14 @@ class ChatRightPanel extends LitElement { style=${ this.openUserInfo ? "display: block" : "display: none" }> -
    - { - this.openUserInfo = false - }} - ?disabled="${this.isLoading}"> - - -
    - ${translate("chatpage.cchange58")} -
    -
    { - this.openTipUser = true - this.openUserInfo = false - this.chatEditor.disable(); - }}> - ${translate("chatpage.cchange59")} -
    -
    - - - ${translate("grouppage.gchange36")}   - - - - - ${this.message} - -
    -
    + this.setOpenUserInfo(val)} + .setOpenTipUser=${(val) => this.setOpenTipUser(val)} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} + .chatEditor=${this.chatEditor} + .userName=${this.userName} + .selectedHead=${this.selectedHead} + >
    { diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js index 1d054bab..64b49b45 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js @@ -63,12 +63,19 @@ export const chatStyles = css` margin-bottom: 5px; } + .forwarded-text { + user-select: none; + color: #03a9f4; + margin-bottom: 5px; + } + .message-data-forward { user-select: none; color: var(--mainmenutext); margin-bottom: 5px; font-size: 12px; } + .message-data-my-name { color: #cf21e8; text-shadow: 0 0 3px #cf21e8; diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index 5c0a7954..38903750 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -5,18 +5,19 @@ import { translate, get } from 'lit-translate'; import {unsafeHTML} from 'lit/directives/unsafe-html.js'; import { chatStyles } from './ChatScroller-css.js' import { Epml } from "../../../epml"; +import { EmojiPicker } from 'emoji-picker-js'; +import { cropAddress } from "../../utils/cropAddress"; import './LevelFounder.js'; import './NameMenu.js'; import './ChatModals.js'; import './WrapperModal'; import './TipUser' +import "./UserInfo/UserInfo"; import '@vaadin/icons'; import '@vaadin/icon'; import '@material/mwc-button'; import '@material/mwc-dialog'; import '@material/mwc-icon'; -import { EmojiPicker } from 'emoji-picker-js'; -import { cropAddress } from "../../utils/cropAddress"; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) let toggledMessage = {} @@ -42,7 +43,9 @@ class ChatScroller extends LitElement { setForwardProperties: { attribute: false }, setOpenPrivateMessage: { attribute: false }, openTipUser: { type: Boolean }, - userName: { type: String } + openUserInfo: { type: Boolean }, + userName: { type: String }, + selectedHead: { type: Object } } } @@ -54,14 +57,17 @@ class ChatScroller extends LitElement { this._upObserverhandler = this._upObserverhandler.bind(this) this._downObserverHandler = this._downObserverHandler.bind(this) this.setOpenTipUser = this.setOpenTipUser.bind(this) + this.setOpenUserInfo = this.setOpenUserInfo.bind(this) this.setUserName = this.setUserName.bind(this) this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]") this.openTipUser = false; + this.openUserInfo = false; this.userName = ""; } render() { + console.log(9, "chat scroller here"); let formattedMessages = this.messages.reduce((messageArray, message, index) => { const lastGroupedMessage = messageArray[messageArray.length - 1]; let timestamp; @@ -126,6 +132,7 @@ class ChatScroller extends LitElement { .setForwardProperties=${this.setForwardProperties} .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} .setOpenTipUser=${(val) => this.setOpenTipUser(val)} + .setOpenUserInfo=${(val) => this.setOpenUserInfo(val)} .setUserName=${(val) => this.setUserName(val)}> ` ) @@ -146,6 +153,25 @@ class ChatScroller extends LitElement { .setOpenTipUser=${(val) => this.setOpenTipUser(val)}> + { + this.openUserInfo = false; + this.chatEditor.enable(); + this.userName = ""; + this.selectedHead = {}; + }} + style=${ + this.openUserInfo ? "display: block" : "display: none" + }> + this.setOpenUserInfo(val)} + .setOpenTipUser=${(val) => this.setOpenTipUser(val)} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} + .chatEditor=${this.chatEditor} + .userName=${this.userName} + .selectedHead=${this.selectedHead} + > + ` } @@ -159,6 +185,9 @@ class ChatScroller extends LitElement { if(changedProperties.has('openTipUser')){ return true } + if(changedProperties.has('openUserInfo')){ + return true + } // Only update element if prop1 changed. return changedProperties.has('messages'); } @@ -179,8 +208,18 @@ class ChatScroller extends LitElement { this.chatEditor.disable(); } + setOpenUserInfo(props) { + this.openUserInfo = props; + this.chatEditor.disable(); + } + setUserName(props) { - this.userName = props; + this.userName = props.senderName ? props.senderName : props.sender; + this.selectedHead = { + ...this.selectedHead, + address: props.sender, + name: props.senderName, + }; } async firstUpdated() { @@ -280,6 +319,7 @@ class MessageTemplate extends LitElement { viewImage: { type: Boolean }, setOpenPrivateMessage : { attribute: false }, setOpenTipUser: { attribute: false }, + setOpenUserInfo: { attribute: false }, setUserName: { attribute: false } } } @@ -450,7 +490,13 @@ class MessageTemplate extends LitElement { (this.isSingleMessageInGroup === true && this.isLastMessageInGroup === true)) ? ( html` -
    +
    { + if (this.myAddress === this.messageObj.sender) return; + this.setOpenUserInfo(true); + this.setUserName(this.messageObj); + }} class="message-data-avatar"> ${avatarImg}
    ` @@ -477,7 +523,14 @@ class MessageTemplate extends LitElement { ${repliedToData && html`
    -

    - ${repliedToData.senderName ?? cropAddress(repliedToData.sender)} +

    { + if (this.myAddress === repliedToData.sender) return; + this.setOpenUserInfo(true); + this.setUserName(repliedToData) + }} + class="original-message-sender"> + ${repliedToData.senderName ?? cropAddress(repliedToData.sender)}

    ${repliedToData.decodedMessage.messageText} @@ -837,7 +897,7 @@ class ChatMenu extends LitElement { data-text="${translate("blockpage.bcchange18")}" @click=${() => { this.setOpenTipUser(true); - this.setUserName(this.originalMessage.sender); + this.setUserName(this.originalMessage); }}>

    diff --git a/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js b/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js index 220aeb79..b0798399 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js +++ b/qortal-ui-plugins/plugins/core/components/ChatSideNavHeads.js @@ -93,7 +93,6 @@ class ChatSideNavHeads extends LitElement { } imageHTMLRes.onload = () => { this.isImageLoaded = true; - this.requestUpdate(); } imageHTMLRes.onerror = () => { if (this.imageFetches < 4) { @@ -105,14 +104,10 @@ class ChatSideNavHeads extends LitElement { this.isImageLoaded = false } }; - console.log(imageHTMLRes, "here8") return imageHTMLRes; } render() { - console.log(9, 'chat side nav head'); - console.log(this.isImageLoaded, 'Is image loaded'); - console.log(this.chatInfo, 'Chat Info Here'); let avatarImg = "" if (this.chatInfo.name) { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; @@ -181,15 +176,7 @@ class ChatSideNavHeads extends LitElement { this.config = JSON.parse(c) }) }) - parentEpml.imReady() - - - } - - updated(changedProperties) { - if (changedProperties && changedProperties.has("avatarImg")) { - console.log(this.avatarImg, "avatarImg"); - } + parentEpml.imReady(); } shouldUpdate(changedProperties) { diff --git a/qortal-ui-plugins/plugins/core/components/UserInfo.js b/qortal-ui-plugins/plugins/core/components/UserInfo.js deleted file mode 100644 index e69de29b..00000000 From ab8de0dbcdf6853119d70f163d8e4ab35bf5764d Mon Sep 17 00:00:00 2001 From: Justin Ferrari <‘justinwesleyferrari@gmail.com’> Date: Mon, 9 Jan 2023 20:07:48 -0500 Subject: [PATCH 18/19] Added User Info Folder (Fixed .gitignore) --- .gitignore | 2 +- .../core/components/UserInfo/UserInfo-css.js | 69 +++++++++ .../core/components/UserInfo/UserInfo.js | 134 ++++++++++++++++++ 3 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo-css.js create mode 100644 qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo.js diff --git a/.gitignore b/.gitignore index 6cf26473..02e71ef5 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,7 @@ yarn.lock qortal-ui-plugins/plugins/core/**/*.js !*.src.js qortal-ui-core/src/redux/app/version.js -!qortal-ui-plugins/plugins/core/components/*.js +!qortal-ui-plugins/plugins/core/components/**/*.js # Node modules node_modules/ diff --git a/qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo-css.js b/qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo-css.js new file mode 100644 index 00000000..d22025ca --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo-css.js @@ -0,0 +1,69 @@ +import { css } from 'lit' + +export const userInfoStyles = css` + .user-info-header { + font-family: Montserrat, sans-serif; + text-align: center; + font-size: 28px; + color: var(--chat-bubble-msg-color); + margin-bottom: 10px; + padding: 10px 0; + user-select: none; + } + + .avatar-container { + display: flex; + justify-content: center; + } + + .user-info-avatar { + width: 100px; + height: 100px; + border-radius: 50%; + margin: 10px 0; + } + + .user-info-no-avatar { + display: flex; + justify-content: center; + align-items: center; + text-transform: capitalize; + font-size: 50px; + font-family: Roboto, sans-serif; + width: 100px; + height: 100px; + border-radius:50%; + background: var(--chatHeadBg); + color: var(--chatHeadText); + } + + .send-message-button { + font-family: Roboto, sans-serif; + letter-spacing: 0.3px; + font-weight: 300; + padding: 8px 5px; + border-radius: 3px; + text-align: center; + color: var(--mdc-theme-primary); + transition: all 0.3s ease-in-out; + } + + .send-message-button:hover { + cursor: pointer; + background-color: #03a8f485; + } + + .close-icon { + position: absolute; + top: 3px; + right: 5px; + color: #676b71; + width: 14px; + transition: all 0.1s ease-in-out; + } + + .close-icon:hover { + cursor: pointer; + color: #494c50; + } +` \ No newline at end of file diff --git a/qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo.js b/qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo.js new file mode 100644 index 00000000..c31b4515 --- /dev/null +++ b/qortal-ui-plugins/plugins/core/components/UserInfo/UserInfo.js @@ -0,0 +1,134 @@ +import { LitElement, html } from 'lit'; +import { render } from 'lit/html.js'; +import { translate } from 'lit-translate'; +import { userInfoStyles } from './UserInfo-css.js'; +import { Epml } from '../../../../epml'; +import '@vaadin/button'; +import '@polymer/paper-progress/paper-progress.js'; +import { cropAddress } from '../../../utils/cropAddress.js'; + +// const parentEpml = new Epml({ type: "WINDOW", source: window.parent }); + +export class UserInfo extends LitElement { + static get properties() { + return { + setOpenUserInfo: { attribute: false }, + setOpenTipUser: { attribute: false }, + setOpenPrivateMessage: { attribute: false }, + chatEditor: { type: Object }, + userName: { type: String }, + selectedHead: { type: Object }, + isImageLoaded: { type: Boolean } + } + } + + constructor() { + super() + this.isImageLoaded = false + this.selectedHead = {} + this.imageFetches = 0 +} + + static styles = [userInfoStyles] + + createImage(imageUrl) { + const imageHTMLRes = new Image(); + imageHTMLRes.src = imageUrl; + imageHTMLRes.classList.add("user-info-avatar"); + // imageHTMLRes.style= "width:30px; height:30px; float: left; border-radius:50%; font-size:14px"; + imageHTMLRes.onload = () => { + this.isImageLoaded = true; + } + imageHTMLRes.onerror = () => { + if (this.imageFetches < 4) { + setTimeout(() => { + this.imageFetches = this.imageFetches + 1; + imageHTMLRes.src = imageUrl; + }, 500); + } else { + this.isImageLoaded = false + } + }; + return imageHTMLRes; + } + + updated(changedProperties) { + if (changedProperties && changedProperties.has('selectedHead')) { + if (this.selectedHead) { + console.log(this.selectedHead, "selected head") + } + } + } + + render() { + let avatarImg = ""; + if (this.selectedHead.name) { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.selectedHead.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`; + avatarImg = this.createImage(avatarUrl); + } + return html` +
    + { + this.setOpenUserInfo(false) + this.chatEditor.enable(); + }}> + + ${this.isImageLoaded ? + html` +
    + ${avatarImg} +
    ` : + html``} + ${!this.isImageLoaded && this.selectedHead.name ? + html` +
    + +
    + ` + : ""} + ${!this.isImageLoaded && !this.selectedHead.name ? + html` +
    + avatar +
    ` + : ""} + +
    + ${translate("chatpage.cchange58")} +
    +
    { + this.setOpenTipUser(true); + this.setOpenUserInfo(false); + this.chatEditor.disable(); + }}> + ${translate("chatpage.cchange59")} +
    +
    + ` + } +} +customElements.define('user-info', UserInfo); From 71ccaaa60443c418b6e0dd921e0ea3f17d3feee3 Mon Sep 17 00:00:00 2001 From: Phillip Date: Tue, 10 Jan 2023 15:40:20 -0500 Subject: [PATCH 19/19] fix package jsons --- package.json | 14 +++++++------- qortal-ui-core/package.json | 17 ++++++++--------- qortal-ui-plugins/package.json | 23 +++++++++++------------ 3 files changed, 26 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index 67893cef..6f6fd7ba 100644 --- a/package.json +++ b/package.json @@ -19,12 +19,12 @@ "install_link:all": "(cd qortal-ui-core && yarn install && yarn link) && (cd qortal-ui-plugins && yarn install && yarn link) && (cd qortal-ui-crypto && yarn install && yarn link) && (yarn link qortal-ui-core && yarn link qortal-ui-plugins && yarn link qortal-ui-crypto)", "dev": "node server.js", "prebuild": "node -p \"'export const UI_VERSION = ' + JSON.stringify(require('./package.json').version) + ';'\" > qortal-ui-core/src/redux/app/version.js", - "build-dev": "node build.js", - "build": "NODE_ENV=production node build.js", - "server": "NODE_ENV=production node server.js", - "watch": "node watch.js", - "watch-inline": "node watch-inline.js", - "start-electron": "NODE_ENV=production electron .", + "build-dev": "node --max-old-space-size=8192 build.js", + "build": "NODE_ENV=production node --max-old-space-size=8192 build.js", + "server": "NODE_ENV=production node --max-old-space-size=8192 server.js", + "watch": "node --max-old-space-size=8192 watch.js", + "watch-inline": "node --max-old-space-size=8192 watch-inline.js", + "start-electron": "NODE_ENV=production electron --js-flags=--max-old-space-size=8192 .", "build-electron": "electron-builder build --publish never", "deploy-electron": "electron-builder build --win --publish never", "release": "NODE_ENV=production electron-builder build --publish never", @@ -46,4 +46,4 @@ "engines": { "node": ">=16.17.1" } -} +} \ No newline at end of file diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index 51034438..ba56c34c 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -58,17 +58,17 @@ "@rollup/plugin-commonjs": "24.0.0", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.2.1", - "@vaadin/button": "23.3.2", - "@vaadin/grid": "23.3.2", - "@vaadin/icons": "23.3.2", - "@vaadin/password-field": "23.3.2", - "@vaadin/tooltip": "23.3.2", + "@rollup/plugin-terser": "0.3.0", + "@vaadin/button": "23.3.3", + "@vaadin/grid": "23.3.3", + "@vaadin/icons": "23.3.3", + "@vaadin/password-field": "23.3.3", + "@vaadin/tooltip": "23.3.3", "asmcrypto.js": "2.3.2", "bcryptjs": "2.4.3", "epml": "0.3.3", "file-saver": "2.0.5", - "lit": "2.5.0", + "lit": "2.6.0", "lit-translate": "2.0.1", "pwa-helpers": "0.9.1", "random-sentence-generator": "0.0.8", @@ -78,8 +78,7 @@ "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0", - "rollup-plugin-terser": "7.0.2", - "rollup-plugin-web-worker-loader": "^1.6.1" + "rollup-plugin-web-worker-loader": "1.6.1" }, "engines": { "node": ">=16.17.1" diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index e8396fc1..87c5c4a5 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -20,10 +20,10 @@ "@material/mwc-list": "0.27.0", "@material/mwc-select": "0.27.0", "asmcrypto.js": "2.3.2", - "compressorjs": "^1.1.1", + "compressorjs": "1.1.1", "emoji-picker-js": "https://github.com/Qortal/emoji-picker-js", - "localforage": "^1.10.0", - "short-unique-id": "^4.4.4" + "localforage": "1.10.0", + "short-unique-id": "4.4.4" }, "devDependencies": { "@babel/core": "7.20.12", @@ -50,23 +50,22 @@ "@rollup/plugin-commonjs": "24.0.0", "@rollup/plugin-node-resolve": "15.0.1", "@rollup/plugin-replace": "5.0.2", - "@rollup/plugin-terser": "0.2.1", - "@vaadin/avatar": "23.3.2", - "@vaadin/button": "23.3.2", - "@vaadin/grid": "23.3.2", - "@vaadin/icons": "23.3.2", - "@vaadin/tooltip": "23.3.2", + "@rollup/plugin-terser": "0.3.0", + "@vaadin/avatar": "23.3.3", + "@vaadin/button": "23.3.3", + "@vaadin/grid": "23.3.3", + "@vaadin/icons": "23.3.3", + "@vaadin/tooltip": "23.3.3", "epml": "0.3.3", "file-saver": "2.0.5", "highcharts": "10.3.2", "html-escaper": "3.0.3", - "lit": "2.5.0", + "lit": "2.6.0", "lit-translate": "2.0.1", "rollup": "3.9.1", "rollup-plugin-node-globals": "1.4.0", "rollup-plugin-progress": "1.1.2", - "rollup-plugin-terser": "7.0.2", - "rollup-plugin-web-worker-loader": "^1.6.1" + "rollup-plugin-web-worker-loader": "1.6.1" }, "engines": { "node": ">=16.17.1"