mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-02-11 17:55:51 +00:00
started profile
This commit is contained in:
parent
b2a5b13a22
commit
ed5253d6d0
@ -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;"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -1212,5 +1212,12 @@
|
|||||||
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
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;
|
@ -46,6 +46,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'
|
||||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
class AppView extends connect(store)(LitElement) {
|
class AppView extends connect(store)(LitElement) {
|
||||||
@ -584,6 +585,7 @@ class AppView extends connect(store)(LitElement) {
|
|||||||
</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>
|
||||||
|
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);
|
301
core/src/components/friends-view/profile-modal-update.js
Normal file
301
core/src/components/friends-view/profile-modal-update.js
Normal file
@ -0,0 +1,301 @@
|
|||||||
|
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-dialog';
|
||||||
|
import '@material/mwc-checkbox';
|
||||||
|
import { connect } from 'pwa-helpers';
|
||||||
|
import { store } from '../../store';
|
||||||
|
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
||||||
|
|
||||||
|
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}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isOpen = false;
|
||||||
|
this.isLoading = false;
|
||||||
|
this.nodeUrl = this.getNodeUrl();
|
||||||
|
this.myNode = this.getMyNode();
|
||||||
|
this.tagline = "";
|
||||||
|
this.bio = "",
|
||||||
|
this.walletList = [
|
||||||
|
"btcWallet", "ltcWallet", "dogeWallet","dgbWallet", "rvnWallet", "arrrWallet"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {}
|
||||||
|
|
||||||
|
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() {}
|
||||||
|
|
||||||
|
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);"
|
||||||
|
>
|
||||||
|
${get('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);"
|
||||||
|
>
|
||||||
|
${get('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>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
<button
|
||||||
|
?disabled="${this.isLoading}"
|
||||||
|
class="modal-button"
|
||||||
|
@click=${() => {
|
||||||
|
this.addFriend();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${translate('profile.profile3')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('profile-modal-update', ProfileModalUpdate);
|
672
core/src/components/friends-view/profile.js
Normal file
672
core/src/components/friends-view/profile.js
Normal file
@ -0,0 +1,672 @@
|
|||||||
|
import { LitElement, html, css } from 'lit';
|
||||||
|
import '@material/mwc-icon';
|
||||||
|
import './friends-side-panel.js';
|
||||||
|
import { connect } from 'pwa-helpers';
|
||||||
|
import { store } from '../../store.js';
|
||||||
|
import WebWorker2 from '../WebWorkerFile.js';
|
||||||
|
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
||||||
|
import '@vaadin/tooltip';
|
||||||
|
import { get, translate } from 'lit-translate';
|
||||||
|
import ShortUniqueId from 'short-unique-id';
|
||||||
|
|
||||||
|
import {
|
||||||
|
decryptGroupData,
|
||||||
|
encryptDataGroup,
|
||||||
|
objectToBase64,
|
||||||
|
uint8ArrayToBase64,
|
||||||
|
uint8ArrayToObject,
|
||||||
|
} from '../../../../plugins/plugins/core/components/qdn-action-encryption.js';
|
||||||
|
import { publishData } from '../../../../plugins/plugins/utils/publish-image.js';
|
||||||
|
import { parentEpml } from '../show-plugin.js';
|
||||||
|
import '../notification-view/popover.js';
|
||||||
|
import './avatar.js';
|
||||||
|
import { setNewTab } from '../../redux/app/app-actions.js';
|
||||||
|
import './profile-modal-update.js'
|
||||||
|
|
||||||
|
class ProfileQdn extends connect(store)(LitElement) {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
isOpen: { type: Boolean },
|
||||||
|
syncPercentage: { type: Number },
|
||||||
|
settingsRawData: { type: Object },
|
||||||
|
valuesToBeSavedOnQdn: { type: Object },
|
||||||
|
resourceExists: { type: Boolean },
|
||||||
|
isSaving: { type: Boolean },
|
||||||
|
fee: { type: Object },
|
||||||
|
name: { type: String },
|
||||||
|
isOpenProfileModalUpdate: {type: Boolean},
|
||||||
|
editContent: {type: Object}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.isOpen = false;
|
||||||
|
this.getProfile = this.getProfile.bind(this);
|
||||||
|
this._updateTempSettingsData = this._updateTempSettingsData.bind(this);
|
||||||
|
this.setValues = this.setValues.bind(this);
|
||||||
|
this.saveToQdn = this.saveToQdn.bind(this);
|
||||||
|
this.syncPercentage = 0;
|
||||||
|
this.hasRetrievedResource = false;
|
||||||
|
this.hasAttemptedToFetchResource = false;
|
||||||
|
this.resourceExists = undefined;
|
||||||
|
this.settingsRawData = null;
|
||||||
|
this.nodeUrl = this.getNodeUrl();
|
||||||
|
this.myNode = this.getMyNode();
|
||||||
|
this.valuesToBeSavedOnQdn = {};
|
||||||
|
this.isSaving = false;
|
||||||
|
this.fee = null;
|
||||||
|
this.name = undefined;
|
||||||
|
this.uid = new ShortUniqueId();
|
||||||
|
this.isOpenProfileModalUpdate = false
|
||||||
|
this.editContent = null
|
||||||
|
}
|
||||||
|
static styles = css`
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
visibility: hidden;
|
||||||
|
position: fixed;
|
||||||
|
z-index: -100;
|
||||||
|
right: -1000px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.parent-side-panel {
|
||||||
|
transform: translateX(100%); /* start from outside the right edge */
|
||||||
|
transition: transform 0.3s ease-in-out;
|
||||||
|
}
|
||||||
|
.parent-side-panel.open {
|
||||||
|
transform: translateX(0); /* slide in to its original position */
|
||||||
|
}
|
||||||
|
.notActive {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: default;
|
||||||
|
color: var(--black);
|
||||||
|
}
|
||||||
|
.active {
|
||||||
|
opacity: 1;
|
||||||
|
cursor: pointer;
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.accept-button {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 8px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--mdc-theme-primary);
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accept-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #03a8f485;
|
||||||
|
}
|
||||||
|
|
||||||
|
.undo-button {
|
||||||
|
font-family: Roboto, sans-serif;
|
||||||
|
letter-spacing: 0.3px;
|
||||||
|
font-weight: 300;
|
||||||
|
padding: 8px 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
text-align: center;
|
||||||
|
color: #f44336;
|
||||||
|
transition: all 0.3s ease-in-out;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.undo-button:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #f4433663;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAvatar(dataItem) {
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/${dataItem.service}/${dataItem.name}/${dataItem.identifier}?encoding=base64`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const data = await res.text();
|
||||||
|
if (data.error) throw new Error('Cannot retrieve your data from qdn');
|
||||||
|
const decryptedData = decryptGroupData(data);
|
||||||
|
const decryptedDataToBase64 = uint8ArrayToObject(decryptedData);
|
||||||
|
return decryptedDataToBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRawData(dataItem) {
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/${dataItem.service}/${dataItem.name}/${dataItem.identifier}?encoding=base64`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
const data = await res.text();
|
||||||
|
if (data.error) throw new Error('Cannot retrieve your data from qdn');
|
||||||
|
const decryptedData = decryptGroupData(data);
|
||||||
|
const decryptedDataToBase64 = uint8ArrayToObject(decryptedData);
|
||||||
|
return decryptedDataToBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getMyFollowedNames() {
|
||||||
|
let myFollowedNames = [];
|
||||||
|
try {
|
||||||
|
myFollowedNames = await parentEpml.request('apiCall', {
|
||||||
|
url: `/lists/followedNames?apiKey=${this.myNode.apiKey}`,
|
||||||
|
});
|
||||||
|
} catch (error) {}
|
||||||
|
|
||||||
|
return myFollowedNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
async followNames(names) {
|
||||||
|
let items = names;
|
||||||
|
let namesJsonString = JSON.stringify({ items: items });
|
||||||
|
|
||||||
|
let ret = await parentEpml.request('apiCall', {
|
||||||
|
url: `/lists/followedNames?apiKey=${this.myNode.apiKey}`,
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: `${namesJsonString}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
async setValues(response, resource) {
|
||||||
|
this.settingsRawData = response;
|
||||||
|
const rawDataTimestamp = resource.updated;
|
||||||
|
|
||||||
|
const tempSettingsData = JSON.parse(
|
||||||
|
localStorage.getItem('temp-settings-data') || '{}'
|
||||||
|
);
|
||||||
|
|
||||||
|
const userLists = response.userLists || [];
|
||||||
|
const friendsFeed = response.friendsFeed;
|
||||||
|
const myMenuPlugs = response.myMenuPlugs;
|
||||||
|
|
||||||
|
this.valuesToBeSavedOnQdn = {};
|
||||||
|
if (
|
||||||
|
userLists.length > 0 &&
|
||||||
|
(!tempSettingsData.userLists ||
|
||||||
|
(tempSettingsData.userLists &&
|
||||||
|
tempSettingsData.userLists.timestamp < rawDataTimestamp))
|
||||||
|
) {
|
||||||
|
const friendList = userLists[0];
|
||||||
|
const copyPayload = [...friendList];
|
||||||
|
const onlyNames = copyPayload.map((item) => item.name);
|
||||||
|
const followedList = await this.getMyFollowedNames();
|
||||||
|
|
||||||
|
const namesNotInFollowedList = onlyNames.filter(
|
||||||
|
(name) => !followedList.includes(name)
|
||||||
|
);
|
||||||
|
if (namesNotInFollowedList.length > 0) {
|
||||||
|
await this.followNames(namesNotInFollowedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem(
|
||||||
|
'friends-my-friend-list',
|
||||||
|
JSON.stringify(friendList)
|
||||||
|
);
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('friends-my-friend-list-event', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: copyPayload,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
tempSettingsData.userLists &&
|
||||||
|
tempSettingsData.userLists.timestamp > rawDataTimestamp
|
||||||
|
) {
|
||||||
|
this.valuesToBeSavedOnQdn = {
|
||||||
|
...this.valuesToBeSavedOnQdn,
|
||||||
|
userLists: {
|
||||||
|
data: tempSettingsData.userLists.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
friendsFeed &&
|
||||||
|
(!tempSettingsData.friendsFeed ||
|
||||||
|
(tempSettingsData.friendsFeed &&
|
||||||
|
tempSettingsData.friendsFeed.timestamp < rawDataTimestamp))
|
||||||
|
) {
|
||||||
|
const copyPayload = [...friendsFeed];
|
||||||
|
|
||||||
|
localStorage.setItem(
|
||||||
|
'friends-my-selected-feeds',
|
||||||
|
JSON.stringify(friendsFeed)
|
||||||
|
);
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('friends-my-selected-feeds-event', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: copyPayload,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
} else if (
|
||||||
|
tempSettingsData.friendsFeed &&
|
||||||
|
tempSettingsData.friendsFeed.timestamp > rawDataTimestamp
|
||||||
|
) {
|
||||||
|
this.valuesToBeSavedOnQdn = {
|
||||||
|
...this.valuesToBeSavedOnQdn,
|
||||||
|
friendsFeed: {
|
||||||
|
data: tempSettingsData.friendsFeed.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
myMenuPlugs &&
|
||||||
|
(!tempSettingsData.myMenuPlugs ||
|
||||||
|
(tempSettingsData.myMenuPlugs &&
|
||||||
|
tempSettingsData.myMenuPlugs.timestamp < rawDataTimestamp))
|
||||||
|
) {
|
||||||
|
if (Array.isArray(myMenuPlugs)) {
|
||||||
|
const copyPayload = [...myMenuPlugs];
|
||||||
|
|
||||||
|
localStorage.setItem(
|
||||||
|
'myMenuPlugs',
|
||||||
|
JSON.stringify(myMenuPlugs)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('myMenuPlugs-event', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
detail: copyPayload,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
tempSettingsData.myMenuPlugs &&
|
||||||
|
tempSettingsData.myMenuPlugs.timestamp > rawDataTimestamp
|
||||||
|
) {
|
||||||
|
this.valuesToBeSavedOnQdn = {
|
||||||
|
...this.valuesToBeSavedOnQdn,
|
||||||
|
myMenuPlugs: {
|
||||||
|
data: tempSettingsData.myMenuPlugs.data,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getProfile() {
|
||||||
|
try {
|
||||||
|
const arbFee = await this.getArbitraryFee();
|
||||||
|
this.fee = arbFee;
|
||||||
|
this.hasAttemptedToFetchResource = true;
|
||||||
|
let resource;
|
||||||
|
const nameObject = store.getState().app.accountInfo.names[0];
|
||||||
|
if (!nameObject) {
|
||||||
|
this.name = null;
|
||||||
|
throw new Error('no name');
|
||||||
|
}
|
||||||
|
const name = nameObject.name;
|
||||||
|
this.name = name;
|
||||||
|
this.error = '';
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/resources/search?service=DOCUMENT&identifier=qortal_profile&name=${name}&prefix=true&exactmatchnames=true&excludeblocked=true&limit=20`;
|
||||||
|
const res = await fetch(url);
|
||||||
|
let data = '';
|
||||||
|
try {
|
||||||
|
data = await res.json();
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
data = data.filter(
|
||||||
|
(item) => item.identifier === 'qortal_profile'
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.length > 0) {
|
||||||
|
this.resourceExists = true;
|
||||||
|
const dataItem = data[0];
|
||||||
|
try {
|
||||||
|
const response = await this.getRawData(dataItem);
|
||||||
|
if (response.version) {
|
||||||
|
// this.setValues(response, dataItem);
|
||||||
|
} else {
|
||||||
|
this.error = 'Cannot get saved user settings';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error });
|
||||||
|
this.error = 'Cannot get saved user settings';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.resourceExists = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.error = 'Unable to perform query';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
data = {
|
||||||
|
error: 'No resource found',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource) {
|
||||||
|
this.hasRetrievedResource = true;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChanged(state) {
|
||||||
|
if (
|
||||||
|
state.app.accountInfo &&
|
||||||
|
state.app.accountInfo.names.length &&
|
||||||
|
state.app.nodeStatus &&
|
||||||
|
state.app.nodeStatus.syncPercent !== this.syncPercentage
|
||||||
|
) {
|
||||||
|
this.syncPercentage = state.app.nodeStatus.syncPercent;
|
||||||
|
|
||||||
|
if (
|
||||||
|
!this.hasAttemptedToFetchResource &&
|
||||||
|
state.app.nodeStatus.syncPercent === 100
|
||||||
|
) {
|
||||||
|
this.getProfile();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getArbitraryFee() {
|
||||||
|
const timestamp = Date.now();
|
||||||
|
const url = `${this.nodeUrl}/transactions/unitfee?txType=ARBITRARY×tamp=${timestamp}`;
|
||||||
|
const response = await fetch(url);
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Error when fetching arbitrary fee');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
const arbitraryFee = (Number(data) / 1e8).toFixed(8);
|
||||||
|
return {
|
||||||
|
timestamp,
|
||||||
|
fee: Number(data),
|
||||||
|
feeToShow: arbitraryFee,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveToQdn() {
|
||||||
|
try {
|
||||||
|
this.isSaving = true;
|
||||||
|
if (this.resourceExists === true && this.error)
|
||||||
|
throw new Error('Unable to save');
|
||||||
|
|
||||||
|
const nameObject = store.getState().app.accountInfo.names[0];
|
||||||
|
if (!nameObject) throw new Error('no name');
|
||||||
|
const name = nameObject.name;
|
||||||
|
const identifer = 'qortal_general_settings';
|
||||||
|
const filename = 'qortal_general_settings.json';
|
||||||
|
const selectedAddress = store.getState().app.selectedAddress;
|
||||||
|
const getArbitraryFee = await this.getArbitraryFee();
|
||||||
|
const feeAmount = getArbitraryFee.fee;
|
||||||
|
const friendsList = JSON.parse(
|
||||||
|
localStorage.getItem('friends-my-friend-list') || '[]'
|
||||||
|
);
|
||||||
|
const friendsFeed = JSON.parse(
|
||||||
|
localStorage.getItem('friends-my-selected-feeds') || '[]'
|
||||||
|
);
|
||||||
|
const myMenuPlugs = JSON.parse(
|
||||||
|
localStorage.getItem('myMenuPlugs') || '[]'
|
||||||
|
);
|
||||||
|
|
||||||
|
let newObject;
|
||||||
|
|
||||||
|
if (this.resourceExists === false) {
|
||||||
|
newObject = {
|
||||||
|
version: 1,
|
||||||
|
userLists: [friendsList],
|
||||||
|
friendsFeed,
|
||||||
|
myMenuPlugs,
|
||||||
|
};
|
||||||
|
} else if (this.settingsRawData) {
|
||||||
|
const tempSettingsData = JSON.parse(
|
||||||
|
localStorage.getItem('temp-settings-data') || '{}'
|
||||||
|
);
|
||||||
|
newObject = {
|
||||||
|
...this.settingsRawData,
|
||||||
|
};
|
||||||
|
for (const key in tempSettingsData) {
|
||||||
|
if (tempSettingsData[key].hasOwnProperty('data')) {
|
||||||
|
if (
|
||||||
|
key === 'userLists' &&
|
||||||
|
!Array.isArray(tempSettingsData[key].data)
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
if (
|
||||||
|
key === 'friendsFeed' &&
|
||||||
|
!Array.isArray(tempSettingsData[key].data)
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
if (
|
||||||
|
key === 'myMenuPlugs' &&
|
||||||
|
!Array.isArray(tempSettingsData[key].data)
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
newObject[key] = tempSettingsData[key].data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newObjectToBase64 = await objectToBase64(newObject);
|
||||||
|
const encryptedData = encryptDataGroup({
|
||||||
|
data64: newObjectToBase64,
|
||||||
|
publicKeys: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const worker = new WebWorker2();
|
||||||
|
try {
|
||||||
|
const resPublish = await publishData({
|
||||||
|
registeredName: encodeURIComponent(name),
|
||||||
|
file: encryptedData,
|
||||||
|
service: 'DOCUMENT_PRIVATE',
|
||||||
|
identifier: encodeURIComponent(identifer),
|
||||||
|
parentEpml: parentEpml,
|
||||||
|
uploadType: 'file',
|
||||||
|
selectedAddress: selectedAddress,
|
||||||
|
worker: worker,
|
||||||
|
isBase64: true,
|
||||||
|
filename: filename,
|
||||||
|
apiVersion: 2,
|
||||||
|
withFee: true,
|
||||||
|
feeAmount: feeAmount,
|
||||||
|
});
|
||||||
|
|
||||||
|
this.resourceExists = true;
|
||||||
|
this.setValues(newObject, {
|
||||||
|
updated: Date.now(),
|
||||||
|
});
|
||||||
|
localStorage.setItem('temp-settings-data', JSON.stringify({}));
|
||||||
|
this.valuesToBeSavedOnQdn = {};
|
||||||
|
worker.terminate();
|
||||||
|
} catch (error) {
|
||||||
|
worker.terminate();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error });
|
||||||
|
} finally {
|
||||||
|
this.isSaving = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateTempSettingsData() {
|
||||||
|
this.valuesToBeSavedOnQdn = JSON.parse(
|
||||||
|
localStorage.getItem('temp-settings-data') || '{}'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback();
|
||||||
|
window.addEventListener(
|
||||||
|
'temp-settings-data-event',
|
||||||
|
this._updateTempSettingsData
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
window.removeEventListener(
|
||||||
|
'temp-settings-data-event',
|
||||||
|
this._updateTempSettingsData
|
||||||
|
);
|
||||||
|
super.disconnectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
publishProfile(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose(){
|
||||||
|
this.isOpenProfileModalUpdate = false
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
console.log('sup profile2', this.name);
|
||||||
|
return html`
|
||||||
|
${this.isSaving ||
|
||||||
|
(!this.error && this.resourceExists === undefined)
|
||||||
|
? html`
|
||||||
|
<paper-spinner-lite
|
||||||
|
active
|
||||||
|
style="display: block; margin: 0 auto;"
|
||||||
|
></paper-spinner-lite>
|
||||||
|
`
|
||||||
|
: !this.name
|
||||||
|
? html`
|
||||||
|
<mwc-icon
|
||||||
|
id="profile-icon"
|
||||||
|
class=${Object.values(this.valuesToBeSavedOnQdn)
|
||||||
|
.length > 0 || this.resourceExists === false
|
||||||
|
? 'active'
|
||||||
|
: '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"
|
||||||
|
>account_circle</mwc-icon
|
||||||
|
>
|
||||||
|
<vaadin-tooltip
|
||||||
|
for="profile-icon"
|
||||||
|
position="bottom"
|
||||||
|
hover-delay=${300}
|
||||||
|
hide-delay=${1}
|
||||||
|
text=${this.error
|
||||||
|
? get('save.saving1')
|
||||||
|
: Object.values(this.valuesToBeSavedOnQdn)
|
||||||
|
.length > 0 ||
|
||||||
|
this.resourceExists === false
|
||||||
|
? get('save.saving3')
|
||||||
|
: get('save.saving2')}
|
||||||
|
>
|
||||||
|
</vaadin-tooltip>
|
||||||
|
<popover-component for="profile-icon" message="">
|
||||||
|
<div style="margin-bottom:20px">
|
||||||
|
<p style="margin:10px 0px; font-size:16px">
|
||||||
|
${`${get('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`
|
||||||
|
<div style="user-select:none;cursor:pointer" @click=${()=> {
|
||||||
|
this.isOpenProfileModalUpdate = !this.isOpenProfileModalUpdate
|
||||||
|
}}>
|
||||||
|
<avatar-component
|
||||||
|
.resource=${{
|
||||||
|
name: this.name,
|
||||||
|
service: 'THUMBNAIL',
|
||||||
|
identifier: 'qortal_avatar',
|
||||||
|
}}
|
||||||
|
name=${this.name}
|
||||||
|
></avatar-component>
|
||||||
|
</div>
|
||||||
|
`}
|
||||||
|
|
||||||
|
<profile-modal-update
|
||||||
|
?isOpen=${this.isOpenProfileModalUpdate}
|
||||||
|
.setIsOpen=${(val)=> {
|
||||||
|
this.isOpenProfileModalUpdate = val
|
||||||
|
}}
|
||||||
|
.onSubmit=${(val, isEdit)=> this.publishProfile(val, isEdit)}
|
||||||
|
.editContent=${this.editContent}
|
||||||
|
.onClose=${()=> this.onClose()}
|
||||||
|
></profile-modal-update>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
customElements.define('profile-qdn', ProfileQdn);
|
@ -3,12 +3,13 @@ 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 { get, translate } from 'lit-translate';
|
import { get, translate } from 'lit-translate';
|
||||||
import {
|
import {
|
||||||
decryptGroupData,
|
decryptGroupData,
|
||||||
|
|
||||||
encryptDataGroup,
|
encryptDataGroup,
|
||||||
objectToBase64,
|
objectToBase64,
|
||||||
uint8ArrayToBase64,
|
uint8ArrayToBase64,
|
||||||
|
@ -337,6 +337,7 @@ class ShowPlugin extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
console.log('this.tabs', this.tabs)
|
||||||
const plugSrc = (myPlug) => {
|
const plugSrc = (myPlug) => {
|
||||||
return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}`
|
return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}`
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user