mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-03-27 07:45:54 +00:00
start group chat components
This commit is contained in:
parent
7639c8b211
commit
b986f1ae58
@ -0,0 +1,46 @@
|
|||||||
|
'use strict';
|
||||||
|
import TransactionBase from '../TransactionBase.js'
|
||||||
|
import Base58 from '../../deps/Base58.js'
|
||||||
|
import { store } from '../../../api.js'
|
||||||
|
import { QORT_DECIMALS } from "../../constants.js"
|
||||||
|
|
||||||
|
export default class AddGroupAdminTransaction extends TransactionBase {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.type = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
render(html) {
|
||||||
|
const conf = store.getState().config
|
||||||
|
return html`
|
||||||
|
Are you sure to update this group ?
|
||||||
|
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
On pressing confirm, the group details will be updated!
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
set fee(fee) {
|
||||||
|
this._fee = fee * QORT_DECIMALS
|
||||||
|
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||||
|
}
|
||||||
|
set member(member) {
|
||||||
|
this._member = member instanceof Uint8Array ? member : this.constructor.Base58.decode(member)
|
||||||
|
}
|
||||||
|
|
||||||
|
set _groupId(_groupId){
|
||||||
|
this._groupBytes = this.constructor.utils.int32ToBytes(_groupId)
|
||||||
|
}
|
||||||
|
get params() {
|
||||||
|
const params = super.params
|
||||||
|
params.push(
|
||||||
|
this._groupBytes,
|
||||||
|
this._member,
|
||||||
|
this._feeBytes
|
||||||
|
)
|
||||||
|
console.log('verify params', params)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
@ -58,6 +58,7 @@ export default class LeaveGroupTransaction extends TransactionBase {
|
|||||||
this._rGroupIdBytes,
|
this._rGroupIdBytes,
|
||||||
this._feeBytes
|
this._feeBytes
|
||||||
)
|
)
|
||||||
|
console.log('check exec params2', params)
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
'use strict';
|
||||||
|
import TransactionBase from '../TransactionBase.js'
|
||||||
|
import Base58 from '../../deps/Base58.js'
|
||||||
|
import { store } from '../../../api.js'
|
||||||
|
import { QORT_DECIMALS } from "../../constants.js"
|
||||||
|
|
||||||
|
export default class RemoveGroupAdminTransaction extends TransactionBase {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.type = 25
|
||||||
|
}
|
||||||
|
|
||||||
|
render(html) {
|
||||||
|
const conf = store.getState().config
|
||||||
|
return html`
|
||||||
|
Are you sure to update this group ?
|
||||||
|
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
On pressing confirm, the group details will be updated
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
set fee(fee) {
|
||||||
|
this._fee = fee * QORT_DECIMALS
|
||||||
|
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||||
|
}
|
||||||
|
set member(member) {
|
||||||
|
this._member = member instanceof Uint8Array ? member : this.constructor.Base58.decode(member)
|
||||||
|
}
|
||||||
|
|
||||||
|
set _groupId(_groupId){
|
||||||
|
this._groupBytes = this.constructor.utils.int32ToBytes(_groupId)
|
||||||
|
}
|
||||||
|
get params() {
|
||||||
|
const params = super.params
|
||||||
|
params.push(
|
||||||
|
this._groupBytes,
|
||||||
|
this._member,
|
||||||
|
this._feeBytes
|
||||||
|
)
|
||||||
|
console.log('verify params', params)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
'use strict';
|
||||||
|
import TransactionBase from '../TransactionBase.js'
|
||||||
|
import Base58 from '../../deps/Base58.js'
|
||||||
|
import { store } from '../../../api.js'
|
||||||
|
import { QORT_DECIMALS } from "../../constants.js"
|
||||||
|
|
||||||
|
export default class UpdateGroupTransaction extends TransactionBase {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.type = 23
|
||||||
|
}
|
||||||
|
|
||||||
|
render(html) {
|
||||||
|
const conf = store.getState().config
|
||||||
|
return html`
|
||||||
|
Are you sure to update this group ?
|
||||||
|
<div style="background: #eee; padding: 8px; margin: 8px 0; border-radius: 5px;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
On pressing confirm, the group details will be updated!
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
set fee(fee) {
|
||||||
|
this._fee = fee * QORT_DECIMALS
|
||||||
|
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
|
||||||
|
}
|
||||||
|
set newOwner(newOwner) {
|
||||||
|
this._newOwner = newOwner instanceof Uint8Array ? newOwner : this.constructor.Base58.decode(newOwner)
|
||||||
|
}
|
||||||
|
set newIsOpen(newIsOpen) {
|
||||||
|
|
||||||
|
this._rGroupType = new Uint8Array(1)
|
||||||
|
this._rGroupType[0] = newIsOpen
|
||||||
|
}
|
||||||
|
set newDescription(newDescription) {
|
||||||
|
this._rGroupDescBytes = this.constructor.utils.stringtoUTF8Array(newDescription.toLocaleLowerCase())
|
||||||
|
this._rGroupDescLength = this.constructor.utils.int32ToBytes(this._rGroupDescBytes.length)
|
||||||
|
}
|
||||||
|
set newApprovalThreshold(newApprovalThreshold) {
|
||||||
|
this._rGroupApprovalThreshold = new Uint8Array(1)
|
||||||
|
this._rGroupApprovalThreshold[0] = newApprovalThreshold;
|
||||||
|
}
|
||||||
|
set newMinimumBlockDelay(newMinimumBlockDelay) {
|
||||||
|
this._rGroupMinimumBlockDelayBytes = this.constructor.utils.int32ToBytes(newMinimumBlockDelay)
|
||||||
|
}
|
||||||
|
set newMaximumBlockDelay(newMaximumBlockDelay) {
|
||||||
|
|
||||||
|
this._rGroupMaximumBlockDelayBytes = this.constructor.utils.int32ToBytes(newMaximumBlockDelay)
|
||||||
|
}
|
||||||
|
|
||||||
|
set _groupId(_groupId){
|
||||||
|
this._groupBytes = this.constructor.utils.int32ToBytes(_groupId)
|
||||||
|
}
|
||||||
|
get params() {
|
||||||
|
const params = super.params
|
||||||
|
params.push(
|
||||||
|
this._groupBytes,
|
||||||
|
this._newOwner,
|
||||||
|
this._rGroupDescLength,
|
||||||
|
this._rGroupDescBytes,
|
||||||
|
this._rGroupType,
|
||||||
|
this._rGroupApprovalThreshold,
|
||||||
|
this._rGroupMinimumBlockDelayBytes,
|
||||||
|
this._rGroupMaximumBlockDelayBytes,
|
||||||
|
this._feeBytes
|
||||||
|
)
|
||||||
|
console.log('verify params', params)
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
}
|
@ -7,8 +7,11 @@ import RewardShareTransaction from './reward-share/RewardShareTransaction.js'
|
|||||||
import RemoveRewardShareTransaction from './reward-share/RemoveRewardShareTransaction.js'
|
import RemoveRewardShareTransaction from './reward-share/RemoveRewardShareTransaction.js'
|
||||||
import CreateGroupTransaction from './groups/CreateGroupTransaction.js';
|
import CreateGroupTransaction from './groups/CreateGroupTransaction.js';
|
||||||
import JoinGroupTransaction from './groups/JoinGroupTransaction.js'
|
import JoinGroupTransaction from './groups/JoinGroupTransaction.js'
|
||||||
|
import UpdateGroupTransaction from './groups/UpdateGroupTransaction.js'
|
||||||
import LeaveGroupTransaction from './groups/LeaveGroupTransaction.js'
|
import LeaveGroupTransaction from './groups/LeaveGroupTransaction.js'
|
||||||
import PublicizeTransaction from './PublicizeTransaction.js'
|
import PublicizeTransaction from './PublicizeTransaction.js'
|
||||||
|
import AddGroupAdminTransaction from './groups/AddGroupAdminTransaction.js'
|
||||||
|
import RemoveGroupAdminTransaction from './groups/RemoveGroupAdminTransaction.js'
|
||||||
|
|
||||||
export const transactionTypes = {
|
export const transactionTypes = {
|
||||||
2: PaymentTransaction,
|
2: PaymentTransaction,
|
||||||
@ -18,6 +21,9 @@ export const transactionTypes = {
|
|||||||
181: GroupChatTransaction,
|
181: GroupChatTransaction,
|
||||||
19: PublicizeTransaction,
|
19: PublicizeTransaction,
|
||||||
22: CreateGroupTransaction,
|
22: CreateGroupTransaction,
|
||||||
|
23: UpdateGroupTransaction,
|
||||||
|
24: AddGroupAdminTransaction,
|
||||||
|
25: RemoveGroupAdminTransaction,
|
||||||
31: JoinGroupTransaction,
|
31: JoinGroupTransaction,
|
||||||
32: LeaveGroupTransaction,
|
32: LeaveGroupTransaction,
|
||||||
38: RewardShareTransaction,
|
38: RewardShareTransaction,
|
||||||
|
@ -54,6 +54,9 @@
|
|||||||
"@vaadin/button": "23.2.5",
|
"@vaadin/button": "23.2.5",
|
||||||
"@vaadin/grid": "23.2.5",
|
"@vaadin/grid": "23.2.5",
|
||||||
"@vaadin/icons": "23.2.5",
|
"@vaadin/icons": "23.2.5",
|
||||||
|
"@vaadin/tabs": "23.2.5",
|
||||||
|
"@vaadin/avatar": "23.2.5",
|
||||||
|
"@vaadin/horizontal-layout": "23.2.5",
|
||||||
"epml": "0.3.3",
|
"epml": "0.3.3",
|
||||||
"file-saver": "2.0.5",
|
"file-saver": "2.0.5",
|
||||||
"html-escaper": "3.0.3",
|
"html-escaper": "3.0.3",
|
||||||
|
335
qortal-ui-plugins/plugins/core/components/ChatGroupInvites.js
Normal file
335
qortal-ui-plugins/plugins/core/components/ChatGroupInvites.js
Normal file
@ -0,0 +1,335 @@
|
|||||||
|
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 ChatGroupInvites extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoading: { type: Boolean },
|
||||||
|
isOpenLeaveModal: { type: Boolean },
|
||||||
|
leaveGroupObj: { type: Object },
|
||||||
|
error: { type: Boolean },
|
||||||
|
message: { type: String },
|
||||||
|
chatHeads: { type: Array },
|
||||||
|
groupAdmin: { attribute: false },
|
||||||
|
groupMembers: { attribute: false },
|
||||||
|
selectedHead: { type: Object },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.isLoading = false
|
||||||
|
this.isOpenLeaveModal = false
|
||||||
|
this.leaveGroupObj = {}
|
||||||
|
this.leaveFee = 0.001
|
||||||
|
this.error = false
|
||||||
|
this.message = ""
|
||||||
|
this.chatHeads = []
|
||||||
|
this.groupAdmin = []
|
||||||
|
this.groupMembers = []
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
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(reference) {
|
||||||
|
let interval = null
|
||||||
|
let stop = false
|
||||||
|
const getAnswer = async () => {
|
||||||
|
|
||||||
|
|
||||||
|
if (!stop) {
|
||||||
|
stop = true
|
||||||
|
try {
|
||||||
|
let myRef = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
url: `/transactions/reference/${reference}`,
|
||||||
|
})
|
||||||
|
if (myRef && myRef.type) {
|
||||||
|
clearInterval(interval)
|
||||||
|
this.isLoading = false
|
||||||
|
this.isOpenLeaveModal = false
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
stop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interval = setInterval(getAnswer, 5000)
|
||||||
|
}
|
||||||
|
|
||||||
|
async 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) {
|
||||||
|
// Reset Default Settings...
|
||||||
|
this.resetDefaultSettings()
|
||||||
|
const leaveFeeInput = this.leaveFee
|
||||||
|
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
// Get Last Ref
|
||||||
|
|
||||||
|
const validateReceiver = async () => {
|
||||||
|
let lastRef = await this.getLastRef()
|
||||||
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
this.getTxnRequestResponse(myTransaction, lastRef )
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Transaction Request
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
const body = {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
reference: lastRef,
|
||||||
|
fee: leaveFeeInput,
|
||||||
|
ownerPublicKey: window.parent.Base58.encode(
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress
|
||||||
|
.keyPair.publicKey
|
||||||
|
),
|
||||||
|
groupId: groupId,
|
||||||
|
member: this.selectedHead.address,
|
||||||
|
}
|
||||||
|
const bodyToString = JSON.stringify(body)
|
||||||
|
let transactionBytes = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
method: "POST",
|
||||||
|
url: `/groups/addadmin`,
|
||||||
|
body: bodyToString,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const readforsign = await this.convertBytesForSigning(
|
||||||
|
transactionBytes
|
||||||
|
)
|
||||||
|
const body2 = {
|
||||||
|
privateKey: window.parent.Base58.encode(
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress
|
||||||
|
.keyPair.privateKey
|
||||||
|
),
|
||||||
|
transactionBytes: readforsign,
|
||||||
|
}
|
||||||
|
const bodyToString2 = JSON.stringify(body2)
|
||||||
|
let signTransaction = await this.signTx(bodyToString2)
|
||||||
|
let processTransaction = await this.process(signTransaction)
|
||||||
|
return processTransaction
|
||||||
|
}
|
||||||
|
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
async _removeAdmin(groupId) {
|
||||||
|
// Reset Default Settings...
|
||||||
|
this.resetDefaultSettings()
|
||||||
|
const leaveFeeInput = this.leaveFee
|
||||||
|
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
// Get Last Ref
|
||||||
|
|
||||||
|
const validateReceiver = async () => {
|
||||||
|
let lastRef = await this.getLastRef()
|
||||||
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
this.getTxnRequestResponse(myTransaction, lastRef)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Transaction Request
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
const body = {
|
||||||
|
timestamp: Date.now(),
|
||||||
|
reference: lastRef,
|
||||||
|
fee: leaveFeeInput,
|
||||||
|
ownerPublicKey: window.parent.Base58.encode(
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress
|
||||||
|
.keyPair.publicKey
|
||||||
|
),
|
||||||
|
groupId: groupId,
|
||||||
|
admin: this.selectedHead.address,
|
||||||
|
}
|
||||||
|
const bodyToString = JSON.stringify(body)
|
||||||
|
let transactionBytes = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
method: "POST",
|
||||||
|
url: `/groups/removeadmin`,
|
||||||
|
body: bodyToString,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
const readforsign = await this.convertBytesForSigning(
|
||||||
|
transactionBytes
|
||||||
|
)
|
||||||
|
const body2 = {
|
||||||
|
privateKey: window.parent.Base58.encode(
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress
|
||||||
|
.keyPair.privateKey
|
||||||
|
),
|
||||||
|
transactionBytes: readforsign,
|
||||||
|
}
|
||||||
|
const bodyToString2 = JSON.stringify(body2)
|
||||||
|
let signTransaction = await this.signTx(bodyToString2)
|
||||||
|
let processTransaction = await this.process(signTransaction)
|
||||||
|
return processTransaction
|
||||||
|
}
|
||||||
|
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log("leaveGroupObj", this.leaveGroupObj)
|
||||||
|
return html`
|
||||||
|
<vaadin-icon @click=${()=> {
|
||||||
|
this.isOpenLeaveModal = true
|
||||||
|
}} class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:users" slot="icon"></vaadin-icon>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<button @click=${() =>
|
||||||
|
this._addAdmin(
|
||||||
|
this.leaveGroupObj.groupId
|
||||||
|
)}>Promote to Admin</button>
|
||||||
|
<button @click=${() =>
|
||||||
|
this._removeAdmin(
|
||||||
|
this.leaveGroupObj.groupId
|
||||||
|
)}>Remove as Admin</button>
|
||||||
|
<div style="text-align:right; height:36px;">
|
||||||
|
<span ?hidden="${!this.isLoading}">
|
||||||
|
<!-- loading message -->
|
||||||
|
${translate("grouppage.gchange36")}
|
||||||
|
<paper-spinner-lite
|
||||||
|
style="margin-top:12px;"
|
||||||
|
?active="${this.isLoading}"
|
||||||
|
alt="Leaving"
|
||||||
|
>
|
||||||
|
</paper-spinner-lite>
|
||||||
|
</span>
|
||||||
|
<span ?hidden=${this.message === ""} style="${
|
||||||
|
this.error ? "color:red;" : ""
|
||||||
|
}">
|
||||||
|
${this.message}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click=${() => {
|
||||||
|
this.isOpenLeaveModal = false
|
||||||
|
}}
|
||||||
|
class="modal-button"
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</button>
|
||||||
|
</wrapper-modal >
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("chat-right-panel", ChatGroupInvites)
|
281
qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js
Normal file
281
qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
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 ChatGroupSettings 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 _convertToPrivate(groupId) {
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
}
|
||||||
|
const convertBytesForSigning = async (transactionBytesBase58) => {
|
||||||
|
let convertedBytes = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
method: "POST",
|
||||||
|
url: `/transactions/convert`,
|
||||||
|
body: `${transactionBytesBase58}`,
|
||||||
|
})
|
||||||
|
return convertedBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Make Transaction Request
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
let groupdialog3 = get("transactions.groupdialog3")
|
||||||
|
let groupdialog4 = get("transactions.groupdialog4")
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
"timestamp": Date.now(),
|
||||||
|
"reference": lastRef,
|
||||||
|
"fee": leaveFeeInput,
|
||||||
|
"ownerPublicKey": window.parent.Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.publicKey),
|
||||||
|
"groupId": groupId,
|
||||||
|
"newOwner": "QdR4bQ1fJFnSZgswtW27eE8ToXwHqUQyaU",
|
||||||
|
"newIsOpen": false,
|
||||||
|
"newDescription": "my group for accounts I like",
|
||||||
|
"newApprovalThreshold": "NONE",
|
||||||
|
"newMinimumBlockDelay": 5,
|
||||||
|
"newMaximumBlockDelay": 60
|
||||||
|
}
|
||||||
|
console.log('STRING3')
|
||||||
|
// const bodyToString = JSON.stringify(body)
|
||||||
|
// let transactionBytes = await parentEpml.request("apiCall", {
|
||||||
|
// type: "api",
|
||||||
|
// method: "POST",
|
||||||
|
// url: `/groups/update`,
|
||||||
|
// body: bodyToString,
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// console.log({transactionBytes})
|
||||||
|
// const readforsign = await convertBytesForSigning(transactionBytes)
|
||||||
|
// // const res = await signAndProcess(transactionBytes)
|
||||||
|
// const body2 = {
|
||||||
|
// "privateKey": window.parent.Base58.encode(window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey),
|
||||||
|
// "transactionBytes": readforsign
|
||||||
|
// }
|
||||||
|
// const bodyToString2 = JSON.stringify(body2)
|
||||||
|
// let signTransaction = await parentEpml.request("apiCall", {
|
||||||
|
// type: "api",
|
||||||
|
// method: "POST",
|
||||||
|
// url: `/transactions/sign`,
|
||||||
|
// body: bodyToString2,
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// let processTransaction = await parentEpml.request("apiCall", {
|
||||||
|
// type: "api",
|
||||||
|
// method: "POST",
|
||||||
|
// url: `/transactions/process`,
|
||||||
|
// body: signTransaction,
|
||||||
|
// })
|
||||||
|
// return processTransaction
|
||||||
|
console.log('this.selectedAddress.nonce', this.selectedAddress.nonce)
|
||||||
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
|
type: 23,
|
||||||
|
nonce: this.selectedAddress.nonce,
|
||||||
|
params: {
|
||||||
|
_groupId: groupId,
|
||||||
|
lastReference: lastRef,
|
||||||
|
fee: leaveFeeInput,
|
||||||
|
"newOwner": "QdR4bQ1fJFnSZgswtW27eE8ToXwHqUQyaU",
|
||||||
|
"newIsOpen": false,
|
||||||
|
"newDescription": "my group for accounts I like",
|
||||||
|
"newApprovalThreshold": "NONE",
|
||||||
|
"newMinimumBlockDelay": 5,
|
||||||
|
"newMaximumBlockDelay": 60
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return myTxnrequest
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
|
|
||||||
|
if (txnResponse === true) {
|
||||||
|
this.message = this.renderErr9Text()
|
||||||
|
this.error = false
|
||||||
|
this.confirmRelationship()
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
this.message = ""
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log('leaveGroupObj', this.leaveGroupObj)
|
||||||
|
return html`
|
||||||
|
<vaadin-icon @click=${()=> {
|
||||||
|
this.isOpenLeaveModal = true
|
||||||
|
}} class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:cog" 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>
|
||||||
|
<
|
||||||
|
<button @click=${() => this._convertToPrivate(this.leaveGroupObj.groupId, this.leaveGroupObj.groupName)}> Convert a public group to private</button>
|
||||||
|
|
||||||
|
<div style="text-align:right; height:36px;">
|
||||||
|
<span ?hidden="${!this.isLoading}">
|
||||||
|
<!-- loading message -->
|
||||||
|
${translate("grouppage.gchange36")}
|
||||||
|
<paper-spinner-lite
|
||||||
|
style="margin-top:12px;"
|
||||||
|
?active="${this.isLoading}"
|
||||||
|
alt="Leaving"
|
||||||
|
>
|
||||||
|
</paper-spinner-lite>
|
||||||
|
</span>
|
||||||
|
<span ?hidden=${this.message === ''} style="${this.error ? 'color:red;' : ''}">
|
||||||
|
${this.message}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click=${() => {
|
||||||
|
this.isOpenLeaveModal= false
|
||||||
|
}}
|
||||||
|
class="modal-button"
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</button>
|
||||||
|
</wrapper-modal >
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('chat-group-settings', ChatGroupSettings);
|
@ -0,0 +1,296 @@
|
|||||||
|
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';
|
||||||
|
import '@vaadin/tabs'
|
||||||
|
import '@vaadin/tabs/theme/material/vaadin-tabs.js';
|
||||||
|
import '@vaadin/avatar';
|
||||||
|
import '@vaadin/grid';
|
||||||
|
import '@vaadin/grid/vaadin-grid-filter-column.js';
|
||||||
|
import { columnBodyRenderer } from '@vaadin/grid/lit.js';
|
||||||
|
|
||||||
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
|
class ChatGroupsManagement 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},
|
||||||
|
selectedAddress: {attribute: Object},
|
||||||
|
currentTab: {type: Number},
|
||||||
|
groups: {type: Array}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isLoading = false;
|
||||||
|
this.isOpenLeaveModal = false
|
||||||
|
this.leaveGroupObj = {}
|
||||||
|
this.fee = null
|
||||||
|
this.error = false
|
||||||
|
this.message = ''
|
||||||
|
this.chatHeads = []
|
||||||
|
this.currentTab = 0
|
||||||
|
this.groups = []
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async getJoinedGroups(){
|
||||||
|
let joinedG = await parentEpml.request('apiCall', {
|
||||||
|
url: `/groups/member/${this.selectedAddress.address}`
|
||||||
|
})
|
||||||
|
return joinedG
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
let _joinedGroups = await this.getJoinedGroups()
|
||||||
|
this.joinedGroups = _joinedGroups
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
_tabChanged(e) {
|
||||||
|
this.currentTab = e.detail.value
|
||||||
|
}
|
||||||
|
|
||||||
|
async unitFee() {
|
||||||
|
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=LEAVE_GROUP`
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = await this.unitFee()
|
||||||
|
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: 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
nameRenderer(person){
|
||||||
|
console.log({person})
|
||||||
|
return html`
|
||||||
|
<vaadin-horizontal-layout style="align-items: center;display:flex" theme="spacing">
|
||||||
|
<vaadin-avatar style="margin-right:5px" img="${person.pictureUrl}" .name="${person.displayName}"></vaadin-avatar>
|
||||||
|
<span> ${person.displayName} </span>
|
||||||
|
</vaadin-horizontal-layout>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
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
|
||||||
|
} }
|
||||||
|
customStyle=${"width: 90%; max-width: 900px; height: 90%"}
|
||||||
|
style=${(this.isOpenLeaveModal) ? "display: block" : "display: none"}>
|
||||||
|
<div style="width: 100%;height: 100%;display: flex; flex-direction: column;background:var(--mdc-theme-surface)">
|
||||||
|
<div style="height: 50px;display: flex; flex:0">
|
||||||
|
<vaadin-tabs id="tabs" selected="${this.currentTab}" @selected-changed="${this._tabChanged}" style="width: 100%">
|
||||||
|
|
||||||
|
<vaadin-tab>Groups</vaadin-tab>
|
||||||
|
<vaadin-tab>Group Join Requests</vaadin-tab>
|
||||||
|
<vaadin-tab>Invites</vaadin-tab>
|
||||||
|
<vaadin-tab>Blocked Users</vaadin-tab>
|
||||||
|
</vaadin-tabs>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style="width: 100%;display: flex; flex-direction: column; flex-grow: 1; overflow:auto;background:var(--mdc-theme-surface)">
|
||||||
|
|
||||||
|
${this.currentTab === 0 ? html`
|
||||||
|
<div>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Groups tab -->
|
||||||
|
<!-- Search groups and be able to join -->
|
||||||
|
<p>Search groups</p>
|
||||||
|
<!-- Click group and it goes to that group and open right panel and settings -->
|
||||||
|
<p>Current groups as owner</p>
|
||||||
|
<p>Current groups as member</p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div style="width: 100%;height: 50;display: flex; flex: 0">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</wrapper-modal >
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('chat-groups-management', ChatGroupsManagement);
|
@ -21,7 +21,9 @@ class ChatHead extends LitElement {
|
|||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return css`
|
||||||
li {
|
li {
|
||||||
padding: 10px 2px 20px 5px;
|
|
||||||
|
width: 100%;
|
||||||
|
padding: 7px 5px 7px 5px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@ class ChatLeaveGroup extends LitElement {
|
|||||||
error: {type: Boolean},
|
error: {type: Boolean},
|
||||||
message: {type: String},
|
message: {type: String},
|
||||||
chatHeads: {type: Array},
|
chatHeads: {type: Array},
|
||||||
setActiveChatHeadUrl: {attribute: false}
|
setActiveChatHeadUrl: {attribute: false},
|
||||||
|
selectedAddress: {attribute: Object}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,7 +29,7 @@ class ChatLeaveGroup extends LitElement {
|
|||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.isOpenLeaveModal = false
|
this.isOpenLeaveModal = false
|
||||||
this.leaveGroupObj = {}
|
this.leaveGroupObj = {}
|
||||||
this.leaveFee = 0.001
|
this.fee = null
|
||||||
this.error = false
|
this.error = false
|
||||||
this.message = ''
|
this.message = ''
|
||||||
this.chatHeads = []
|
this.chatHeads = []
|
||||||
@ -59,7 +60,24 @@ class ChatLeaveGroup extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async unitFee() {
|
||||||
|
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=LEAVE_GROUP`
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
timeIsoString(timestamp) {
|
timeIsoString(timestamp) {
|
||||||
@ -108,8 +126,11 @@ class ChatLeaveGroup extends LitElement {
|
|||||||
async _leaveGroup(groupId, groupName) {
|
async _leaveGroup(groupId, groupName) {
|
||||||
// Reset Default Settings...
|
// Reset Default Settings...
|
||||||
this.resetDefaultSettings()
|
this.resetDefaultSettings()
|
||||||
const leaveFeeInput = this.leaveFee
|
|
||||||
|
const leaveFeeInput = await this.unitFee()
|
||||||
|
if(!leaveFeeInput){
|
||||||
|
throw Error()
|
||||||
|
}
|
||||||
this.isLoading = true
|
this.isLoading = true
|
||||||
|
|
||||||
// Get Last Ref
|
// Get Last Ref
|
||||||
|
@ -3,6 +3,8 @@ import { render } from 'lit/html.js';
|
|||||||
import {animate} from '@lit-labs/motion';
|
import {animate} from '@lit-labs/motion';
|
||||||
import { Epml } from '../../../epml.js';
|
import { Epml } from '../../../epml.js';
|
||||||
import { use, get, translate, registerTranslateConfig } from 'lit-translate';
|
import { use, get, translate, registerTranslateConfig } from 'lit-translate';
|
||||||
|
import { chatStyles } from './ChatScroller-css.js'
|
||||||
|
|
||||||
// import localForage from "localforage";
|
// import localForage from "localforage";
|
||||||
registerTranslateConfig({
|
registerTranslateConfig({
|
||||||
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
@ -20,6 +22,8 @@ import './WrapperModal';
|
|||||||
import './ChatSelect.js'
|
import './ChatSelect.js'
|
||||||
import './ChatSideNavHeads.js'
|
import './ChatSideNavHeads.js'
|
||||||
import './ChatLeaveGroup.js'
|
import './ChatLeaveGroup.js'
|
||||||
|
import './ChatGroupSettings.js'
|
||||||
|
import './ChatRightPanel.js'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
||||||
import '@material/mwc-button';
|
import '@material/mwc-button';
|
||||||
import '@material/mwc-dialog';
|
import '@material/mwc-dialog';
|
||||||
@ -615,29 +619,35 @@ class ChatPage extends LitElement {
|
|||||||
this.groupMembers = []
|
this.groupMembers = []
|
||||||
this.shifted = false
|
this.shifted = false
|
||||||
this.groupInfo = {}
|
this.groupInfo = {}
|
||||||
|
this.pageNumber = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggle() {
|
_toggle(value) {
|
||||||
this.shifted = !this.shifted;
|
console.log('toggel', value, this.shifted)
|
||||||
|
this.shifted = value === (false || true) ? value : !this.shifted;
|
||||||
|
this.requestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log('this.chatHeads', this.chatHeads)
|
console.log('this._chatId', this._chatId)
|
||||||
return html`
|
return html`
|
||||||
<div class="main-container">
|
<div class="main-container">
|
||||||
<div class="chat-container">
|
<div class="chat-container">
|
||||||
|
${(!this.isReceipient && +this._chatId !== 0) ? html`
|
||||||
<div style="display:flex; height:40px; padding:3px; margin:0px;background-color: var(--chat-bubble-bg); box-sizing: border-box; align-items: center;justify-content: space-between">
|
<div style="display:flex; height:40px; padding:3px; margin:0px;background-color: var(--chat-bubble-bg); box-sizing: border-box; align-items: center;justify-content: space-between">
|
||||||
<div>
|
<div @click=${this._toggle} style="height: 100%;display: flex;align-items: center;flex-grow: 1;cursor: pointer;cursor:pointer;user-select:none">
|
||||||
<p style="color: var(--black);margin:0px;padding:0px">Name</p>
|
<p style="color: var(--black);margin:0px;padding:0px">${this.groupInfo && this.groupInfo.groupName}</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;height:100%;align-items:center">
|
<div style="display:flex;height:100%;align-items:center">
|
||||||
<vaadin-icon class="top-bar-icon" @click=${this._toggle} style="margin: 0px 10px" icon="vaadin:info" slot="icon"></vaadin-icon>
|
<vaadin-icon class="top-bar-icon" @click=${this._toggle} style="margin: 0px 10px" icon="vaadin:info" slot="icon"></vaadin-icon>
|
||||||
<vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:cog" slot="icon"></vaadin-icon>
|
<chat-group-settings .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-group-settings>
|
||||||
<vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:search" slot="icon"></vaadin-icon>
|
<!-- <vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:search" slot="icon"></vaadin-icon> -->
|
||||||
<!-- <vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:exit" slot="icon"></vaadin-icon> -->
|
<!-- <vaadin-icon class="top-bar-icon" style="margin: 0px 20px" icon="vaadin:exit" slot="icon"></vaadin-icon> -->
|
||||||
<chat-leave-group .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-leave-group>
|
<chat-leave-group .chatHeads=${this.chatHeads} .selectedAddress=${this.selectedAddress} .leaveGroupObj=${this.groupInfo} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}></chat-leave-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
` : html`<div></div>`}
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
${this.isLoadingMessages ?
|
${this.isLoadingMessages ?
|
||||||
html`
|
html`
|
||||||
@ -829,36 +839,44 @@ class ChatPage extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</wrapper-modal>
|
</wrapper-modal>
|
||||||
</div>
|
</div>
|
||||||
<div class="chat-right-panel ${this.shifted ? "movedin" : "movedout"}" ${animate()}>
|
<div class="chat-right-panel ${this.shifted ? "movedin" : "movedout"}" ${animate()}>
|
||||||
<p>Exit Icon</p>
|
<chat-right-panel .getMoreMembers=${(val)=> this.getMoreMembers(val)} .toggle=${(val)=> this._toggle(val)} .selectedAddress=${this.selectedAddress} .groupMembers=${this.groupMembers} .groupAdmin=${this.groupAdmin} .leaveGroupObj=${this.groupInfo}></chat-right-panel>
|
||||||
<span>Group Avatar</span> <p>Group Name</p>
|
|
||||||
<p>Group owner</p>
|
|
||||||
<p>100 Members</p>
|
|
||||||
<p>Description</p>
|
|
||||||
<p>date created</p>
|
|
||||||
<p>private / public</p>
|
|
||||||
<p>approvalThreshold</p>
|
|
||||||
<p>"minimumBlockDelay": 0, "maximumBlockDelay": 0</p>
|
|
||||||
<p class="chat-right-panel-label">Admins</p>
|
|
||||||
${this.groupAdmin.map((item)=> {
|
|
||||||
return html`<chat-side-nav-heads activeChatHeadUrl="" setActiveChatHeadUrl=${(val)=> {
|
|
||||||
|
|
||||||
}} chatInfo=${JSON.stringify(item)}></chat-side-nav-heads>`
|
|
||||||
})}
|
|
||||||
|
|
||||||
<p class="chat-right-panel-label">Members</p>
|
|
||||||
${this.groupAdmin.map((item)=> {
|
|
||||||
return html`<chat-side-nav-heads activeChatHeadUrl="" setActiveChatHeadUrl=${(val)=> {
|
|
||||||
|
|
||||||
}} chatInfo=${JSON.stringify(item)}></chat-side-nav-heads>`
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getMoreMembers(groupId){
|
||||||
|
console.log('getMoreMembers', groupId)
|
||||||
|
try {
|
||||||
|
const getMembers = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
url: `/groups/members/${groupId}?onlyAdmins=false&limit=20&offset=${this.pageNumber * 20}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
const getMembersWithName = (getMembers.members || []).map(async (member) => {
|
||||||
|
let memberItem = member
|
||||||
|
try {
|
||||||
|
const name = await this.getName(member.member)
|
||||||
|
memberItem = {
|
||||||
|
address: member.member,
|
||||||
|
name: name ? name : undefined
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return memberItem
|
||||||
|
})
|
||||||
|
const membersWithName = await Promise.all(getMembersWithName)
|
||||||
|
this.groupMembers = membersWithName
|
||||||
|
this.pageNumber = this.pageNumber + 1
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setForwardProperties(forwardedMessage){
|
setForwardProperties(forwardedMessage){
|
||||||
this.openForwardOpen = true
|
this.openForwardOpen = true
|
||||||
this.forwardedMessage = forwardedMessage
|
this.forwardedMessage = forwardedMessage
|
||||||
@ -957,6 +975,7 @@ class ChatPage extends LitElement {
|
|||||||
this.webSocket.close()
|
this.webSocket.close()
|
||||||
this.webSocket= ''
|
this.webSocket= ''
|
||||||
}
|
}
|
||||||
|
this.pageNumber = 1
|
||||||
const getAddressPublicKey = () => {
|
const getAddressPublicKey = () => {
|
||||||
|
|
||||||
parentEpml.request('apiCall', {
|
parentEpml.request('apiCall', {
|
||||||
@ -1006,7 +1025,7 @@ class ChatPage extends LitElement {
|
|||||||
try {
|
try {
|
||||||
const getMembers = await parentEpml.request("apiCall", {
|
const getMembers = await parentEpml.request("apiCall", {
|
||||||
type: "api",
|
type: "api",
|
||||||
url: `/groups/members/${groupId}?onlyAdmins=false&limit=20`,
|
url: `/groups/members/${groupId}?onlyAdmins=false&limit=20&offset=0`,
|
||||||
});
|
});
|
||||||
const getMembersAdmins = await parentEpml.request("apiCall", {
|
const getMembersAdmins = await parentEpml.request("apiCall", {
|
||||||
type: "api",
|
type: "api",
|
||||||
@ -1404,6 +1423,7 @@ async getName (recipient) {
|
|||||||
let decodedMessageObj = {};
|
let decodedMessageObj = {};
|
||||||
|
|
||||||
if (isReceipientVar === true) {
|
if (isReceipientVar === true) {
|
||||||
|
console.log('encoded', encodedMessageObj.isEncrypted, _publicKeyVar.hasPubKey,encodedMessageObj.data)
|
||||||
// direct chat
|
// direct chat
|
||||||
if (encodedMessageObj.isEncrypted === true && _publicKeyVar.hasPubKey === true && encodedMessageObj.data) {
|
if (encodedMessageObj.isEncrypted === true && _publicKeyVar.hasPubKey === true && encodedMessageObj.data) {
|
||||||
let decodedMessage = window.parent.decryptChatMessage(encodedMessageObj.data, window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey, _publicKeyVar.key, encodedMessageObj.reference);
|
let decodedMessage = window.parent.decryptChatMessage(encodedMessageObj.data, window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey, _publicKeyVar.key, encodedMessageObj.reference);
|
||||||
|
486
qortal-ui-plugins/plugins/core/components/ChatRightPanel.js
Normal file
486
qortal-ui-plugins/plugins/core/components/ChatRightPanel.js
Normal file
@ -0,0 +1,486 @@
|
|||||||
|
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 ChatRightPanel extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isLoading: { type: Boolean },
|
||||||
|
isOpenLeaveModal: { type: Boolean },
|
||||||
|
leaveGroupObj: { type: Object },
|
||||||
|
error: { type: Boolean },
|
||||||
|
message: { type: String },
|
||||||
|
chatHeads: { type: Array },
|
||||||
|
groupAdmin: { attribute: false },
|
||||||
|
groupMembers: { attribute: false },
|
||||||
|
selectedHead: { type: Object },
|
||||||
|
toggle: {attribute: false},
|
||||||
|
getMoreMembers:{attribute: false}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.isLoading = false
|
||||||
|
this.isOpenLeaveModal = false
|
||||||
|
this.leaveGroupObj = {}
|
||||||
|
this.leaveFee = 0.001
|
||||||
|
this.error = false
|
||||||
|
this.message = ""
|
||||||
|
this.chatHeads = []
|
||||||
|
this.groupAdmin = []
|
||||||
|
this.groupMembers = []
|
||||||
|
this.observerHandler = this.observerHandler.bind(this)
|
||||||
|
this.viewElement = ''
|
||||||
|
this.downObserverElement = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
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: 15px;
|
||||||
|
padding: 0px 5px;
|
||||||
|
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%;
|
||||||
|
}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.viewElement = this.shadowRoot.getElementById('viewElement');
|
||||||
|
this.downObserverElement = this.shadowRoot.getElementById('downObserver');
|
||||||
|
this.elementObserver();
|
||||||
|
}
|
||||||
|
|
||||||
|
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.isOpenLeaveModal = false
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
stop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interval = setInterval(getAnswer, 5000)
|
||||||
|
}
|
||||||
|
|
||||||
|
async unitFee(txType) {
|
||||||
|
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||||
|
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
const url = `${nodeUrl}/transactions/unitfee?txType=${txType}`
|
||||||
|
let fee = null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await fetch(url)
|
||||||
|
const data = await res.json()
|
||||||
|
fee = (Number(data) / 1e8).toFixed(3)
|
||||||
|
} catch (error) {
|
||||||
|
fee = null
|
||||||
|
}
|
||||||
|
|
||||||
|
return fee
|
||||||
|
}
|
||||||
|
|
||||||
|
async getLastRef() {
|
||||||
|
let myRef = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
url: `/addresses/lastreference/${this.selectedAddress.address}`,
|
||||||
|
})
|
||||||
|
return myRef
|
||||||
|
}
|
||||||
|
|
||||||
|
getTxnRequestResponse(txnResponse, reference) {
|
||||||
|
if (txnResponse === true) {
|
||||||
|
this.message = this.renderErr9Text()
|
||||||
|
this.error = false
|
||||||
|
this.confirmRelationship(reference)
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
this.message = ""
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async convertBytesForSigning(transactionBytesBase58) {
|
||||||
|
let convertedBytes = await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
method: "POST",
|
||||||
|
url: `/transactions/convert`,
|
||||||
|
body: `${transactionBytesBase58}`,
|
||||||
|
})
|
||||||
|
return convertedBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
async signTx(body){
|
||||||
|
return await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
method: "POST",
|
||||||
|
url: `/transactions/sign`,
|
||||||
|
body: body,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async process(body){
|
||||||
|
return await parentEpml.request("apiCall", {
|
||||||
|
type: "api",
|
||||||
|
method: "POST",
|
||||||
|
url: `/transactions/process`,
|
||||||
|
body: body,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
async _addAdmin(groupId) {
|
||||||
|
this.resetDefaultSettings()
|
||||||
|
|
||||||
|
const leaveFeeInput = await this.unitFee('ADD_GROUP_ADMIN')
|
||||||
|
if(!leaveFeeInput){
|
||||||
|
throw Error()
|
||||||
|
}
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
// Get Last Ref
|
||||||
|
const getLastRef = async () => {
|
||||||
|
let myRef = await parentEpml.request('apiCall', {
|
||||||
|
type: 'api',
|
||||||
|
url: `/addresses/lastreference/${this.selectedAddress.address}`
|
||||||
|
})
|
||||||
|
return myRef
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateReceiver = async () => {
|
||||||
|
let lastRef = await getLastRef();
|
||||||
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
getTxnRequestResponse(myTransaction)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Transaction Request
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
let groupdialog3 = get("transactions.groupdialog3")
|
||||||
|
let groupdialog4 = get("transactions.groupdialog4")
|
||||||
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
|
type: 24,
|
||||||
|
nonce: this.selectedAddress.nonce,
|
||||||
|
params: {
|
||||||
|
_groupId: groupId,
|
||||||
|
fee: leaveFeeInput,
|
||||||
|
member: this.selectedHead.address,
|
||||||
|
lastReference: lastRef
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return myTxnrequest
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
|
|
||||||
|
if (txnResponse.success === false && txnResponse.message) {
|
||||||
|
this.error = true
|
||||||
|
this.message = txnResponse.message
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
||||||
|
this.message = this.renderErr9Text()
|
||||||
|
this.error = false
|
||||||
|
this.confirmRelationship()
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
this.message = txnResponse.data.message
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
async _removeAdmin(groupId) {
|
||||||
|
this.resetDefaultSettings()
|
||||||
|
|
||||||
|
const leaveFeeInput = await this.unitFee('REMOVE_GROUP_ADMIN')
|
||||||
|
if(!leaveFeeInput){
|
||||||
|
throw Error()
|
||||||
|
}
|
||||||
|
this.isLoading = true
|
||||||
|
|
||||||
|
// Get Last Ref
|
||||||
|
const getLastRef = async () => {
|
||||||
|
let myRef = await parentEpml.request('apiCall', {
|
||||||
|
type: 'api',
|
||||||
|
url: `/addresses/lastreference/${this.selectedAddress.address}`
|
||||||
|
})
|
||||||
|
return myRef
|
||||||
|
};
|
||||||
|
|
||||||
|
const validateReceiver = async () => {
|
||||||
|
let lastRef = await getLastRef();
|
||||||
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
getTxnRequestResponse(myTransaction)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make Transaction Request
|
||||||
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
|
let groupdialog3 = get("transactions.groupdialog3")
|
||||||
|
let groupdialog4 = get("transactions.groupdialog4")
|
||||||
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
|
type: 25,
|
||||||
|
nonce: this.selectedAddress.nonce,
|
||||||
|
params: {
|
||||||
|
_groupId: groupId,
|
||||||
|
fee: leaveFeeInput,
|
||||||
|
member: this.selectedHead.address,
|
||||||
|
lastReference: lastRef
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return myTxnrequest
|
||||||
|
}
|
||||||
|
|
||||||
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
|
|
||||||
|
if (txnResponse.success === false && txnResponse.message) {
|
||||||
|
this.error = true
|
||||||
|
this.message = txnResponse.message
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
} else if (txnResponse.success === true && !txnResponse.data.error) {
|
||||||
|
this.message = this.renderErr9Text()
|
||||||
|
this.error = false
|
||||||
|
this.confirmRelationship()
|
||||||
|
} else {
|
||||||
|
this.error = true
|
||||||
|
this.message = txnResponse.data.message
|
||||||
|
throw new Error(txnResponse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
validateReceiver()
|
||||||
|
}
|
||||||
|
|
||||||
|
elementObserver() {
|
||||||
|
const options = {
|
||||||
|
root: this.viewElement,
|
||||||
|
rootMargin: '0px',
|
||||||
|
threshold: 1
|
||||||
|
}
|
||||||
|
// identify an element to observe
|
||||||
|
const elementToObserve = this.downObserverElement;
|
||||||
|
// passing it a callback function
|
||||||
|
const observer = new IntersectionObserver(this.observerHandler, options);
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
console.log('this.groupMembers', this.groupMembers)
|
||||||
|
const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner)
|
||||||
|
return html`
|
||||||
|
<div class="container">
|
||||||
|
<div class="close-row" style="margin-top: 15px">
|
||||||
|
<vaadin-icon class="top-bar-icon" @click=${()=> this.toggle(false)} style="margin: 0px 10px" icon="vaadin:close" slot="icon"></vaadin-icon>
|
||||||
|
</div>
|
||||||
|
<div id="viewElement" class="container-body">
|
||||||
|
<p style="font-size: 20px;">${this.leaveGroupObj && this.leaveGroupObj.groupName}</p>
|
||||||
|
<p style="font-size: 14px;margin-top: 5px">${this.leaveGroupObj && this.leaveGroupObj.description}</p>
|
||||||
|
<p style="font-size: 14px;margin-top: 10px">Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}</p>
|
||||||
|
|
||||||
|
<p style="font-size: 14px;margin-top: 5px">Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}</p>
|
||||||
|
<br />
|
||||||
|
<p class="chat-right-panel-label">Group Owner</p>
|
||||||
|
${owner.map((item) => {
|
||||||
|
return html`<chat-side-nav-heads
|
||||||
|
activeChatHeadUrl=""
|
||||||
|
.setActiveChatHeadUrl=${(val) => {}}
|
||||||
|
chatInfo=${JSON.stringify(item)}
|
||||||
|
></chat-side-nav-heads>`
|
||||||
|
})}
|
||||||
|
<p class="chat-right-panel-label">Admins</p>
|
||||||
|
${this.groupAdmin.map((item) => {
|
||||||
|
return html`<chat-side-nav-heads
|
||||||
|
activeChatHeadUrl=""
|
||||||
|
.setActiveChatHeadUrl=${(val) => {}}
|
||||||
|
chatInfo=${JSON.stringify(item)}
|
||||||
|
></chat-side-nav-heads>`
|
||||||
|
})}
|
||||||
|
<p class="chat-right-panel-label">Members</p>
|
||||||
|
${this.groupMembers.map((item) => {
|
||||||
|
return html`<chat-side-nav-heads
|
||||||
|
activeChatHeadUrl=""
|
||||||
|
.setActiveChatHeadUrl=${(val) => {
|
||||||
|
console.log({ val })
|
||||||
|
this.selectedHead = val
|
||||||
|
this.isOpenLeaveModal = true
|
||||||
|
}}
|
||||||
|
chatInfo=${JSON.stringify(item)}
|
||||||
|
></chat-side-nav-heads>`
|
||||||
|
})}
|
||||||
|
<div id='downObserver'></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<button @click=${() =>
|
||||||
|
this._addAdmin(
|
||||||
|
this.leaveGroupObj.groupId
|
||||||
|
)}>Promote to Admin</button>
|
||||||
|
<button @click=${() =>
|
||||||
|
this._removeAdmin(
|
||||||
|
this.leaveGroupObj.groupId
|
||||||
|
)}>Remove as Admin</button>
|
||||||
|
<div style="text-align:right; height:36px;">
|
||||||
|
<span ?hidden="${!this.isLoading}">
|
||||||
|
<!-- loading message -->
|
||||||
|
${translate("grouppage.gchange36")}
|
||||||
|
<paper-spinner-lite
|
||||||
|
style="margin-top:12px;"
|
||||||
|
?active="${this.isLoading}"
|
||||||
|
alt="Leaving"
|
||||||
|
>
|
||||||
|
</paper-spinner-lite>
|
||||||
|
</span>
|
||||||
|
<span ?hidden=${this.message === ""} style="${
|
||||||
|
this.error ? "color:red;" : ""
|
||||||
|
}">
|
||||||
|
${this.message}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<button
|
||||||
|
@click=${() => {
|
||||||
|
this.isOpenLeaveModal = false
|
||||||
|
}}
|
||||||
|
class="modal-button"
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
|
||||||
|
>
|
||||||
|
${translate("general.close")}
|
||||||
|
</button>
|
||||||
|
</wrapper-modal >
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define("chat-right-panel", ChatRightPanel)
|
@ -662,6 +662,7 @@ class ChatMenu extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
console.log(this.messages, 'this.messages')
|
||||||
return html`
|
return html`
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div
|
<div
|
||||||
|
@ -124,7 +124,7 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<li @click=${() => this.getUrl(this.chatInfo.url)} class="clearfix">
|
<li @click=${() => this.getUrl(this.chatInfo)} class="clearfix">
|
||||||
${this.isImageLoaded ? html`${avatarImg}` : html`` }
|
${this.isImageLoaded ? html`${avatarImg}` : html`` }
|
||||||
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? html`<mwc-icon class="img-icon">account_circle</mwc-icon>` : html`` }
|
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? 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.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>`: ''}
|
||||||
|
@ -10,6 +10,7 @@ export const wrapperModalStyles = css`
|
|||||||
background: rgb(186 186 186 / 26%);
|
background: rgb(186 186 186 / 26%);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
animation: backdrop_blur cubic-bezier(0.22, 1, 0.36, 1) 1s forwards;
|
animation: backdrop_blur cubic-bezier(0.22, 1, 0.36, 1) 1s forwards;
|
||||||
|
z-index: 50
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal-body {
|
.modal-body {
|
||||||
@ -29,6 +30,7 @@ export const wrapperModalStyles = css`
|
|||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
animation: 1s cubic-bezier(0.22, 1, 0.36, 1) 0s 1 normal forwards running modal_transition;
|
animation: 1s cubic-bezier(0.22, 1, 0.36, 1) 0s 1 normal forwards running modal_transition;
|
||||||
max-height: 80%;
|
max-height: 80%;
|
||||||
|
z-index: 51
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes backdrop_blur {
|
@keyframes backdrop_blur {
|
||||||
|
@ -6,6 +6,7 @@ export class WrapperModal extends LitElement {
|
|||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
removeImage: { type: Function },
|
removeImage: { type: Function },
|
||||||
|
customStyle: {type: String}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,7 +18,7 @@ export class WrapperModal extends LitElement {
|
|||||||
<div class="backdrop" @click=${() => {
|
<div class="backdrop" @click=${() => {
|
||||||
this.removeImage()
|
this.removeImage()
|
||||||
}}></div>
|
}}></div>
|
||||||
<div class="modal-body">
|
<div class="modal-body" style=${this.customStyle ? this.customStyle : ""}>
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -523,6 +523,7 @@ class GroupManagement extends LitElement {
|
|||||||
setTimeout(getOpen_JoinedGroups, 1)
|
setTimeout(getOpen_JoinedGroups, 1)
|
||||||
configLoaded = true
|
configLoaded = true
|
||||||
}
|
}
|
||||||
|
console.log('parse', JSON.parse(c))
|
||||||
this.config = JSON.parse(c)
|
this.config = JSON.parse(c)
|
||||||
})
|
})
|
||||||
parentEpml.subscribe('copy_menu_switch', async value => {
|
parentEpml.subscribe('copy_menu_switch', async value => {
|
||||||
|
@ -10,6 +10,7 @@ registerTranslateConfig({
|
|||||||
import '../../components/ChatWelcomePage.js'
|
import '../../components/ChatWelcomePage.js'
|
||||||
import '../../components/ChatHead.js'
|
import '../../components/ChatHead.js'
|
||||||
import '../../components/ChatPage.js'
|
import '../../components/ChatPage.js'
|
||||||
|
import '../../components/ChatGroupsManagement.js'
|
||||||
import snackbar from '../../components/snackbar.js'
|
import snackbar from '../../components/snackbar.js'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
@ -342,6 +343,7 @@ class Chat extends LitElement {
|
|||||||
<div class="people-list" id="people-list">
|
<div class="people-list" id="people-list">
|
||||||
<div class="search">
|
<div class="search">
|
||||||
<div class="create-chat" @click=${() => this.shadowRoot.querySelector('#startChatDialog').show()}>${translate("chatpage.cchange1")}</div>
|
<div class="create-chat" @click=${() => this.shadowRoot.querySelector('#startChatDialog').show()}>${translate("chatpage.cchange1")}</div>
|
||||||
|
<chat-groups-management></chat-groups-management>
|
||||||
</div>
|
</div>
|
||||||
<ul class="list">
|
<ul class="list">
|
||||||
${this.isEmptyArray(this.chatHeads) ? this.renderLoadingText() : this.renderChatHead(this.chatHeads)}
|
${this.isEmptyArray(this.chatHeads) ? this.renderLoadingText() : this.renderChatHead(this.chatHeads)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user