forked from Qortal/qortal-ui
Phillip Lang Martinez
2 years ago
8 changed files with 608 additions and 9 deletions
@ -17,6 +17,7 @@
|
||||
"author": "QORTAL <[email protected]>", |
||||
"license": "GPL-3.0", |
||||
"dependencies": { |
||||
"@lit-labs/motion": "^1.0.3", |
||||
"@material/mwc-list": "0.27.0", |
||||
"@material/mwc-select": "0.27.0", |
||||
"asmcrypto.js": "2.3.2", |
||||
|
@ -0,0 +1,247 @@
|
||||
import { LitElement, html, css } from 'lit'; |
||||
import { render } from 'lit/html.js'; |
||||
import { get, translate } from 'lit-translate'; |
||||
import { Epml } from '../../../epml'; |
||||
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 }) |
||||
|
||||
class ChatLeaveGroup extends LitElement { |
||||
static get properties() { |
||||
return { |
||||
isLoading: { type: Boolean }, |
||||
isOpenLeaveModal: {type: Boolean}, |
||||
leaveGroupObj: { type: Object }, |
||||
error: {type: Boolean}, |
||||
message: {type: String}, |
||||
chatHeads: {type: Array}, |
||||
setActiveChatHeadUrl: {attribute: false} |
||||
} |
||||
} |
||||
|
||||
constructor() { |
||||
super(); |
||||
this.isLoading = false; |
||||
this.isOpenLeaveModal = false |
||||
this.leaveGroupObj = {} |
||||
this.leaveFee = 0.001 |
||||
this.error = false |
||||
this.message = '' |
||||
this.chatHeads = [] |
||||
} |
||||
|
||||
static get styles() { |
||||
return css` |
||||
.top-bar-icon { |
||||
cursor: pointer; |
||||
height: 18px; |
||||
width: 18px; |
||||
transition: .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; |
||||
} |
||||
` |
||||
} |
||||
|
||||
firstUpdated() { |
||||
|
||||
} |
||||
|
||||
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() { |
||||
|
||||
|
||||
let interval = null |
||||
let stop = false |
||||
const getAnswer = async () => { |
||||
const currentChats = this.chatHeads |
||||
|
||||
if (!stop) { |
||||
stop = true; |
||||
try { |
||||
const findGroup = currentChats.find((item)=> item.groupId === this.leaveGroupObj.groupId) |
||||
if (!findGroup) { |
||||
clearInterval(interval) |
||||
this.isLoading = false |
||||
this.isOpenLeaveModal= false |
||||
this.setActiveChatHeadUrl('') |
||||
} |
||||
|
||||
} catch (error) { |
||||
} |
||||
stop = false |
||||
} |
||||
}; |
||||
interval = setInterval(getAnswer, 5000); |
||||
} |
||||
|
||||
async _leaveGroup(groupId, groupName) { |
||||
// Reset Default Settings...
|
||||
this.resetDefaultSettings() |
||||
const leaveFeeInput = this.leaveFee |
||||
|
||||
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: 32, |
||||
nonce: this.selectedAddress.nonce, |
||||
params: { |
||||
fee: leaveFeeInput, |
||||
registrantAddress: this.selectedAddress.address, |
||||
rGroupName: groupName, |
||||
rGroupId: groupId, |
||||
lastReference: lastRef, |
||||
groupdialog3: groupdialog3, |
||||
groupdialog4: groupdialog4, |
||||
} |
||||
}) |
||||
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() |
||||
} |
||||
|
||||
render() { |
||||
return html` |
||||
<vaadin-icon @click=${()=> { |
||||
this.isOpenLeaveModal = true |
||||
}} class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:exit" slot="icon"></vaadin-icon> |
||||
<!-- Leave Group Dialog --> |
||||
<wrapper-modal
|
||||
.removeImage=${() => { |
||||
if(this.isLoading) return |
||||
this.isOpenLeaveModal = false |
||||
} }
|
||||
style=${(this.isOpenLeaveModal) ? "display: block" : "display: none"}> |
||||
<div style="text-align:center"> |
||||
<h1>${translate("grouppage.gchange35")}</h1> |
||||
<hr> |
||||
</div> |
||||
|
||||
<div class="itemList"> |
||||
<span class="title">${translate("grouppage.gchange4")}</span> |
||||
<br> |
||||
<div><span>${this.leaveGroupObj.groupName}</span></div> |
||||
|
||||
<span class="title">${translate("grouppage.gchange5")}</span> |
||||
<br> |
||||
<div><span>${this.leaveGroupObj.description}</span></div> |
||||
|
||||
<span class="title">${translate("grouppage.gchange10")}</span> |
||||
<br> |
||||
<div><span>${this.leaveGroupObj.owner}</span></div> |
||||
|
||||
<span class="title">${translate("grouppage.gchange31")}</span> |
||||
<br> |
||||
<div><span><time-ago datetime=${this.timeIsoString(this.leaveGroupObj.created)}></time-ago></span></div> |
||||
|
||||
${!this.leaveGroupObj.updated ? "" : html`<span class="title">${translate("grouppage.gchange32")}</span>
|
||||
<br> |
||||
<div><span><time-ago datetime=${this.timeIsoString(this.leaveGroupObj.updated)}></time-ago></span></div>`} |
||||
</div> |
||||
|
||||
<div style="text-align:right; height:36px;"> |
||||
<span ?hidden="${!this.isLoading}"> |
||||
<!-- loading message --> |
||||
${translate("grouppage.gchange36")} |
||||
<paper-spinner-lite |
||||
style="margin-top:12px;" |
||||
?active="${this.isLoading}" |
||||
alt="Leaving" |
||||
> |
||||
</paper-spinner-lite> |
||||
</span> |
||||
<span ?hidden=${this.message === ''} style="${this.error ? 'color:red;' : ''}"> |
||||
${this.message} |
||||
</span> |
||||
</div> |
||||
|
||||
<button |
||||
class="modal-button" |
||||
?disabled="${this.isLoading}" |
||||
@click=${() => this._leaveGroup(this.leaveGroupObj.groupId, this.leaveGroupObj.groupName)} |
||||
> |
||||
${translate("grouppage.gchange37")} |
||||
</button> |
||||
<button |
||||
@click=${() => { |
||||
this.isOpenLeaveModal= false |
||||
}} |
||||
class="modal-button" |
||||
?disabled="${this.isLoading}" |
||||
|
||||
> |
||||
${translate("general.close")} |
||||
</button> |
||||
</wrapper-modal > |
||||
`;
|
||||
} |
||||
} |
||||
|
||||
customElements.define('chat-leave-group', ChatLeaveGroup); |
@ -0,0 +1,180 @@
|
||||
import { LitElement, html, css } from 'lit' |
||||
import { Epml } from '../../../epml.js' |
||||
|
||||
import '@material/mwc-icon' |
||||
|
||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) |
||||
|
||||
class ChatSideNavHeads extends LitElement { |
||||
static get properties() { |
||||
return { |
||||
selectedAddress: { type: Object }, |
||||
config: { type: Object }, |
||||
chatInfo: { type: Object }, |
||||
iconName: { type: String }, |
||||
activeChatHeadUrl: { type: String }, |
||||
isImageLoaded: { type: Boolean }, |
||||
setActiveChatHeadUrl: {attribute: false} |
||||
} |
||||
} |
||||
|
||||
static get styles() { |
||||
return css` |
||||
ul { |
||||
list-style-type: none; |
||||
} |
||||
li { |
||||
padding: 10px 2px 10px 5px; |
||||
cursor: pointer; |
||||
width: 100%; |
||||
display: flex; |
||||
box-sizing: border-box; |
||||
font-size: 14px; |
||||
transition: 0.2s background-color; |
||||
} |
||||
|
||||
li:hover { |
||||
background-color: var(--lightChatHeadHover); |
||||
} |
||||
|
||||
.active { |
||||
background: var(--menuactive); |
||||
border-left: 4px solid #3498db; |
||||
} |
||||
|
||||
.img-icon { |
||||
font-size:40px; |
||||
color: var(--chat-group); |
||||
} |
||||
|
||||
.about { |
||||
margin-top: 8px; |
||||
} |
||||
|
||||
.about { |
||||
padding-left: 8px; |
||||
} |
||||
|
||||
.status { |
||||
color: #92959e; |
||||
} |
||||
|
||||
.clearfix:after { |
||||
visibility: hidden; |
||||
display: block; |
||||
font-size: 0; |
||||
content: " "; |
||||
clear: both; |
||||
height: 0; |
||||
} |
||||
` |
||||
} |
||||
|
||||
constructor() { |
||||
super() |
||||
this.selectedAddress = {} |
||||
this.config = { |
||||
user: { |
||||
node: { |
||||
|
||||
} |
||||
} |
||||
} |
||||
this.chatInfo = {} |
||||
this.iconName = '' |
||||
this.activeChatHeadUrl = '' |
||||
this.isImageLoaded = false |
||||
this.imageFetches = 0 |
||||
} |
||||
|
||||
createImage(imageUrl) { |
||||
const imageHTMLRes = new Image(); |
||||
imageHTMLRes.src = imageUrl; |
||||
imageHTMLRes.style= "width:30px; height:30px; float: left; border-radius:50%; font-size:14px"; |
||||
imageHTMLRes.onclick= () => { |
||||
this.openDialogImage = true; |
||||
} |
||||
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; |
||||
} |
||||
|
||||
render() { |
||||
let avatarImg = ''; |
||||
let backupAvatarImg = '' |
||||
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) |
||||
|
||||
} |
||||
|
||||
return html` |
||||
<li @click=${() => this.getUrl(this.chatInfo.url)} class="clearfix"> |
||||
${this.isImageLoaded ? html`${avatarImg}` : html`` } |
||||
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? html`<mwc-icon class="img-icon">account_circle</mwc-icon>` : html`` } |
||||
${!this.isImageLoaded && this.chatInfo.name ? html`<div style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadBgActive)' : 'var(--chatHeadBg)' }; color: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadTextActive)' : 'var(--chatHeadText)' }; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize">${this.chatInfo.name.charAt(0)}</div>`: ''} |
||||
${!this.isImageLoaded && this.chatInfo.groupName ? html`<div style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadBgActive)' : 'var(--chatHeadBg)' }; color: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadTextActive)' : 'var(--chatHeadText)' }; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize">${this.chatInfo.groupName.charAt(0)}</div>`: ''} |
||||
<div class="about"> |
||||
<div class="name"><span style="float:left; padding-left: 8px; color: var(--chat-group);">${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} </span> </div> |
||||
</div> |
||||
</li> |
||||
` |
||||
} |
||||
|
||||
firstUpdated() { |
||||
let configLoaded = false |
||||
parentEpml.ready().then(() => { |
||||
parentEpml.subscribe('selected_address', async selectedAddress => { |
||||
this.selectedAddress = {} |
||||
selectedAddress = JSON.parse(selectedAddress) |
||||
if (!selectedAddress || Object.entries(selectedAddress).length === 0) return |
||||
this.selectedAddress = selectedAddress |
||||
}) |
||||
parentEpml.subscribe('config', c => { |
||||
if (!configLoaded) { |
||||
configLoaded = true |
||||
} |
||||
this.config = JSON.parse(c) |
||||
}) |
||||
}) |
||||
parentEpml.imReady() |
||||
|
||||
|
||||
} |
||||
|
||||
shouldUpdate(changedProperties) { |
||||
if(changedProperties.has('activeChatHeadUrl')){ |
||||
return true |
||||
} |
||||
if(changedProperties.has('chatInfo')){ |
||||
return true |
||||
} |
||||
|
||||
return false |
||||
} |
||||
|
||||
getUrl(chatUrl) { |
||||
this.setActiveChatHeadUrl(chatUrl) |
||||
} |
||||
|
||||
onPageNavigation(pageUrl) { |
||||
parentEpml.request('setPageUrl', pageUrl) |
||||
} |
||||
} |
||||
|
||||
window.customElements.define('chat-side-nav-heads', ChatSideNavHeads) |
Loading…
Reference in new issue