mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-05-06 17:57:51 +00:00
commit
516804cf70
@ -7,24 +7,16 @@
|
|||||||
"version": 1,
|
"version": 1,
|
||||||
"updated": 1696646223261,
|
"updated": 1696646223261,
|
||||||
"title": "Q-Blog Post creations",
|
"title": "Q-Blog Post creations",
|
||||||
"description": "blablabla",
|
"description": "Get your friends Q-Blog posts on your feed",
|
||||||
"search": {
|
"search": {
|
||||||
"query": "-post-",
|
"query": "-post-",
|
||||||
"identifier": "q-blog-",
|
"identifier": "q-blog-",
|
||||||
"service": "BLOG_POST",
|
"service": "BLOG_POST",
|
||||||
"exactmatchnames": true
|
"exactmatchnames": true
|
||||||
},
|
},
|
||||||
"click": "qortal://APP/Q-Blog/$${resource.name}$$/$${customParams.blogId}$$/$${customParams.shortIdentifier}$$",
|
"click": "qortal://APP/Q-Blog/$${resource.name}$$/blog/$${resource.identifier}$$",
|
||||||
"display": {
|
"display": {
|
||||||
"title": "$${rawdata.title}$$"
|
"title": "$${rawdata.title}$$"
|
||||||
},
|
|
||||||
"customParams": {
|
|
||||||
"blogId": "**methods.getBlogId(resource)**",
|
|
||||||
"shortIdentifier": "**methods.getShortId(resource)**"
|
|
||||||
},
|
|
||||||
"methods": {
|
|
||||||
"getShortId": "return resource.identifier.split('-post-')[1];",
|
|
||||||
"getBlogId": "const arr = resource.identifier.split('-post-'); const id = arr[0]; return id.startsWith('q-blog-') ? id.substring(7) : id;"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -729,7 +729,10 @@
|
|||||||
"bchange46": "Do you give this application permission to save the following file",
|
"bchange46": "Do you give this application permission to save the following file",
|
||||||
"bchange47": "Instant publish - requires",
|
"bchange47": "Instant publish - requires",
|
||||||
"bchange48": "Do you give this application permission to send you notifications",
|
"bchange48": "Do you give this application permission to send you notifications",
|
||||||
"bchange49": "Do you give this application permission to get your wallet information?"
|
"bchange49": "Do you grant this application permission to access the following private information from your profile?",
|
||||||
|
"bchange50": "This app has requested a change to your public profile. Property: ",
|
||||||
|
"bchange51": "To submit the changes don't forget to click on 'Update profile'",
|
||||||
|
"bchange52": "Do you give this application permission to get your wallet information?"
|
||||||
},
|
},
|
||||||
"datapage": {
|
"datapage": {
|
||||||
"dchange1": "Data Management",
|
"dchange1": "Data Management",
|
||||||
@ -1214,5 +1217,28 @@
|
|||||||
"saving2": "Nothing to save",
|
"saving2": "Nothing to save",
|
||||||
"saving3": "Save unsaved changes",
|
"saving3": "Save unsaved changes",
|
||||||
"saving4": "Undo changes"
|
"saving4": "Undo changes"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"profile1": "You do not have a name",
|
||||||
|
"profile2": "Go to name registration",
|
||||||
|
"profile3": "Update profile",
|
||||||
|
"profile4": "Tagline",
|
||||||
|
"profile5": "Bio",
|
||||||
|
"profile6": "Wallet Addresses",
|
||||||
|
"profile7": "Fill from UI",
|
||||||
|
"profile8": "Add custom property",
|
||||||
|
"profile9": "Property name",
|
||||||
|
"profile10": "Fields",
|
||||||
|
"profile11": "Add new field",
|
||||||
|
"profile12": "Field name",
|
||||||
|
"profile13": "Fill out",
|
||||||
|
"profile14": "Activity",
|
||||||
|
"profile15": "No value",
|
||||||
|
"profile16": "This name has no profile",
|
||||||
|
"profile17": "Unable to fetch profile",
|
||||||
|
"profile18": "Open profile",
|
||||||
|
"profile19": "Cannot fetch profile",
|
||||||
|
"profile20": "Register name",
|
||||||
|
"profile21": "Insert address from UI"
|
||||||
}
|
}
|
||||||
}
|
}
|
5
core/src/components/WebWorkerFile.js
Normal file
5
core/src/components/WebWorkerFile.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import WebWorker from 'web-worker:./computePowWorkerFile.js';
|
||||||
|
|
||||||
|
// You can add any initialization or configuration for the Web Worker here
|
||||||
|
|
||||||
|
export default WebWorker;
|
@ -1,12 +1,12 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { css, html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store.js'
|
||||||
import {Epml} from '../epml.js'
|
import { Epml } from '../epml.js'
|
||||||
import {addTradeBotRoutes} from '../tradebot/addTradeBotRoutes.js'
|
import { addTradeBotRoutes } from '../tradebot/addTradeBotRoutes.js'
|
||||||
import {get, translate} from 'lit-translate'
|
import { get, translate } from 'lit-translate'
|
||||||
import localForage from 'localforage'
|
import localForage from 'localforage'
|
||||||
import {decryptData, encryptData} from '../lockScreen.js'
|
import { decryptData, encryptData } from '../lockScreen.js'
|
||||||
import {setChatLastSeen} from '../redux/app/app-actions.js'
|
import { setChatLastSeen } from '../redux/app/app-actions.js'
|
||||||
import isElectron from 'is-electron'
|
import isElectron from 'is-electron'
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
@ -41,6 +41,7 @@ import './notification-view/notification-bell-general.js'
|
|||||||
import './friends-view/friends-side-panel-parent.js'
|
import './friends-view/friends-side-panel-parent.js'
|
||||||
import './friends-view/save-settings-qdn.js'
|
import './friends-view/save-settings-qdn.js'
|
||||||
import './friends-view/core-sync-status.js'
|
import './friends-view/core-sync-status.js'
|
||||||
|
import './friends-view/profile.js'
|
||||||
import './controllers/coin-balances-controller.js'
|
import './controllers/coin-balances-controller.js'
|
||||||
|
|
||||||
const chatLastSeen = localForage.createInstance({
|
const chatLastSeen = localForage.createInstance({
|
||||||
@ -564,7 +565,8 @@ class AppView extends connect(store)(LitElement) {
|
|||||||
<img src="${this.config.coin.logo}" style="height:32px; padding-left:12px;">
|
<img src="${this.config.coin.logo}" style="height:32px; padding-left:12px;">
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex; align-items: center; gap: 20px">
|
<div style="display:flex;align-items:center;gap:20px">
|
||||||
|
<profile-qdn></profile-qdn>
|
||||||
<friends-side-panel-parent></friends-side-panel-parent>
|
<friends-side-panel-parent></friends-side-panel-parent>
|
||||||
<notification-bell></notification-bell>
|
<notification-bell></notification-bell>
|
||||||
<notification-bell-general></notification-bell-general>
|
<notification-bell-general></notification-bell-general>
|
||||||
@ -705,11 +707,11 @@ class AppView extends connect(store)(LitElement) {
|
|||||||
var drawerTog = this.shadowRoot.getElementById("mb")
|
var drawerTog = this.shadowRoot.getElementById("mb")
|
||||||
var drawerOut = this.shadowRoot.getElementById("appsidebar")
|
var drawerOut = this.shadowRoot.getElementById("appsidebar")
|
||||||
|
|
||||||
drawerTog.addEventListener('mouseover', function() {
|
drawerTog.addEventListener('mouseover', function () {
|
||||||
drawerTog.click()
|
drawerTog.click()
|
||||||
})
|
})
|
||||||
|
|
||||||
drawerOut.addEventListener('mouseleave', function() {
|
drawerOut.addEventListener('mouseleave', function () {
|
||||||
drawerTog.click()
|
drawerTog.click()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
92
core/src/components/computePowWorkerFile.js
Normal file
92
core/src/components/computePowWorkerFile.js
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { Sha256 } from 'asmcrypto.js'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function sbrk(size, heap){
|
||||||
|
let brk = 512 * 1024 // stack top
|
||||||
|
let old = brk
|
||||||
|
brk += size
|
||||||
|
|
||||||
|
if (brk > heap.length)
|
||||||
|
throw new Error('heap exhausted')
|
||||||
|
|
||||||
|
return old
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
self.addEventListener('message', async e => {
|
||||||
|
const response = await computePow(e.data.convertedBytes, e.data.path)
|
||||||
|
postMessage(response)
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||||
|
const heap = new Uint8Array(memory.buffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const computePow = async (convertedBytes, path) => {
|
||||||
|
|
||||||
|
|
||||||
|
let response = null
|
||||||
|
|
||||||
|
await new Promise((resolve, reject)=> {
|
||||||
|
|
||||||
|
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
||||||
|
function (key) {
|
||||||
|
return convertedBytes[key]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
||||||
|
const convertedBytesHash = new Sha256()
|
||||||
|
.process(convertedBytesArray)
|
||||||
|
.finish().result
|
||||||
|
const hashPtr = sbrk(32, heap)
|
||||||
|
const hashAry = new Uint8Array(
|
||||||
|
memory.buffer,
|
||||||
|
hashPtr,
|
||||||
|
32
|
||||||
|
)
|
||||||
|
|
||||||
|
hashAry.set(convertedBytesHash)
|
||||||
|
const difficulty = 14
|
||||||
|
const workBufferLength = 8 * 1024 * 1024
|
||||||
|
const workBufferPtr = sbrk(
|
||||||
|
workBufferLength,
|
||||||
|
heap
|
||||||
|
)
|
||||||
|
|
||||||
|
const importObject = {
|
||||||
|
env: {
|
||||||
|
memory: memory
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadWebAssembly(filename, imports) {
|
||||||
|
return fetch(filename)
|
||||||
|
.then(response => response.arrayBuffer())
|
||||||
|
.then(buffer => WebAssembly.compile(buffer))
|
||||||
|
.then(module => {
|
||||||
|
return new WebAssembly.Instance(module, importObject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
loadWebAssembly(path)
|
||||||
|
.then(wasmModule => {
|
||||||
|
response = {
|
||||||
|
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
||||||
|
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
310
core/src/components/friends-view/avatar.js
Normal file
310
core/src/components/friends-view/avatar.js
Normal file
@ -0,0 +1,310 @@
|
|||||||
|
import { LitElement, html, css } from 'lit';
|
||||||
|
import { get, translate } from 'lit-translate';
|
||||||
|
import axios from 'axios';
|
||||||
|
import '@material/mwc-menu';
|
||||||
|
import '@material/mwc-list/mwc-list-item.js';
|
||||||
|
import { RequestQueueWithPromise } from '../../../../plugins/plugins/utils/queue';
|
||||||
|
import '../../../../plugins/plugins/core/components/TimeAgo';
|
||||||
|
import { connect } from 'pwa-helpers';
|
||||||
|
import { store } from '../../store';
|
||||||
|
import { setNewTab } from '../../redux/app/app-actions';
|
||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
|
||||||
|
const requestQueue = new RequestQueueWithPromise(3);
|
||||||
|
const requestQueueRawData = new RequestQueueWithPromise(3);
|
||||||
|
const requestQueueStatus = new RequestQueueWithPromise(3);
|
||||||
|
|
||||||
|
export class AvatarComponent extends connect(store)(LitElement) {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
resource: { type: Object },
|
||||||
|
isReady: { type: Boolean },
|
||||||
|
status: { type: Object },
|
||||||
|
name: { type: String },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
* {
|
||||||
|
--mdc-theme-text-primary-on-background: var(--black);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
:host {
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 30vh;
|
||||||
|
border-radius: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.smallLoading,
|
||||||
|
.smallLoading:after {
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 2px;
|
||||||
|
height: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.defaultSize {
|
||||||
|
width: 100%;
|
||||||
|
height: 160px;
|
||||||
|
}
|
||||||
|
.parent-feed-item {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
background-color: var(--chat-bubble-bg);
|
||||||
|
flex-grow: 0;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 12px 15px 4px 15px;
|
||||||
|
min-width: 150px;
|
||||||
|
width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.avatarApp {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 50%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.feed-item-name {
|
||||||
|
user-select: none;
|
||||||
|
color: #03a9f4;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-name {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
mwc-menu {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.resource = {
|
||||||
|
identifier: '',
|
||||||
|
name: '',
|
||||||
|
service: '',
|
||||||
|
};
|
||||||
|
this.status = {
|
||||||
|
status: '',
|
||||||
|
};
|
||||||
|
this.isReady = false;
|
||||||
|
this.nodeUrl = this.getNodeUrl();
|
||||||
|
this.myNode = this.getMyNode();
|
||||||
|
this.isFetching = false;
|
||||||
|
this.uid = new ShortUniqueId();
|
||||||
|
}
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode =
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.node
|
||||||
|
];
|
||||||
|
|
||||||
|
const nodeUrl =
|
||||||
|
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
||||||
|
return nodeUrl;
|
||||||
|
}
|
||||||
|
getMyNode() {
|
||||||
|
const myNode =
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.node
|
||||||
|
];
|
||||||
|
|
||||||
|
return myNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
getApiKey() {
|
||||||
|
const myNode =
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.node
|
||||||
|
];
|
||||||
|
let apiKey = myNode.apiKey;
|
||||||
|
return apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchResource() {
|
||||||
|
try {
|
||||||
|
if (this.isFetching) return;
|
||||||
|
this.isFetching = true;
|
||||||
|
await axios.get(
|
||||||
|
`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
);
|
||||||
|
this.isFetching = false;
|
||||||
|
} catch (error) {
|
||||||
|
this.isFetching = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchVideoUrl() {
|
||||||
|
this.fetchResource();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRawData() {
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`;
|
||||||
|
return await requestQueueRawData.enqueue(() => {
|
||||||
|
return axios.get(url);
|
||||||
|
});
|
||||||
|
// const response2 = await fetch(url, {
|
||||||
|
// method: 'GET',
|
||||||
|
// headers: {
|
||||||
|
// 'Content-Type': 'application/json'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
// const responseData2 = await response2.json()
|
||||||
|
// return responseData2
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplayWithPlaceholders(display, resource, rawdata) {
|
||||||
|
const pattern = /\$\$\{([a-zA-Z0-9_\.]+)\}\$\$/g;
|
||||||
|
|
||||||
|
for (const key in display) {
|
||||||
|
const value = display[key];
|
||||||
|
|
||||||
|
display[key] = value.replace(pattern, (match, p1) => {
|
||||||
|
if (p1.startsWith('rawdata.')) {
|
||||||
|
const dataKey = p1.split('.')[1];
|
||||||
|
if (rawdata[dataKey] === undefined) {
|
||||||
|
console.error('rawdata key not found:', dataKey);
|
||||||
|
}
|
||||||
|
return rawdata[dataKey] || match;
|
||||||
|
} else if (p1.startsWith('resource.')) {
|
||||||
|
const resourceKey = p1.split('.')[1];
|
||||||
|
if (resource[resourceKey] === undefined) {
|
||||||
|
console.error('resource key not found:', resourceKey);
|
||||||
|
}
|
||||||
|
return resource[resourceKey] || match;
|
||||||
|
}
|
||||||
|
return match;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchStatus() {
|
||||||
|
let isCalling = false;
|
||||||
|
let percentLoaded = 0;
|
||||||
|
let timer = 24;
|
||||||
|
const response = await requestQueueStatus.enqueue(() => {
|
||||||
|
return axios.get(
|
||||||
|
`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
if (response && response.data && response.data.status === 'READY') {
|
||||||
|
this.status = response.data;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const intervalId = setInterval(async () => {
|
||||||
|
if (isCalling) return;
|
||||||
|
isCalling = true;
|
||||||
|
|
||||||
|
const data = await requestQueue.enqueue(() => {
|
||||||
|
return axios.get(
|
||||||
|
`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const res = data.data;
|
||||||
|
|
||||||
|
isCalling = false;
|
||||||
|
if (res.localChunkCount) {
|
||||||
|
if (res.percentLoaded) {
|
||||||
|
if (
|
||||||
|
res.percentLoaded === percentLoaded &&
|
||||||
|
res.percentLoaded !== 100
|
||||||
|
) {
|
||||||
|
timer = timer - 5;
|
||||||
|
} else {
|
||||||
|
timer = 24;
|
||||||
|
}
|
||||||
|
if (timer < 0) {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
}
|
||||||
|
percentLoaded = res.percentLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.status = res;
|
||||||
|
if (this.status.status === 'DOWNLOADED') {
|
||||||
|
this.fetchResource();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if progress is 100% and clear interval if true
|
||||||
|
if (res.status === 'READY') {
|
||||||
|
clearInterval(intervalId);
|
||||||
|
this.status = res;
|
||||||
|
this.isReady = true;
|
||||||
|
}
|
||||||
|
}, 5000); // 1 second interval
|
||||||
|
}
|
||||||
|
|
||||||
|
async _fetchImage() {
|
||||||
|
try {
|
||||||
|
this.fetchVideoUrl();
|
||||||
|
this.fetchStatus();
|
||||||
|
} catch (error) {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this._fetchImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log('hello', this.name, this.resource, this.status);
|
||||||
|
return html`
|
||||||
|
<div>
|
||||||
|
${this.status.status !== 'READY'
|
||||||
|
? html`
|
||||||
|
<mwc-icon style="user-select:none;"
|
||||||
|
>account_circle</mwc-icon
|
||||||
|
>
|
||||||
|
`
|
||||||
|
: ''}
|
||||||
|
${this.status.status === 'READY'
|
||||||
|
? html`
|
||||||
|
<div
|
||||||
|
style="height: 24px;width: 24px;overflow: hidden;"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="${this
|
||||||
|
.nodeUrl}/arbitrary/THUMBNAIL/${this
|
||||||
|
.name}/qortal_avatar?async=true&apiKey=${this
|
||||||
|
.myNode.apiKey}"
|
||||||
|
style="width:100%; height:100%;border-radius:50%"
|
||||||
|
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ''}
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('avatar-component', AvatarComponent);
|
@ -134,7 +134,7 @@ class FriendsFeed extends connect(store)(LitElement) {
|
|||||||
this.endpointOffsets = Array(this.endpoints.length).fill(0);
|
this.endpointOffsets = Array(this.endpoints.length).fill(0);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const baseurl = `${this.nodeUrl}/arbitrary/resources/search?reverse=true&exactmatchnames=true&${names}`
|
const baseurl = `${this.nodeUrl}/arbitrary/resources/search?reverse=true&mode=ALL&exactmatchnames=true&${names}`
|
||||||
let formEndpoints = []
|
let formEndpoints = []
|
||||||
schemas.forEach((schema)=> {
|
schemas.forEach((schema)=> {
|
||||||
const feedData = schema.feed[0]
|
const feedData = schema.feed[0]
|
||||||
@ -350,7 +350,7 @@ this.getFeedOnInterval()
|
|||||||
|
|
||||||
// Merge new data with old data immutably
|
// Merge new data with old data immutably
|
||||||
this.feed = [...enhancedNewData, ...this.feed];
|
this.feed = [...enhancedNewData, ...this.feed];
|
||||||
|
this.feed = this.removeDuplicates(this.feed)
|
||||||
this.feed.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
this.feed.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
||||||
this.feed = this.trimDataToLimit(this.feed, maxResultsInMemory); // Trim to the maximum allowed in memory
|
this.feed = this.trimDataToLimit(this.feed, maxResultsInMemory); // Trim to the maximum allowed in memory
|
||||||
this.feedToRender = this.feed.slice(0, 20);
|
this.feedToRender = this.feed.slice(0, 20);
|
||||||
@ -365,6 +365,17 @@ this.getFeedOnInterval()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
removeDuplicates(array) {
|
||||||
|
const seenIds = new Set();
|
||||||
|
return array.filter(item => {
|
||||||
|
if (!seenIds.has(item.identifier)) {
|
||||||
|
seenIds.add(item.identifier);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async loadAndMergeData() {
|
async loadAndMergeData() {
|
||||||
let allData = this.feed
|
let allData = this.feed
|
||||||
@ -373,6 +384,7 @@ this.getFeedOnInterval()
|
|||||||
allData = this.mergeData(newData, allData);
|
allData = this.mergeData(newData, allData);
|
||||||
allData.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
allData.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
||||||
allData = this.trimDataToLimit(allData, maxResultsInMemory); // Trim to the maximum allowed in memory
|
allData = this.trimDataToLimit(allData, maxResultsInMemory); // Trim to the maximum allowed in memory
|
||||||
|
allData = this.removeDuplicates(allData)
|
||||||
this.feed = [...allData]
|
this.feed = [...allData]
|
||||||
this.feedToRender = this.feed.slice(0,20)
|
this.feedToRender = this.feed.slice(0,20)
|
||||||
this.hasInitialFetch = true
|
this.hasInitialFetch = true
|
||||||
|
725
core/src/components/friends-view/profile-modal-update.js
Normal file
725
core/src/components/friends-view/profile-modal-update.js
Normal file
@ -0,0 +1,725 @@
|
|||||||
|
import { LitElement, html, css } from 'lit';
|
||||||
|
import { render } from 'lit/html.js';
|
||||||
|
import {
|
||||||
|
use,
|
||||||
|
get,
|
||||||
|
translate,
|
||||||
|
translateUnsafeHTML,
|
||||||
|
registerTranslateConfig,
|
||||||
|
} from 'lit-translate';
|
||||||
|
import '@material/mwc-button';
|
||||||
|
import '@material/mwc-icon';
|
||||||
|
import '@vaadin/tooltip';
|
||||||
|
import '@material/mwc-dialog';
|
||||||
|
import '@material/mwc-checkbox';
|
||||||
|
import { connect } from 'pwa-helpers';
|
||||||
|
import { store } from '../../store';
|
||||||
|
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
||||||
|
import { parentEpml } from '../show-plugin';
|
||||||
|
|
||||||
|
class ProfileModalUpdate extends connect(store)(LitElement) {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isOpen: { type: Boolean },
|
||||||
|
setIsOpen: { attribute: false },
|
||||||
|
isLoading: { type: Boolean },
|
||||||
|
onSubmit: { attribute: false },
|
||||||
|
editContent: { type: Object },
|
||||||
|
onClose: { attribute: false },
|
||||||
|
tagline: { type: String },
|
||||||
|
bio: { type: String },
|
||||||
|
wallets: { type: Array },
|
||||||
|
hasFetchedArrr: { type: Boolean },
|
||||||
|
isOpenCustomDataModal: { type: Boolean },
|
||||||
|
customData: { type: Object },
|
||||||
|
newCustomDataField: {type: Object},
|
||||||
|
newFieldName: {type: String},
|
||||||
|
qortalRequestCustomData: {type: Object},
|
||||||
|
newCustomDataKey: {type: String},
|
||||||
|
isSaving: {type: Boolean}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isOpen = false;
|
||||||
|
this.isLoading = false;
|
||||||
|
this.nodeUrl = this.getNodeUrl();
|
||||||
|
this.myNode = this.getMyNode();
|
||||||
|
this.tagline = '';
|
||||||
|
this.bio = '';
|
||||||
|
this.walletList = ['btc', 'ltc', 'doge', 'dgb', 'rvn', 'arrr'];
|
||||||
|
let wallets = {};
|
||||||
|
this.walletList.forEach((item) => {
|
||||||
|
wallets[item] = '';
|
||||||
|
});
|
||||||
|
this.wallets = wallets;
|
||||||
|
this.walletsUi = new Map();
|
||||||
|
let coinProp = {
|
||||||
|
wallet: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.walletList.forEach((c, i) => {
|
||||||
|
this.walletsUi.set(c, { ...coinProp });
|
||||||
|
});
|
||||||
|
this.walletsUi.get('btc').wallet =
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress.btcWallet;
|
||||||
|
this.walletsUi.get('ltc').wallet =
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress.ltcWallet;
|
||||||
|
this.walletsUi.get('doge').wallet =
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress.dogeWallet;
|
||||||
|
this.walletsUi.get('dgb').wallet =
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress.dgbWallet;
|
||||||
|
this.walletsUi.get('rvn').wallet =
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress.rvnWallet;
|
||||||
|
this.hasFetchedArrr = false;
|
||||||
|
this.isOpenCustomDataModal = false;
|
||||||
|
this.customData = {};
|
||||||
|
this.newCustomDataKey = ""
|
||||||
|
this.newCustomDataField = {};
|
||||||
|
this.newFieldName = '';
|
||||||
|
this.isSaving = false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return css`
|
||||||
|
* {
|
||||||
|
--mdc-theme-primary: rgb(3, 169, 244);
|
||||||
|
--mdc-theme-secondary: var(--mdc-theme-primary);
|
||||||
|
--mdc-theme-surface: var(--white);
|
||||||
|
--mdc-dialog-content-ink-color: var(--black);
|
||||||
|
--mdc-dialog-min-width: 400px;
|
||||||
|
--mdc-dialog-max-width: 1024px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.input {
|
||||||
|
width: 90%;
|
||||||
|
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);
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.input::selection {
|
||||||
|
background-color: var(--mdc-theme-primary);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input::placeholder {
|
||||||
|
opacity: 0.6;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-button-red {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #f44336;
|
||||||
|
background-color: transparent;
|
||||||
|
padding: 8px 10px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: none;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-button-red:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f4433663;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #03a8f475;
|
||||||
|
}
|
||||||
|
.checkbox-row {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
align-content: center;
|
||||||
|
font-family: Montserrat, sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--black);
|
||||||
|
}
|
||||||
|
.modal-overlay {
|
||||||
|
display: block;
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: rgba(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0.5
|
||||||
|
); /* Semi-transparent backdrop */
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-content {
|
||||||
|
position: fixed;
|
||||||
|
top: 50vh;
|
||||||
|
left: 50vw;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
background-color: var(--mdc-theme-surface);
|
||||||
|
width: 80vw;
|
||||||
|
max-width: 600px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;
|
||||||
|
z-index: 1001;
|
||||||
|
border-radius: 5px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-overlay.hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.avatar {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-name {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
.inner-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
max-height: 75vh;
|
||||||
|
flex-grow: 1;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-content::-webkit-scrollbar-track {
|
||||||
|
background-color: whitesmoke;
|
||||||
|
border-radius: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-content::-webkit-scrollbar {
|
||||||
|
width: 12px;
|
||||||
|
border-radius: 7px;
|
||||||
|
background-color: whitesmoke;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-content::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgb(180, 176, 176);
|
||||||
|
border-radius: 7px;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updated(changedProperties) {
|
||||||
|
if (
|
||||||
|
changedProperties &&
|
||||||
|
changedProperties.has('editContent') &&
|
||||||
|
this.editContent
|
||||||
|
) {
|
||||||
|
const {bio, tagline, wallets, customData} = this.editContent
|
||||||
|
this.bio = bio ?? '';
|
||||||
|
this.tagline = tagline ?? '';
|
||||||
|
let formWallets = {...this.wallets}
|
||||||
|
if(wallets && Object.keys(wallets).length){
|
||||||
|
Object.keys(formWallets).forEach((key)=> {
|
||||||
|
if(wallets[key]){
|
||||||
|
formWallets[key] = wallets[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.wallets = formWallets
|
||||||
|
|
||||||
|
this.customData = {...customData}
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
changedProperties &&
|
||||||
|
changedProperties.has('qortalRequestCustomData') &&
|
||||||
|
this.qortalRequestCustomData
|
||||||
|
) {
|
||||||
|
this.isOpenCustomDataModal = true
|
||||||
|
this.newCustomDataField = {...this.qortalRequestCustomData.payload.customData}
|
||||||
|
this.newCustomDataKey = this.qortalRequestCustomData.property
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
try {
|
||||||
|
await this.fetchWalletAddress('arrr');
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error });
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchWalletAddress(coin) {
|
||||||
|
switch (coin) {
|
||||||
|
case 'arrr':
|
||||||
|
const arrrWalletName = `${coin}Wallet`;
|
||||||
|
|
||||||
|
let res = await parentEpml.request('apiCall', {
|
||||||
|
url: `/crosschain/${coin}/walletaddress?apiKey=${this.myNode.apiKey}`,
|
||||||
|
method: 'POST',
|
||||||
|
body: `${
|
||||||
|
window.parent.reduxStore.getState().app.selectedAddress[
|
||||||
|
arrrWalletName
|
||||||
|
].seed58
|
||||||
|
}`,
|
||||||
|
});
|
||||||
|
if (res != null && res.error != 1201 && res.length === 78) {
|
||||||
|
this.arrrWalletAddress = res;
|
||||||
|
this.hasFetchedArrr = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Not used for other coins yet
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSelectedWalletAddress(wallet) {
|
||||||
|
switch (wallet) {
|
||||||
|
case 'arrr':
|
||||||
|
if(!this.arrrWalletAddress){
|
||||||
|
try {
|
||||||
|
await this.fetchWalletAddress('arrr');
|
||||||
|
} catch (error) {
|
||||||
|
console.log({error})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Use address returned by core API
|
||||||
|
return this.arrrWalletAddress;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Use locally derived address
|
||||||
|
return this.walletsUi.get(wallet).wallet.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode =
|
||||||
|
store.getState().app.nodeConfig.knownNodes[
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.node
|
||||||
|
];
|
||||||
|
|
||||||
|
const nodeUrl =
|
||||||
|
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
||||||
|
return nodeUrl;
|
||||||
|
}
|
||||||
|
getMyNode() {
|
||||||
|
const myNode =
|
||||||
|
store.getState().app.nodeConfig.knownNodes[
|
||||||
|
window.parent.reduxStore.getState().app.nodeConfig.node
|
||||||
|
];
|
||||||
|
|
||||||
|
return myNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFields() {
|
||||||
|
this.bio = '';
|
||||||
|
this.tagline = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
fillAddress(coin) {
|
||||||
|
const address = this.getSelectedWalletAddress(coin);
|
||||||
|
if (address) {
|
||||||
|
this.wallets = {
|
||||||
|
...this.wallets,
|
||||||
|
[coin]: address,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveProfile() {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
version: 1,
|
||||||
|
tagline: this.tagline,
|
||||||
|
bio: this.bio,
|
||||||
|
wallets: this.wallets,
|
||||||
|
customData: this.customData
|
||||||
|
};
|
||||||
|
this.isSaving = true
|
||||||
|
await this.onSubmit(data);
|
||||||
|
this.setIsOpen(false);
|
||||||
|
this.clearFields();
|
||||||
|
this.onClose('success');
|
||||||
|
} catch (error) {} finally {
|
||||||
|
this.isSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeField(key){
|
||||||
|
const copyObj = {...this.newCustomDataField}
|
||||||
|
delete copyObj[key]
|
||||||
|
this.newCustomDataField = copyObj
|
||||||
|
}
|
||||||
|
|
||||||
|
addField(){
|
||||||
|
const copyObj = {...this.newCustomDataField}
|
||||||
|
copyObj[this.newFieldName] = ''
|
||||||
|
this.newCustomDataField = copyObj
|
||||||
|
this.newFieldName = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
addCustomData(){
|
||||||
|
const copyObj = {...this.customData}
|
||||||
|
copyObj[this.newCustomDataKey] = this.newCustomDataField
|
||||||
|
this.customData = copyObj
|
||||||
|
this.newCustomDataKey = ""
|
||||||
|
this.newCustomDataField = {};
|
||||||
|
this.newFieldName = ''
|
||||||
|
this.isOpenCustomDataModal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCustomData(key, data){
|
||||||
|
this.isOpenCustomDataModal = true
|
||||||
|
this.newCustomDataField = data
|
||||||
|
this.newCustomDataKey = key
|
||||||
|
|
||||||
|
}
|
||||||
|
removeCustomData(key){
|
||||||
|
const copyObj = {...this.customData}
|
||||||
|
delete copyObj[key]
|
||||||
|
this.customData = copyObj
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div class="modal-overlay ${this.isOpen ? '' : 'hidden'}">
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="inner-content">
|
||||||
|
<div style="height:15px"></div>
|
||||||
|
<div style="display: flex;flex-direction: column;">
|
||||||
|
<label
|
||||||
|
for="tagline"
|
||||||
|
id="taglineLabel"
|
||||||
|
style="color: var(--black);"
|
||||||
|
>
|
||||||
|
${translate('profile.profile4')}
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
class="input"
|
||||||
|
@change=${(e) => {
|
||||||
|
this.tagline = e.target.value;
|
||||||
|
}}
|
||||||
|
.value=${this.tagline}
|
||||||
|
?disabled=${this.isLoading}
|
||||||
|
id="tagline"
|
||||||
|
placeholder="${translate('profile.profile4')}"
|
||||||
|
rows="3"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div style="height:15px"></div>
|
||||||
|
<div style="display: flex;flex-direction: column;">
|
||||||
|
<label
|
||||||
|
for="bio"
|
||||||
|
id="bioLabel"
|
||||||
|
style="color: var(--black);"
|
||||||
|
>
|
||||||
|
${translate('profile.profile5')}
|
||||||
|
</label>
|
||||||
|
<textarea
|
||||||
|
class="input"
|
||||||
|
@change=${(e) => {
|
||||||
|
this.bio = e.target.value;
|
||||||
|
}}
|
||||||
|
.value=${this.bio}
|
||||||
|
?disabled=${this.isLoading}
|
||||||
|
id="bio"
|
||||||
|
placeholder="${translate('profile.profile5')}"
|
||||||
|
rows="3"
|
||||||
|
></textarea>
|
||||||
|
</div>
|
||||||
|
<div style="height:15px"></div>
|
||||||
|
<p>${translate('profile.profile6')}</p>
|
||||||
|
<div style="display: flex;flex-direction: column;">
|
||||||
|
${Object.keys(this.wallets).map((key) => {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:center;flex-direction:column"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
for=${key}
|
||||||
|
id="taglineLabel"
|
||||||
|
style="color: var(--black);font-size:16px"
|
||||||
|
>
|
||||||
|
${key}
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
style="display:flex;gap:15px;align-items:center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id=${key}
|
||||||
|
placeholder=${key + ' ' + get('settings.address')}
|
||||||
|
class="input"
|
||||||
|
.value=${this.wallets[key]}
|
||||||
|
@change=${(e) => {
|
||||||
|
this.wallets = {
|
||||||
|
...this.wallets,
|
||||||
|
[key]: e.target.value,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<mwc-icon
|
||||||
|
id=${`${key}-upload`}
|
||||||
|
@click=${() =>
|
||||||
|
this.fillAddress(key)}
|
||||||
|
style="color:var(--black);cursor:pointer"
|
||||||
|
>upload_2</mwc-icon
|
||||||
|
>
|
||||||
|
<vaadin-tooltip
|
||||||
|
for=${`${key}-upload`}
|
||||||
|
position="bottom"
|
||||||
|
hover-delay=${200}
|
||||||
|
hide-delay=${1}
|
||||||
|
text=${translate('profile.profile21')}
|
||||||
|
>
|
||||||
|
</vaadin-tooltip>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;flex-direction: column;">
|
||||||
|
${Object.keys(this.customData).map((key) => {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:center;flex-direction:column;gap:25px"
|
||||||
|
>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style="display:flex;gap:15px;align-items:center"
|
||||||
|
>
|
||||||
|
<p
|
||||||
|
|
||||||
|
style="color: var(--black);font-size:16px"
|
||||||
|
>
|
||||||
|
${key}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<mwc-icon
|
||||||
|
@click=${() =>
|
||||||
|
this.updateCustomData(key,this.customData[key])}
|
||||||
|
style="color:var(--black);cursor:pointer"
|
||||||
|
>edit</mwc-icon
|
||||||
|
>
|
||||||
|
<mwc-icon
|
||||||
|
@click=${() =>
|
||||||
|
this.removeCustomData(key)}
|
||||||
|
style="color:var(--black);cursor:pointer"
|
||||||
|
>remove</mwc-icon
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:space-between;align-items:center;margin-top:20px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="modal-button-red"
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
@click="${() => {
|
||||||
|
this.setIsOpen(false);
|
||||||
|
this.clearFields();
|
||||||
|
this.onClose();
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
${translate('general.close')}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div style="display:flex;gap:10px;align-items:center">
|
||||||
|
|
||||||
|
<button
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
class="modal-button"
|
||||||
|
@click=${() => {
|
||||||
|
this.isOpenCustomDataModal = true;
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${translate('profile.profile8')}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
class="modal-button"
|
||||||
|
@click=${() => {
|
||||||
|
if(this.isSaving) return
|
||||||
|
this.saveProfile();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${this.isSaving ? html`
|
||||||
|
<paper-spinner-lite active></paper-spinner-lite>
|
||||||
|
` : ''}
|
||||||
|
${this.isSaving ? '' : translate('profile.profile3') }
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- add custom vars -->
|
||||||
|
<div
|
||||||
|
class="modal-overlay ${this.isOpenCustomDataModal
|
||||||
|
? ''
|
||||||
|
: 'hidden'}"
|
||||||
|
style="z-index:1001"
|
||||||
|
>
|
||||||
|
<div class="modal-content">
|
||||||
|
<div class="inner-content">
|
||||||
|
<div style="height:15px"></div>
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:center;flex-direction:column"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
for="key-name"
|
||||||
|
id="taglineLabel"
|
||||||
|
style="color: var(--black);font-size:16px"
|
||||||
|
>
|
||||||
|
${translate('profile.profile9')}
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
style="display:flex;gap:15px;align-items:center"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="key-name"
|
||||||
|
placeholder=${translate(
|
||||||
|
'profile.profile9'
|
||||||
|
)}
|
||||||
|
?disabled=${!!this.qortalRequestCustomData}
|
||||||
|
class="input"
|
||||||
|
.value=${this.newCustomDataKey}
|
||||||
|
@change=${(e) => {
|
||||||
|
this.newCustomDataKey = e.target.value
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="height:15px"></div>
|
||||||
|
<p>${translate('profile.profile10')}</p>
|
||||||
|
<div style="display: flex;flex-direction: column;">
|
||||||
|
${Object.keys(this.newCustomDataField).map((key) => {
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:center;flex-direction:column"
|
||||||
|
>
|
||||||
|
<label
|
||||||
|
for=${key}
|
||||||
|
id="taglineLabel"
|
||||||
|
style="color: var(--black);font-size:16px"
|
||||||
|
>
|
||||||
|
${key}
|
||||||
|
</label>
|
||||||
|
<div
|
||||||
|
style="display:flex;gap:15px;align-items:center"
|
||||||
|
>
|
||||||
|
|
||||||
|
<input
|
||||||
|
id=${key}
|
||||||
|
placeholder=${translate('profile.profile13')}
|
||||||
|
class="input"
|
||||||
|
.value=${this.newCustomDataField[key]}
|
||||||
|
@change=${(e) => {
|
||||||
|
this.newCustomDataField = {
|
||||||
|
...this.newCustomDataField,
|
||||||
|
[key]: e.target.value,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<mwc-icon
|
||||||
|
@click=${() =>
|
||||||
|
this.removeField(key)}
|
||||||
|
style="color:var(--black);cursor:pointer"
|
||||||
|
>remove</mwc-icon
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
<div style="height:15px"></div>
|
||||||
|
<div style="width:100%;display:flex;justify-content:center;gap:10px;margin-top:30px">
|
||||||
|
<input
|
||||||
|
|
||||||
|
placeholder=${translate('profile.profile12')}
|
||||||
|
class="input"
|
||||||
|
.value=${this.newFieldName}
|
||||||
|
@change=${(e) => {
|
||||||
|
this.newFieldName = e.target.value
|
||||||
|
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="modal-button"
|
||||||
|
@click=${() => {
|
||||||
|
this.addField();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${translate('profile.profile11')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:space-between;align-items:center;margin-top:20px"
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
class="modal-button-red"
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
@click="${() => {
|
||||||
|
this.isOpenCustomDataModal = false
|
||||||
|
this.newCustomDataKey = ""
|
||||||
|
this.newCustomDataField = {};
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
${translate('general.close')}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
?disabled="${this.isSaving}"
|
||||||
|
class="modal-button"
|
||||||
|
@click=${() => {
|
||||||
|
this.addCustomData();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${translate('profile.profile8')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('profile-modal-update', ProfileModalUpdate);
|
1023
core/src/components/friends-view/profile.js
Normal file
1023
core/src/components/friends-view/profile.js
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,14 +1,17 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import {css, html, LitElement} from 'lit';
|
||||||
import '@material/mwc-icon';
|
import '@material/mwc-icon';
|
||||||
import './friends-side-panel.js';
|
import './friends-side-panel.js';
|
||||||
import {connect} from 'pwa-helpers';
|
import { connect } from 'pwa-helpers';
|
||||||
import {store} from '../../store.js';
|
import { store } from '../../store.js';
|
||||||
import WebWorker from 'web-worker:./computePowWorkerFile.src.js';
|
import WebWorker from '../WebWorkerFile.js';
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
||||||
import '@vaadin/tooltip';
|
import '@vaadin/tooltip';
|
||||||
import {translate} from 'lit-translate';
|
import { get, translate } from 'lit-translate';
|
||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
decryptGroupData,
|
decryptGroupData,
|
||||||
|
|
||||||
encryptDataGroup,
|
encryptDataGroup,
|
||||||
objectToBase64,
|
objectToBase64,
|
||||||
uint8ArrayToObject,
|
uint8ArrayToObject,
|
||||||
@ -16,6 +19,7 @@ import {
|
|||||||
import {publishData} from '../../../../plugins/plugins/utils/publish-image.js';
|
import {publishData} from '../../../../plugins/plugins/utils/publish-image.js';
|
||||||
import {parentEpml} from '../show-plugin.js';
|
import {parentEpml} from '../show-plugin.js';
|
||||||
import '../notification-view/popover.js';
|
import '../notification-view/popover.js';
|
||||||
|
import { setNewTab } from '../../redux/app/app-actions.js';
|
||||||
|
|
||||||
class SaveSettingsQdn extends connect(store)(LitElement) {
|
class SaveSettingsQdn extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -27,6 +31,9 @@ class SaveSettingsQdn extends connect(store)(LitElement) {
|
|||||||
resourceExists: { type: Boolean },
|
resourceExists: { type: Boolean },
|
||||||
isSaving: { type: Boolean },
|
isSaving: { type: Boolean },
|
||||||
fee: { type: Object },
|
fee: { type: Object },
|
||||||
|
hasName: {type: Boolean},
|
||||||
|
error: {type: String},
|
||||||
|
name: {type: String}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,6 +54,11 @@ class SaveSettingsQdn extends connect(store)(LitElement) {
|
|||||||
this.valuesToBeSavedOnQdn = {};
|
this.valuesToBeSavedOnQdn = {};
|
||||||
this.isSaving = false;
|
this.isSaving = false;
|
||||||
this.fee = null;
|
this.fee = null;
|
||||||
|
this.hasName = false;
|
||||||
|
this.error = "";
|
||||||
|
this.uid = new ShortUniqueId();
|
||||||
|
this.name = undefined;
|
||||||
|
|
||||||
}
|
}
|
||||||
static styles = css`
|
static styles = css`
|
||||||
:host {
|
:host {
|
||||||
@ -309,13 +321,26 @@ class SaveSettingsQdn extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
async getGeneralSettingsQdn() {
|
async getGeneralSettingsQdn() {
|
||||||
try {
|
try {
|
||||||
|
this.error = ""
|
||||||
const arbFee = await this.getArbitraryFee();
|
const arbFee = await this.getArbitraryFee();
|
||||||
this.fee = arbFee;
|
this.fee = arbFee;
|
||||||
this.hasAttemptedToFetchResource = true;
|
this.hasAttemptedToFetchResource = true;
|
||||||
let resource;
|
let resource;
|
||||||
const nameObject = store.getState().app.accountInfo.names[0];
|
let nameObject
|
||||||
if (!nameObject) throw new Error('no name');
|
try {
|
||||||
|
nameObject = store.getState().app.accountInfo.names[0];
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
if (!nameObject) {
|
||||||
|
this.name = null;
|
||||||
|
this.error = 'no name'
|
||||||
|
throw new Error('no name');
|
||||||
|
}
|
||||||
const name = nameObject.name;
|
const name = nameObject.name;
|
||||||
|
this.name = name;
|
||||||
|
this.hasName = true
|
||||||
this.error = '';
|
this.error = '';
|
||||||
const url = `${this.nodeUrl}/arbitrary/resources/search?service=DOCUMENT_PRIVATE&identifier=qortal_general_settings&name=${name}&prefix=true&exactmatchnames=true&excludeblocked=true&limit=20`;
|
const url = `${this.nodeUrl}/arbitrary/resources/search?service=DOCUMENT_PRIVATE&identifier=qortal_general_settings&name=${name}&prefix=true&exactmatchnames=true&excludeblocked=true&limit=20`;
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
@ -363,8 +388,6 @@ class SaveSettingsQdn extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
stateChanged(state) {
|
stateChanged(state) {
|
||||||
if (
|
if (
|
||||||
state.app.accountInfo &&
|
|
||||||
state.app.accountInfo.names.length &&
|
|
||||||
state.app.nodeStatus &&
|
state.app.nodeStatus &&
|
||||||
state.app.nodeStatus.syncPercent !== this.syncPercentage
|
state.app.nodeStatus.syncPercent !== this.syncPercentage
|
||||||
) {
|
) {
|
||||||
@ -377,6 +400,15 @@ class SaveSettingsQdn extends connect(store)(LitElement) {
|
|||||||
this.getGeneralSettingsQdn();
|
this.getGeneralSettingsQdn();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
state.app.accountInfo &&
|
||||||
|
state.app.accountInfo.names.length &&
|
||||||
|
state.app.nodeStatus &&
|
||||||
|
state.app.nodeStatus.syncPercent === 100 && this.hasName === false && this.hasAttemptedToFetchResource && state.app.accountInfo && state.app.accountInfo.names && state.app.accountInfo.names.length > 0
|
||||||
|
) {
|
||||||
|
this.getGeneralSettingsQdn();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async getArbitraryFee() {
|
async getArbitraryFee() {
|
||||||
@ -529,7 +561,78 @@ class SaveSettingsQdn extends connect(store)(LitElement) {
|
|||||||
style="display: block; margin: 0 auto;"
|
style="display: block; margin: 0 auto;"
|
||||||
></paper-spinner-lite>
|
></paper-spinner-lite>
|
||||||
`
|
`
|
||||||
: html`
|
: !this.name ? html`
|
||||||
|
<mwc-icon
|
||||||
|
id="profile-icon"
|
||||||
|
class=${'notActive'}
|
||||||
|
@click=${() => {
|
||||||
|
const target = this.shadowRoot.getElementById(
|
||||||
|
'popover-notification'
|
||||||
|
);
|
||||||
|
const popover =
|
||||||
|
this.shadowRoot.querySelector(
|
||||||
|
'popover-component'
|
||||||
|
);
|
||||||
|
if (popover) {
|
||||||
|
popover.openPopover(target);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
style="user-select:none;cursor:pointer"
|
||||||
|
>save</mwc-icon
|
||||||
|
>
|
||||||
|
<vaadin-tooltip
|
||||||
|
for="profile-icon"
|
||||||
|
position="bottom"
|
||||||
|
hover-delay=${300}
|
||||||
|
hide-delay=${1}
|
||||||
|
text=${translate('profile.profile20')}
|
||||||
|
>
|
||||||
|
</vaadin-tooltip>
|
||||||
|
<popover-component for="profile-icon" message="">
|
||||||
|
<div style="margin-bottom:20px">
|
||||||
|
<p style="margin:10px 0px; font-size:16px">
|
||||||
|
${translate('profile.profile1')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style="display:flex;justify-content:center;gap:10px"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="accept-button"
|
||||||
|
@click="${() => {
|
||||||
|
store.dispatch(
|
||||||
|
setNewTab({
|
||||||
|
url: `group-management`,
|
||||||
|
id: this.uid.rnd(),
|
||||||
|
myPlugObj: {
|
||||||
|
url: 'name-registration',
|
||||||
|
domain: 'core',
|
||||||
|
page: 'name-registration/index.html',
|
||||||
|
title: 'Name Registration',
|
||||||
|
icon: 'vaadin:user-check',
|
||||||
|
mwcicon: 'manage_accounts',
|
||||||
|
pluginNumber:
|
||||||
|
'plugin-qCmtXAQmtu',
|
||||||
|
menus: [],
|
||||||
|
parent: false,
|
||||||
|
},
|
||||||
|
openExisting: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
const popover =
|
||||||
|
this.shadowRoot.querySelector(
|
||||||
|
'popover-component'
|
||||||
|
);
|
||||||
|
if (popover) {
|
||||||
|
popover.closePopover();
|
||||||
|
}
|
||||||
|
}}"
|
||||||
|
>
|
||||||
|
${translate('profile.profile2')}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</popover-component>
|
||||||
|
` : html`
|
||||||
<mwc-icon
|
<mwc-icon
|
||||||
id="save-icon"
|
id="save-icon"
|
||||||
class=${Object.values(this.valuesToBeSavedOnQdn)
|
class=${Object.values(this.valuesToBeSavedOnQdn)
|
||||||
|
@ -9,6 +9,7 @@ const CHAT_HEADS_STREAM_NAME = 'chat_heads'
|
|||||||
const NODE_CONFIG_STREAM_NAME = 'node_config'
|
const NODE_CONFIG_STREAM_NAME = 'node_config'
|
||||||
const CHAT_LAST_SEEN = 'chat_last_seen'
|
const CHAT_LAST_SEEN = 'chat_last_seen'
|
||||||
const SIDE_EFFECT_ACTION = 'side_effect_action'
|
const SIDE_EFFECT_ACTION = 'side_effect_action'
|
||||||
|
const PROFILE_DATA_ACTION = 'profile_data_action'
|
||||||
const COIN_BALANCES_ACTION = 'coin_balances'
|
const COIN_BALANCES_ACTION = 'coin_balances'
|
||||||
|
|
||||||
export const loggedInStream = new EpmlStream(LOGIN_STREAM_NAME, () => store.getState().app.loggedIn)
|
export const loggedInStream = new EpmlStream(LOGIN_STREAM_NAME, () => store.getState().app.loggedIn)
|
||||||
@ -19,6 +20,7 @@ export const chatHeadsStateStream = new EpmlStream(CHAT_HEADS_STREAM_NAME, () =>
|
|||||||
export const nodeConfigStream = new EpmlStream(NODE_CONFIG_STREAM_NAME, () => store.getState().app.nodeConfig)
|
export const nodeConfigStream = new EpmlStream(NODE_CONFIG_STREAM_NAME, () => store.getState().app.nodeConfig)
|
||||||
export const chatLastSeenStream = new EpmlStream(CHAT_LAST_SEEN, () => store.getState().app.chatLastSeen)
|
export const chatLastSeenStream = new EpmlStream(CHAT_LAST_SEEN, () => store.getState().app.chatLastSeen)
|
||||||
export const sideEffectActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.sideEffectAction)
|
export const sideEffectActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.sideEffectAction)
|
||||||
|
export const profileDataActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.profileData)
|
||||||
export const coinBalancesActionStream = new EpmlStream(COIN_BALANCES_ACTION, () => store.getState().app.coinBalances)
|
export const coinBalancesActionStream = new EpmlStream(COIN_BALANCES_ACTION, () => store.getState().app.coinBalances)
|
||||||
|
|
||||||
|
|
||||||
@ -65,6 +67,9 @@ store.subscribe(() => {
|
|||||||
if (oldState.app.sideEffectAction !== state.app.sideEffectAction) {
|
if (oldState.app.sideEffectAction !== state.app.sideEffectAction) {
|
||||||
sideEffectActionStream.emit(state.app.sideEffectAction)
|
sideEffectActionStream.emit(state.app.sideEffectAction)
|
||||||
}
|
}
|
||||||
|
if(oldState.app.profileDataActionStream !== state.app.profileDataActionStream){
|
||||||
|
profileDataActionStream.emit(state.app.profileData)
|
||||||
|
}
|
||||||
if (oldState.app.coinBalances !== state.app.coinBalances) {
|
if (oldState.app.coinBalances !== state.app.coinBalances) {
|
||||||
coinBalancesActionStream.emit(state.app.coinBalances)
|
coinBalancesActionStream.emit(state.app.coinBalances)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@ import {
|
|||||||
SET_TAB_NOTIFICATIONS,
|
SET_TAB_NOTIFICATIONS,
|
||||||
UPDATE_BLOCK_INFO,
|
UPDATE_BLOCK_INFO,
|
||||||
UPDATE_NODE_INFO,
|
UPDATE_NODE_INFO,
|
||||||
UPDATE_NODE_STATUS
|
UPDATE_NODE_STATUS,
|
||||||
|
SET_PROFILE_DATA
|
||||||
} from '../app-action-types.js'
|
} from '../app-action-types.js'
|
||||||
|
|
||||||
export const doUpdateBlockInfo = (blockObj) => {
|
export const doUpdateBlockInfo = (blockObj) => {
|
||||||
@ -179,6 +180,12 @@ export const setSideEffectAction = (payload)=> {
|
|||||||
payload
|
payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export const setProfileData = (payload)=> {
|
||||||
|
return {
|
||||||
|
type: SET_PROFILE_DATA,
|
||||||
|
payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export const setCoinBalances = (payload)=> {
|
export const setCoinBalances = (payload)=> {
|
||||||
return {
|
return {
|
||||||
|
@ -33,4 +33,5 @@ export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'
|
|||||||
export const IS_OPEN_DEV_DIALOG = 'IS_OPEN_DEV_DIALOG'
|
export const IS_OPEN_DEV_DIALOG = 'IS_OPEN_DEV_DIALOG'
|
||||||
export const SET_NEW_NOTIFICATION = 'SET_NEW_NOTIFICATION'
|
export const SET_NEW_NOTIFICATION = 'SET_NEW_NOTIFICATION'
|
||||||
export const SET_SIDE_EFFECT= 'SET_SIDE_EFFECT'
|
export const SET_SIDE_EFFECT= 'SET_SIDE_EFFECT'
|
||||||
|
export const SET_PROFILE_DATA = 'SET_PROFILE_DATA'
|
||||||
export const SET_COIN_BALANCES= 'SET_COIN_BALANCES'
|
export const SET_COIN_BALANCES= 'SET_COIN_BALANCES'
|
||||||
|
@ -35,7 +35,8 @@ import {
|
|||||||
SET_TAB_NOTIFICATIONS,
|
SET_TAB_NOTIFICATIONS,
|
||||||
UPDATE_BLOCK_INFO,
|
UPDATE_BLOCK_INFO,
|
||||||
UPDATE_NODE_INFO,
|
UPDATE_NODE_INFO,
|
||||||
UPDATE_NODE_STATUS
|
UPDATE_NODE_STATUS,
|
||||||
|
SET_PROFILE_DATA
|
||||||
} from './app-action-types.js'
|
} from './app-action-types.js'
|
||||||
import {initWorkersReducer} from './reducers/init-workers.js'
|
import {initWorkersReducer} from './reducers/init-workers.js'
|
||||||
import {loginReducer} from './reducers/login-reducer.js'
|
import {loginReducer} from './reducers/login-reducer.js'
|
||||||
@ -90,6 +91,7 @@ const INITIAL_STATE = {
|
|||||||
isOpenDevDialog: false,
|
isOpenDevDialog: false,
|
||||||
newNotification: null,
|
newNotification: null,
|
||||||
sideEffectAction: null,
|
sideEffectAction: null,
|
||||||
|
profileData: null,
|
||||||
coinBalances: {}
|
coinBalances: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -331,6 +333,12 @@ export default (state = INITIAL_STATE, action) => {
|
|||||||
sideEffectAction: action.payload
|
sideEffectAction: action.payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case SET_PROFILE_DATA: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
profileData: action.payload
|
||||||
|
}
|
||||||
|
}
|
||||||
case SET_COIN_BALANCES: {
|
case SET_COIN_BALANCES: {
|
||||||
const copyBalances = {...state.coinBalances}
|
const copyBalances = {...state.coinBalances}
|
||||||
copyBalances[action.payload.type] = {
|
copyBalances[action.payload.type] = {
|
||||||
|
@ -65,7 +65,6 @@ export class ChatGroupsModal extends LitElement {
|
|||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
console.log('hello')
|
|
||||||
return html`
|
return html`
|
||||||
|
|
||||||
<mwc-dialog
|
<mwc-dialog
|
||||||
|
@ -363,9 +363,7 @@ class ChatPage extends LitElement {
|
|||||||
|
|
||||||
}
|
}
|
||||||
this.processMessages(getInitialMessages, true, false)
|
this.processMessages(getInitialMessages, true, false)
|
||||||
} catch (error) {
|
} catch (error) { /* empty */ }
|
||||||
console.log
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async copyJoinGroupLinkToClipboard() {
|
async copyJoinGroupLinkToClipboard() {
|
||||||
@ -681,7 +679,10 @@ class ChatPage extends LitElement {
|
|||||||
<br>
|
<br>
|
||||||
<h3 style="color: var(--black);">${translate("chatpage.cchange42")}</h3>
|
<h3 style="color: var(--black);">${translate("chatpage.cchange42")}</h3>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<mwc-button @click=${() => this.sendMessage(this.myTrimmedMeassage)} dialog-confirm>${translate("transpage.tchange3")}</mwc-button>
|
<mwc-button @click=${() => {
|
||||||
|
this.sendMessage(this.myMessageUnder4Qort)
|
||||||
|
|
||||||
|
}} dialog-confirm>${translate("transpage.tchange3")}</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
</paper-dialog>
|
</paper-dialog>
|
||||||
<wrapper-modal
|
<wrapper-modal
|
||||||
@ -1345,6 +1346,7 @@ class ChatPage extends LitElement {
|
|||||||
const isRecipient = this.chatId.includes('direct') === true ? true : false
|
const isRecipient = this.chatId.includes('direct') === true ? true : false
|
||||||
this.chatId.includes('direct') === true ? this.isReceipient = true : this.isReceipient = false
|
this.chatId.includes('direct') === true ? this.isReceipient = true : this.isReceipient = false
|
||||||
this._chatId = this.chatId.split('/')[1]
|
this._chatId = this.chatId.split('/')[1]
|
||||||
|
|
||||||
const mstring = get("chatpage.cchange8")
|
const mstring = get("chatpage.cchange8")
|
||||||
const placeholder = isRecipient === true ? `Message ${this._chatId}` : `${mstring}`
|
const placeholder = isRecipient === true ? `Message ${this._chatId}` : `${mstring}`
|
||||||
this.chatEditorPlaceholder = placeholder
|
this.chatEditorPlaceholder = placeholder
|
||||||
@ -3113,8 +3115,8 @@ class ChatPage extends LitElement {
|
|||||||
const stringifyMessageObject = JSON.stringify(messageObject)
|
const stringifyMessageObject = JSON.stringify(messageObject)
|
||||||
|
|
||||||
if (this.balance < 4) {
|
if (this.balance < 4) {
|
||||||
this.myTrimmedMeassage = ''
|
this.myMessageUnder4Qort = null
|
||||||
this.myTrimmedMeassage = stringifyMessageObject
|
this.myMessageUnder4Qort = {messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue}
|
||||||
this.shadowRoot.getElementById('confirmDialog').open()
|
this.shadowRoot.getElementById('confirmDialog').open()
|
||||||
} else {
|
} else {
|
||||||
return this.sendMessage({messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue})
|
return this.sendMessage({messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue})
|
||||||
@ -3164,23 +3166,23 @@ class ChatPage extends LitElement {
|
|||||||
})
|
})
|
||||||
return _computePow(chatResponse)
|
return _computePow(chatResponse)
|
||||||
} else {
|
} else {
|
||||||
let groupResponse = await parentEpml.request('chat', {
|
let groupResponse = await parentEpml.request('chat', {
|
||||||
type: 181,
|
type: 181,
|
||||||
nonce: this.selectedAddress.nonce,
|
nonce: this.selectedAddress.nonce,
|
||||||
params: {
|
params: {
|
||||||
timestamp: Date.now(),
|
timestamp: Date.now(),
|
||||||
groupID: Number(_chatId),
|
groupID: Number(_chatId),
|
||||||
hasReceipient: 0,
|
hasReceipient: 0,
|
||||||
hasChatReference: typeMessage === 'edit' ? 1 : 0,
|
hasChatReference: typeMessage === 'edit' ? 1 : 0,
|
||||||
chatReference: chatReference,
|
chatReference: chatReference,
|
||||||
message: messageText,
|
message: messageText,
|
||||||
lastReference: reference,
|
lastReference: reference,
|
||||||
proofOfWorkNonce: 0,
|
proofOfWorkNonce: 0,
|
||||||
isEncrypted: 0, // Set default to not encrypted for groups
|
isEncrypted: 0, // Set default to not encrypted for groups
|
||||||
isText: 1
|
isText: 1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return _computePow(groupResponse)
|
return _computePow(groupResponse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,6 +51,16 @@ export class UserInfo extends LitElement {
|
|||||||
return imageHTMLRes
|
return imageHTMLRes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openProfile(){
|
||||||
|
try {
|
||||||
|
const customEvent = new CustomEvent('open-visiting-profile', {
|
||||||
|
detail: this.userName
|
||||||
|
});
|
||||||
|
window.parent.dispatchEvent(customEvent);
|
||||||
|
|
||||||
|
} catch (error) { /* empty */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
let avatarImg = ""
|
let avatarImg = ""
|
||||||
@ -84,7 +94,7 @@ export class UserInfo extends LitElement {
|
|||||||
<img src="/img/incognito.png" alt="avatar" />
|
<img src="/img/incognito.png" alt="avatar" />
|
||||||
</div>`
|
</div>`
|
||||||
: ""}
|
: ""}
|
||||||
<div class="user-info-header">
|
<div class="user-info-header">
|
||||||
${this.selectedHead && this.selectedHead.name ? this.selectedHead.name : this.selectedHead ? cropAddress(this.selectedHead.address) : null}
|
${this.selectedHead && this.selectedHead.name ? this.selectedHead.name : this.selectedHead ? cropAddress(this.selectedHead.address) : null}
|
||||||
</div>
|
</div>
|
||||||
<div class="send-message-button" @click="${() => {
|
<div class="send-message-button" @click="${() => {
|
||||||
@ -102,6 +112,19 @@ export class UserInfo extends LitElement {
|
|||||||
}}>
|
}}>
|
||||||
${translate("chatpage.cchange59")}
|
${translate("chatpage.cchange59")}
|
||||||
</div>
|
</div>
|
||||||
|
${this.userName ? html`
|
||||||
|
<div style="margin-top: 5px;text-transform: uppercase;" class="send-message-button" @click=${() => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.openProfile()
|
||||||
|
}, 250);
|
||||||
|
this.setOpenUserInfo(false)
|
||||||
|
|
||||||
|
|
||||||
|
}}>
|
||||||
|
${translate("profile.profile18")}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
@ -70,5 +70,11 @@ export const VOTE_ON_POLL= 'VOTE_ON_POLL'
|
|||||||
//CREATE_POLL
|
//CREATE_POLL
|
||||||
export const CREATE_POLL= 'CREATE_POLL'
|
export const CREATE_POLL= 'CREATE_POLL'
|
||||||
|
|
||||||
|
//GET_PROFILE_DATA
|
||||||
|
export const GET_PROFILE_DATA = 'GET_PROFILE_DATA'
|
||||||
|
|
||||||
|
|
||||||
|
// SET_PROFILE_DATA
|
||||||
|
export const SET_PROFILE_DATA= 'SET_PROFILE_DATA'
|
||||||
//GET_DAY_SUMMARY
|
//GET_DAY_SUMMARY
|
||||||
export const GET_DAY_SUMMARY = 'GET_DAY_SUMMARY'
|
export const GET_DAY_SUMMARY = 'GET_DAY_SUMMARY'
|
||||||
|
@ -481,11 +481,10 @@ class WebBrowser extends LitElement {
|
|||||||
const arbitraryFee = (Number(data) / 1e8).toFixed(8)
|
const arbitraryFee = (Number(data) / 1e8).toFixed(8)
|
||||||
return {
|
return {
|
||||||
timestamp,
|
timestamp,
|
||||||
fee : Number(data),
|
fee: Number(data),
|
||||||
feeToShow: arbitraryFee
|
feeToShow: arbitraryFee
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendQortFee() {
|
async sendQortFee() {
|
||||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
||||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
@ -660,9 +659,9 @@ class WebBrowser extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const makeTransactionRequest = async (lastRef) => {
|
const makeTransactionRequest = async (lastRef) => {
|
||||||
let votedialog1 = get("transactions.votedialog1")
|
let votedialog1 = get("transactions.votedialog1")
|
||||||
let votedialog2 = get("transactions.votedialog2")
|
let votedialog2 = get("transactions.votedialog2")
|
||||||
let feeDialog = get("walletpage.wchange12")
|
let feeDialog = get("walletpage.wchange12")
|
||||||
|
|
||||||
let myTxnrequest = await parentEpml.request('transaction', {
|
let myTxnrequest = await parentEpml.request('transaction', {
|
||||||
type: 9,
|
type: 9,
|
||||||
@ -1622,7 +1621,7 @@ class WebBrowser extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case actions.SEND_LOCAL_NOTIFICATION: {
|
case actions.SEND_LOCAL_NOTIFICATION: {
|
||||||
const {title, url, icon, message} = data
|
const { title, url, icon, message } = data
|
||||||
try {
|
try {
|
||||||
const id = `appNotificationList-${this.selectedAddress.address}`
|
const id = `appNotificationList-${this.selectedAddress.address}`
|
||||||
const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null
|
const checkData = localStorage.getItem(id) ? JSON.parse(localStorage.getItem(id)) : null
|
||||||
@ -1641,7 +1640,7 @@ class WebBrowser extends LitElement {
|
|||||||
this.updateLastNotification(id, this.name)
|
this.updateLastNotification(id, this.name)
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`duration until another notification can be sent: ${interval - timeDifference}`)
|
throw new Error(`invalid data`)
|
||||||
}
|
}
|
||||||
} else if(!lastNotification){
|
} else if(!lastNotification){
|
||||||
parentEpml.request('showNotification', {
|
parentEpml.request('showNotification', {
|
||||||
@ -2064,6 +2063,199 @@ class WebBrowser extends LitElement {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'GET_PROFILE_DATA': {
|
||||||
|
const defaultProperties = ['tagline', 'bio', 'wallets']
|
||||||
|
const requiredFields = ['property'];
|
||||||
|
const missingFields = [];
|
||||||
|
|
||||||
|
requiredFields.forEach((field) => {
|
||||||
|
if (!data[field] && data[field] !== 0) {
|
||||||
|
missingFields.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (missingFields.length > 0) {
|
||||||
|
const missingFieldsString = missingFields.join(', ');
|
||||||
|
const errorMsg = `Missing fields: ${missingFieldsString}`
|
||||||
|
let data = {};
|
||||||
|
data['error'] = errorMsg;
|
||||||
|
response = JSON.stringify(data);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const profileData = window.parent.reduxStore.getState().app.profileData
|
||||||
|
if (!profileData) {
|
||||||
|
throw new Error('User does not have a profile')
|
||||||
|
}
|
||||||
|
const property = data.property
|
||||||
|
const propertyIndex = defaultProperties.indexOf(property)
|
||||||
|
if (propertyIndex !== -1) {
|
||||||
|
const requestedData = profileData[property]
|
||||||
|
if (requestedData) {
|
||||||
|
response = JSON.stringify(requestedData);
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
throw new Error('Cannot find requested data')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (property.includes('-private')) {
|
||||||
|
const resPrivateProperty = await showModalAndWait(
|
||||||
|
actions.GET_PROFILE_DATA, {
|
||||||
|
property
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (resPrivateProperty.action === 'accept') {
|
||||||
|
|
||||||
|
const requestedData = profileData.customData[property]
|
||||||
|
if (requestedData) {
|
||||||
|
response = JSON.stringify(requestedData);
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
throw new Error('Cannot find requested data')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error('User denied permission for private property')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const requestedData = profileData.customData[property]
|
||||||
|
if (requestedData) {
|
||||||
|
response = JSON.stringify(requestedData);
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
throw new Error('Cannot find requested data')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const obj = {};
|
||||||
|
const errorMsg = error.message || 'Failed to join the group.';
|
||||||
|
obj['error'] = errorMsg;
|
||||||
|
response = JSON.stringify(obj);
|
||||||
|
} finally {
|
||||||
|
this.loader.hide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'SET_PROFILE_DATA': {
|
||||||
|
const requiredFields = ['property', 'data'];
|
||||||
|
const missingFields = [];
|
||||||
|
|
||||||
|
requiredFields.forEach((field) => {
|
||||||
|
if (!data[field] && data[field] !== 0) {
|
||||||
|
missingFields.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (missingFields.length > 0) {
|
||||||
|
const missingFieldsString = missingFields.join(', ');
|
||||||
|
const errorMsg = `Missing fields: ${missingFieldsString}`
|
||||||
|
let data = {};
|
||||||
|
data['error'] = errorMsg;
|
||||||
|
response = JSON.stringify(data);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const property = data.property
|
||||||
|
const payload = data.data
|
||||||
|
const uniqueId = this.uid.rnd()
|
||||||
|
const fee = await this.getArbitraryFee()
|
||||||
|
const resSetPrivateProperty = await showModalAndWait(
|
||||||
|
actions.SET_PROFILE_DATA, {
|
||||||
|
property,
|
||||||
|
fee: fee.feeToShow
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
if (resSetPrivateProperty.action !== 'accept') throw new Error('User declined permission')
|
||||||
|
|
||||||
|
//dispatch event and wait until I get a response to continue
|
||||||
|
|
||||||
|
// Create and dispatch custom event
|
||||||
|
const customEvent = new CustomEvent('qortal-request-set-profile-data', {
|
||||||
|
detail: {
|
||||||
|
property,
|
||||||
|
payload,
|
||||||
|
uniqueId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.parent.dispatchEvent(customEvent);
|
||||||
|
|
||||||
|
// Wait for response event
|
||||||
|
const res = await new Promise((resolve, reject) => {
|
||||||
|
function handleResponseEvent(event) {
|
||||||
|
// Handle the data from the event, if any
|
||||||
|
const responseData = event.detail;
|
||||||
|
if(responseData && responseData.uniqueId !== uniqueId) return
|
||||||
|
// Clean up by removing the event listener once we've received the response
|
||||||
|
window.removeEventListener('qortal-request-set-profile-data-response', handleResponseEvent);
|
||||||
|
|
||||||
|
if (responseData.response === 'saved') {
|
||||||
|
resolve(responseData);
|
||||||
|
} else {
|
||||||
|
reject(new Error('not saved'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up an event listener to wait for the response
|
||||||
|
window.addEventListener('qortal-request-set-profile-data-response', handleResponseEvent);
|
||||||
|
});
|
||||||
|
if(!res.response) throw new Error('Failed to set property')
|
||||||
|
response = JSON.stringify(res.response);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
const obj = {};
|
||||||
|
const errorMsg = error.message || 'Failed to set property.';
|
||||||
|
obj['error'] = errorMsg;
|
||||||
|
response = JSON.stringify(obj);
|
||||||
|
} finally {
|
||||||
|
this.loader.hide();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case 'OPEN_PROFILE': {
|
||||||
|
const requiredFields = ['name'];
|
||||||
|
const missingFields = [];
|
||||||
|
|
||||||
|
requiredFields.forEach((field) => {
|
||||||
|
if (!data[field] && data[field] !== 0) {
|
||||||
|
missingFields.push(field);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (missingFields.length > 0) {
|
||||||
|
const missingFieldsString = missingFields.join(', ');
|
||||||
|
const errorMsg = `Missing fields: ${missingFieldsString}`
|
||||||
|
let data = {};
|
||||||
|
data['error'] = errorMsg;
|
||||||
|
response = JSON.stringify(data);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
const customEvent = new CustomEvent('open-visiting-profile', {
|
||||||
|
detail: data.name
|
||||||
|
});
|
||||||
|
window.parent.dispatchEvent(customEvent);
|
||||||
|
response = JSON.stringify(true);
|
||||||
|
} catch (error) {
|
||||||
|
const obj = {};
|
||||||
|
const errorMsg = error.message || 'Failed to open profile';
|
||||||
|
obj['error'] = errorMsg;
|
||||||
|
response = JSON.stringify(obj);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
case actions.GET_USER_WALLET: {
|
case actions.GET_USER_WALLET: {
|
||||||
const requiredFields = ['coin'];
|
const requiredFields = ['coin'];
|
||||||
const missingFields = [];
|
const missingFields = [];
|
||||||
@ -3561,7 +3753,7 @@ async function showModalAndWait(type, data) {
|
|||||||
|
|
||||||
${type === actions.GET_USER_WALLET ? `
|
${type === actions.GET_USER_WALLET ? `
|
||||||
<div class="modal-subcontainer">
|
<div class="modal-subcontainer">
|
||||||
<p class="modal-paragraph">${get("browserpage.bchange49")}</p>
|
<p class="modal-paragraph">${get("browserpage.bchange52")}</p>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
${type === actions.GET_WALLET_BALANCE ? `
|
${type === actions.GET_WALLET_BALANCE ? `
|
||||||
@ -3593,6 +3785,21 @@ async function showModalAndWait(type, data) {
|
|||||||
<p class="modal-paragraph">${get("browserpage.bchange46")}: <span> ${data.filename}</span></p>
|
<p class="modal-paragraph">${get("browserpage.bchange46")}: <span> ${data.filename}</span></p>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
${type === actions.GET_PROFILE_DATA ? `
|
||||||
|
<div class="modal-subcontainer">
|
||||||
|
<p class="modal-paragraph">${get("browserpage.bchange49")}: <span style="font-weight: bold"> ${data.property}</span></p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
${type === actions.SET_PROFILE_DATA ? `
|
||||||
|
<div class="modal-subcontainer">
|
||||||
|
<p class="modal-paragraph">${get("browserpage.bchange50")} <span style="font-weight: bold"> ${data.property}</span></p>
|
||||||
|
<br>
|
||||||
|
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph">${get('browserpage.bchange47')} <span style="font-weight: bold">${data.fee} QORT fee</span></p>
|
||||||
|
<br>
|
||||||
|
<p style="font-size: 16px;overflow-wrap: anywhere;" class="modal-paragraph">${get('browserpage.bchange51')} </p>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
${type === actions.NOTIFICATIONS_PERMISSION ? `
|
${type === actions.NOTIFICATIONS_PERMISSION ? `
|
||||||
<div class="modal-subcontainer">
|
<div class="modal-subcontainer">
|
||||||
<p class="modal-paragraph">${get("browserpage.bchange48")}</p>
|
<p class="modal-paragraph">${get("browserpage.bchange48")}</p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user