4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-11 17:55:51 +00:00

Merge pull request #56 from Qortal/master

Import
This commit is contained in:
AlphaX-Projects 2022-08-22 18:16:15 +02:00 committed by GitHub
commit 1e0226d82f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 1329 additions and 8 deletions

View File

@ -17,7 +17,7 @@ class SidenavMenu extends connect(store)(LitElement) {
urls: { type: Object },
nodeType: { type: String, reflect: true },
theme: { type: String, reflect: true },
addressInfo: { type: Object },
addressInfo: { type: Object }
};
}
@ -102,6 +102,7 @@ class SidenavMenu extends connect(store)(LitElement) {
renderNodeTypeMenu() {
const addressInfo = this.addressInfo;
const isMinter = addressInfo?.error !== 124 && +addressInfo?.level > 0;
const isSponsor = +addressInfo?.level >= 5
if (this.nodeType === 'lite') {
return html`
@ -151,7 +152,16 @@ class SidenavMenu extends connect(store)(LitElement) {
href="/app/become-minter"
>
<vaadin-icon icon="vaadin:thumbs-up" slot="icon"></vaadin-icon>
</side-menu-item>`}
</side-menu-item>`
}
${isSponsor ? html`
<side-menu-item
label="${translate('mintingpage.mchange35')}"
href="/app/sponsorship-list"
>
<vaadin-icon icon="vaadin:list-ol" slot="icon"></vaadin-icon>
</side-menu-item>
` : ''}
</side-menu-item>
<side-menu-item
label="${translate('sidemenu.wallets')}"
@ -190,6 +200,12 @@ class SidenavMenu extends connect(store)(LitElement) {
>
<vaadin-icon icon="vaadin:desktop" slot="icon" ></vaadin-icon>
</side-menu-item>
<side-menu-item
label="${translate('sidemenu.puzzles')}"
href="/app/puzzles"
>
<vaadin-icon icon="vaadin:puzzle-piece" slot="icon"></vaadin-icon>
</side-menu-item>
<side-menu-item
label="${translate('sidemenu.management')}"
expanded
@ -209,12 +225,6 @@ class SidenavMenu extends connect(store)(LitElement) {
</side-menu-item>
${this.renderNodeManagement()}
</side-menu-item>
<side-menu-item
label="${translate('sidemenu.puzzles')}"
href="/app/puzzles"
>
<vaadin-icon icon="vaadin:puzzle-piece" slot="icon"></vaadin-icon>
</side-menu-item>
`;
}
}

View File

@ -45,6 +45,7 @@ export const sideMenuItemStyle = css`
overflow: hidden;
text-decoration: none;
border-bottom: 1px solid var(--item-border-color);
text-transform: uppercase;
}
#itemLink:hover {

View File

@ -125,6 +125,10 @@ const generateForPlugins = () => {
in: 'plugins/core/become-minter/become-minter.src.js',
out: 'plugins/core/become-minter/become-minter.js',
},
{
in: 'plugins/core/sponsorship-list/sponsorship-list.src.js',
out: 'plugins/core/sponsorship-list/sponsorship-list.js',
},
{
in: 'plugins/core/puzzles/puzzles.src.js',
out: 'plugins/core/puzzles/puzzles.js',

View File

@ -50,6 +50,7 @@
"@vaadin/grid": "23.1.5",
"@vaadin/icons": "23.1.5",
"epml": "0.3.3",
"file-saver": "2.0.5",
"html-escaper": "3.0.3",
"lit": "2.3.0",
"lit-translate": "2.0.1",

View File

@ -0,0 +1,162 @@
function saveFile({ data, debug, filename }) {
if (debug) console.log("[qortal-file-saver] starting with ", { data, debug, filename });
if (!data) throw new Error("[qortal-file-saver] You must pass in data");
if (!filename) {
if (typeof window !== "undefined" && typeof File !== undefined && data instanceof File) {
filename = data.name;
}
throw new Error("[qortal-file-saver] You must pass in filename");
}
const constructorName = (typeof data === "object" && typeof data.constructor === "function" && data.constructor.name) || null;
if (debug) console.log("constructorName:", constructorName);
const ext = filename.substr(filename.lastIndexOf(".")).toLowerCase();
const A = ({ href, download }) => {
const a = document.createElement("a");
a.href = href;
a.download = download;
return a;
};
function convertImageToCanvas({ debug, img }) {
if (debug) console.log("[qortal-file-saver] starting convertImageToCanvas");
const height = img.height;
const width = img.width;
const canvas = document.createElement("canvas");
canvas.height = height;
canvas.width = width;
const context = canvas.getContext("2d");
context.drawImage(img, 0, 0, width, height);
return canvas;
}
function saveHTML({ data, debug, filename }) {
if (typeof data === "object" && "outerHTML" in data) {
if (debug) console.log("[qortal-file-saver] data appears to be an HTML element, so grabbing it's outer HTML");
data = data.outerHTML;
}
const url = "data:text/html," + encodeURIComponent(data);
saveDataOrBlobURL({ url, debug, filename });
}
function saveCanvas({ data, debug, filename, imageType }) {
const url = data.toDataURL("image/" + imageType);
saveDataOrBlobURL({ url, debug, filename });
}
function saveDataOrBlobURL({ url, debug, filename }) {
A({ href: url, download: filename }).click();
}
function saveImageAsJPG({ data: img, debug, filename }) {
if (debug) console.log("starting saveImageAsJPG");
const canvas = convertImageToCanvas({ debug, img });
saveCanvasAsJPG({ data: canvas, debug, filename });
}
function saveImageAsPNG({ data: img, debug, filename }) {
if (debug) console.log("starting saveImageAsPNG");
const canvas = convertImageToCanvas({ debug, img });
saveCanvasAsPNG({ data: canvas, debug, filename });
}
function saveImageAsWebP({ data: img, debug, filename }) {
if (debug) console.log("starting saveImageAsWebP");
const canvas = convertImageToCanvas({ debug, img });
saveCanvasAsWebP({ data: canvas, debug, filename });
}
function saveCanvasAsJPG({ data, debug, filename }) {
saveCanvas({ data, debug, filename, imageType: "jpeg" });
}
function saveCanvasAsPNG({ data, debug, filename }) {
saveCanvas({ data, debug, filename, imageType: "png" });
}
function saveCanvasAsWebP({ data, debug, filename }) {
saveCanvas({ data, debug, filename, imageType: "webp" });
}
function saveDSV({ data, debug, delimiter, filename, mediatype }) {
if (!Array.isArray(data)) throw new Error("[qortal-saver] data must be an array to save as a CSV");
if (!delimiter) throw new Error("[qortal-saver] delimiter must be set");
if (!mediatype) throw new Error("[qortal-saver] mediatype must be set");
let output = "data:" + mediatype + ";charset=utf-8,";
const columns = Array.from(new Set(data.map(Object.keys).flat())).sort();
const types = new Set(data.map(it => (Array.isArray(it) ? "array" : typeof it)));
const includeHeader = types.has("object");
if (debug) console.log("includeHeader:", includeHeader);
if (includeHeader) output += columns.map(c => '"' + c.replace(/,/g, "\\,") + '"') + "\n";
for (let i = 0; i < data.length; i++) {
const row = data[i];
if (i !== 0) output += "\n";
output += columns.map(col => '"' + row[col].toString().replace(/,/g, "\\,") + '"');
}
const url = encodeURI(output);
saveDataOrBlobURL({ url, debug, filename });
}
function saveCSV({ data, debug, filename }) {
saveDSV({ data, debug, delimiter: ",", filename, mediatype: "text/csv" });
}
function saveTSV({ data, debug, filename }) {
saveDSV({ data, debug, delimiter: "\t", filename, mediatype: "text/tab-separated-values" });
}
function saveJSON({ data, debug, filename }) {
const url = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data, undefined, 2));
saveDataOrBlobURL({ url, debug, filename });
}
function saveText({ data, debug, filename }) {
const url = "data:text/plain;charset=utf-8," + encodeURIComponent(data);
saveDataOrBlobURL({ url, debug, filename });
}
function saveBlob({ data, debug, filename }) {
const url = URL.createObjectURL(data);
if (debug) console.log("[qortal-file-saver.saveBlob] url:", url);
saveDataOrBlobURL({ url, debug, filename });
URL.revokeObjectURL(url);
}
if (ext === ".csv") {
saveCSV({ data, debug, filename });
} else if (ext === ".tsv") {
saveTSV({ data, debug, filename });
} else if (ext === ".html") {
saveHTML({ data, debug, filename });
} else if (ext === ".json" || ext === ".geojson" || ext === ".topojson") {
saveJSON({ data, debug, filename });
} else if (ext === ".txt" || ext === ".js" || ext === ".py") {
saveText({ data, debug, filename });
} else if (constructorName === "HTMLCanvasElement" && ext === ".png") {
saveCanvasAsPNG({ data, debug, filename });
} else if (constructorName === "HTMLCanvasElement" && ext === ".jpg") {
saveCanvasAsJPG({ data, debug, filename });
} else if (constructorName === "HTMLCanvasElement" && ext === ".webp") {
saveCanvasAsWebP({ data, debug, filename });
} else if (constructorName === "HTMLImageElement" && ext === ".jpg") {
saveImageAsJPG({ data, debug, filename });
} else if (constructorName === "HTMLImageElement" && ext === ".png") {
saveImageAsPNG({ data, debug, filename });
} else if (constructorName === "HTMLImageElement" && ext === ".webp") {
saveImageAsWebP({ data, debug, filename });
} else if (constructorName === "Blob") {
saveBlob({ data, debug, filename });
} else {
throw new Error('[qortal-file-saver] unrecognized extension "' + ext + '"');
}
}
if (typeof define === "function" && define.amd)
define(function () {
return saveFile;
});
if (typeof module === "object") module.exports = saveFile;
if (typeof window === "object") window.saveFile = saveFile;
if (typeof self === "object") self.saveFile = saveFile;

View File

@ -0,0 +1,115 @@
import { LitElement, html, css } from 'lit'
import '@material/mwc-button'
import '@material/mwc-icon'
import { translate, translateUnsafeHTML } from 'lit-translate'
class FragFileInput extends LitElement {
static get properties () {
return {
accept: { type: String },
readAs: { type: String }
}
}
static get styles () {
return css`
#drop-area {
border: 2px dashed #ccc;
font-family: "Roboto", sans-serif;
padding: 20px;
}
#trigger:hover {
cursor: pointer;
}
#drop-area.highlight {
border-color: var(--mdc-theme-primary, #000);
}
p {
margin-top: 0;
}
form {
margin-bottom: 10px;
}
#fileInput {
display: none;
}
`
}
constructor () {
super()
this.readAs = this.readAs || 'Text'
}
render () {
return html`
<div id="drop-area">
<slot name="info-text"></slot>
<div style="line-height: 40px; text-align: center;">
<slot id="trigger" name="inputTrigger" @click=${() => this.shadowRoot.getElementById('fileInput').click()} style="dispay:inline;">
<mwc-button><mwc-icon>cloud_upload</mwc-icon><span style="color: var(--black);">&nbsp; ${translate("fragfile.selectfile")}</span></mwc-button>
</slot><br>
<span style="text-align: center; padding-top: 4px; color: var(--black);">${translate("fragfile.dragfile")}</span>
</div>
</div>
<input type="file" id="fileInput" accept="${this.accept}" @change="${e => this.readFile(e.target.files[0])}">
`
}
readFile (file) {
const fr = new FileReader()
fr.onload = () => {
this.dispatchEvent(new CustomEvent('file-read-success', {
detail: { result: fr.result },
bubbles: true,
composed: true
}))
}
fr['readAs' + this.readAs](file)
}
firstUpdated () {
this._dropArea = this.shadowRoot.getElementById('drop-area')
const preventDefaults = e => {
e.preventDefault()
e.stopPropagation()
}
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
this._dropArea.addEventListener(eventName, preventDefaults, false)
})
const highlight = e => {
this._dropArea.classList.add('highlight')
}
const unhighlight = e => {
this._dropArea.classList.remove('highlight')
}
;['dragenter', 'dragover'].forEach(eventName => {
this._dropArea.addEventListener(eventName, highlight, false)
})
;['dragleave', 'drop'].forEach(eventName => {
this._dropArea.addEventListener(eventName, unhighlight, false)
})
this._dropArea.addEventListener('drop', e => {
const dt = e.dataTransfer
const file = dt.files[0]
this.readFile(file)
}, false)
}
}
window.customElements.define('frag-file-input', FragFileInput)

View File

@ -25,6 +25,15 @@ parentEpml.ready().then(() => {
menus: [],
parent: false,
},
{
url: 'sponsorship-list',
domain: 'core',
page: 'sponsorship-list/index.html',
title: 'Become a Minter',
icon: 'vaadin:info-circle',
menus: [],
parent: false,
},
{
url: 'wallet',
domain: 'core',

View File

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/font/material-icons.css" />
<link rel="stylesheet" href="/font/switch-theme.css" />
<script>
const checkBack = localStorage.getItem('qortalTheme');
if (checkBack === 'dark') {
newtheme = 'dark';
} else {
newtheme = 'light';
}
document.querySelector('html').setAttribute('theme', newtheme);
</script>
<style>
html {
--scrollbarBG: #a1a1a1;
--thumbBG: #6a6c75;
}
*::-webkit-scrollbar {
width: 11px;
}
* {
scrollbar-width: thin;
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
}
*::-webkit-scrollbar-track {
background: var(--scrollbarBG);
}
*::-webkit-scrollbar-thumb {
background-color: var(--thumbBG);
border-radius: 6px;
border: 3px solid var(--scrollbarBG);
}
html,
body {
margin: 0;
font-family: 'Roboto', sans-serif;
background: var(--plugback);
}
</style>
</head>
<body>
<sponsorship-list></sponsorship-list>
<script src="sponsorship-list.js"></script>
</body>
</html>

View File

@ -0,0 +1,359 @@
import { css } from "lit"
export const pageStyles = css`
* {
--mdc-theme-surface: var(--white);
--mdc-dialog-content-ink-color: var(--black);
box-sizing: border-box;
}
.header-title {
font-size: 40px;
color: var(--black);
font-weight: 400;
text-align: center;
}
.divider {
color: #eee;
border-radius: 80%;
margin-bottom: 2rem;
}
.fullWidth {
width: 100%;
}
.page-container {
display: flex;
align-items: center;
flex-direction: column;
margin-bottom: 75px;
}
.inner-container {
display: flex;
align-items: center;
flex-direction: column;
width: 95%;
max-width: 1100px;
}
.message {
color: var(--gray);
}
.form-wrapper {
display: flex;
align-items: center;
width: 100%;
max-width: 700px;
height: 50px;
flex-wrap: wrap;
}
.sponsor-minter-text {
color: var(--black);
font-weight: bold;
margin-right: 15px;
font-size: 18px;
}
.row {
display: flex;
width: 100%;
}
.column {
display: flex;
flex-direction: column;
width: 100%;
}
.column-center {
align-items: center;
}
.no-margin {
margin: 0;
}
.no-wrap {
flex-wrap: nowrap !important;
}
.row-center {
justify-content: center;
flex-wrap: wrap;
}
.form-item {
display: flex;
height: 100%;
}
.form-item--button {
flex-grow: 0;
}
.form-item--input {
flex-grow: 1;
margin-right: 25px;
min-width: 275px;
}
.gap {
gap: 10px;
}
.title {
font-weight: 600;
font-size: 20px;
line-height: 28px;
opacity: 0.66;
color: var(--switchborder);
}
.address {
overflow-wrap: anywhere;
color: var(--black);
}
h4 {
font-weight: 600;
font-size: 20px;
line-height: 28px;
color: var(--black);
}
mwc-textfield {
width: 100%;
}
vaadin-button {
height: 100%;
margin: 0;
cursor: pointer;
outline: 1px var(--black) solid;
min-width: 80px;
}
.loader,
.loader:after {
border-radius: 50%;
width: 10em;
height: 10em;
}
.loadingContainer {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 10;
}
.backdrop {
height: 100vh;
width: 100vw;
opacity: 0.6;
background-color: var(--border);
z-index: 9;
position: fixed;
}
.loading,
.loading:after {
border-radius: 50%;
width: 5em;
height: 5em;
}
.loading {
margin: 10px auto;
border-width: 0.6em;
border-style: solid;
border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2)
rgba(3, 169, 244, 0.2) rgb(3, 169, 244);
font-size: 10px;
position: relative;
text-indent: -9999em;
transform: translateZ(0px);
animation: 1.1s linear 0s infinite normal none running loadingAnimation;
}
@-webkit-keyframes loadingAnimation {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes loadingAnimation {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.tableGrid {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(
0,
1fr
) minmax(0, 1fr);
align-items: center;
gap: 5px;
width: 100%;
margin-bottom: 15px;
padding: 5px;
}
.grid-item {
text-align: center;
color: var(--black);
word-break: break-all;
overflow: hidden;
}
.text {
color: var(--black)
}
.text--bold {
font-weight: bold;
}
.summary-box {
display: flex;
margin-top: 25px;
width: 100%;
flex-wrap: wrap;
}
.summary-box p:first-child {
margin-right: 30px;
}
.text--normal {
font-weight: normal;
}
.grid-item p {
text-decoration: underline;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.red {
--mdc-theme-primary: #f44336;
border-radius: 2px;
}
.btn--sponsorshipfinished {
background-color: var(--menuactive);
transition: all .2s;
animation: onOff 2s infinite;
--mdc-theme-primary: var(--black);
}
.dialog-container {
width: 300px;
min-height: 300px;
max-height: 75vh;
padding: 5px;
display: flex;
align-items: flex-start;
flex-direction: column;
}
.dialog-paragraph {
word-break: break-all;
color: var(--black)
}
.dialog-header h1 {
font-size: 18px;
}
@keyframes onOff {
from {opacity: 1}
to {opacity: .5}
}
.grid-item-text {
display: none;
}
.sub-title {
margin-bottom: 10px;
}
.sub-title p {
font-size: 18px;
color: var(--black);
}
@media (max-width: 610px) {
.sponsor-minter-wrapper {
width: 100%;
margin-bottom: 10px;
}
.form-item--input {
flex-grow: 1;
margin-right: 25px;
min-width: unset;
}
}
@media (max-width: 710px) {
.table-header {
display: none;
}
.grid-item-text {
display: inline;
color: var(--black);
text-decoration: none;
margin: 0px;
margin-right: 10px;
}
.grid-item {
text-align: start;
align-items: center;
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
}
.grid-item p {
text-decoration: none;
}
.tableGrid {
grid-template-columns: minmax(0, 1fr);
border-radius: 5px;
border: 1px solid var(--black);
padding: 10px;
margin-bottom: 20px;
}
mwc-button {
grid-column: 1 / -1;
}
}
`

View File

@ -0,0 +1,607 @@
import { LitElement, html } from "lit"
import { Epml } from "../../../epml.js"
import "../components/ButtonIconCopy.js"
import { use, get, translate, registerTranslateConfig } from "lit-translate"
import { blocksNeed } from "../../utils/blocks-needed.js"
import "../components/ButtonIconCopy.js"
registerTranslateConfig({
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json()),
})
import "@polymer/paper-spinner/paper-spinner-lite.js"
import "@material/mwc-button"
import "@material/mwc-textfield"
import "@vaadin/button"
import "@material/mwc-button"
import "@polymer/paper-spinner/paper-spinner-lite.js"
import '@material/mwc-dialog'
import { pageStyles } from "./sponsorship-list-css.src.js"
const parentEpml = new Epml({ type: "WINDOW", source: window.parent })
class SponsorshipList extends LitElement {
static get properties() {
return {
theme: { type: String, reflect: true },
nodeInfo: { type: Object },
isPageLoading: { type: Boolean },
addressInfo: { type: Object },
rewardSharePublicKey: { type: String },
mintingAccountData: { type: Array },
sponsorships: { type: Array },
removeRewardShareLoading: { type: Array },
createSponsorshipMessage: { type: String },
isLoadingCreateSponsorship: { type: Array },
publicKeyValue: { type: String },
error: { type: Boolean },
isOpenModal: {type: Boolean}
}
}
static styles = [pageStyles]
constructor() {
super()
this.theme = localStorage.getItem("qortalTheme")
? localStorage.getItem("qortalTheme")
: "light"
this.isPageLoading = true
this.nodeInfo = {}
this.addressInfo = {}
this.rewardSharePublicKey = ""
this.mintingAccountData = null
this.sponsorships = []
this.removeRewardShareLoading = false
this.error = false
this.createSponsorshipMessage = ""
this.isLoadingCreateSponsorship = false
this.publicKeyValue = ""
this.isOpenModal = false
}
inputHandler(e) {
this.publicKeyValue = e.target.value
}
changeLanguage() {
const checkLanguage = localStorage.getItem("qortalLanguage")
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem("qortalLanguage", "us")
use("us")
} else {
use(checkLanguage)
}
}
_handleStorage() {
const checkLanguage = localStorage.getItem("qortalLanguage")
const checkTheme = localStorage.getItem("qortalTheme")
use(checkLanguage)
if (checkTheme === "dark") {
this.theme = "dark"
} else {
this.theme = "light"
}
document.querySelector("html").setAttribute("theme", this.theme)
}
connectedCallback() {
super.connectedCallback()
window.addEventListener("storage", this._handleStorage)
}
disconnectedCallback() {
window.removeEventListener("storage", this._handleStorage)
super.disconnectedCallback()
}
async getNodeInfo() {
const nodeInfo = await parentEpml.request("apiCall", {
url: `/admin/status`,
})
return nodeInfo
}
async atMount() {
this.changeLanguage()
this.addressInfo =
window.parent.reduxStore.getState().app.accountInfo.addressInfo
this.isPageLoading = true
try {
const address =
window.parent.reduxStore.getState().app?.selectedAddress
?.address
let rewardShares = await this.getRewardShareRelationship(
address
)
rewardShares = rewardShares.filter((rs) => rs.recipient !== address)
const getAccountInfo = rewardShares.map(async (rs) => {
const addressInfo = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/${rs.recipient}`,
})
let blocksRemaining = this._levelUpBlocks(addressInfo)
blocksRemaining = +blocksRemaining > 0 ? +blocksRemaining : 0
return {
...addressInfo,
...rs,
blocksRemaining: blocksRemaining,
}
})
const accountInfoValues = await Promise.all(getAccountInfo)
this.sponsorships = accountInfoValues
this.nextSponsorshipEnding = accountInfoValues
.filter((sponsorship) => sponsorship.blocksRemaining !== 0)
.sort((a, b) => a.blocksRemaining - b.blocksRemaining)[0]
this.isPageLoading = false
const openModal = accountInfoValues.find(s=> s.blocksRemaining <= 0)
if(openModal){
this.shadowRoot.querySelector('#showDialog').show()
}
} catch (error) {
this.isPageLoading = false
}
}
async firstUpdated() {
await this.atMount()
}
async getRewardShareRelationship(recipientAddress) {
const myRewardShareArray = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/rewardshares?minters=${recipientAddress}`,
})
return myRewardShareArray
}
_levelUpBlocks(accountInfo) {
let countBlocksString = (
blocksNeed(0) -
(accountInfo?.blocksMinted + accountInfo?.blocksMintedAdjustment)
).toString()
return countBlocksString
}
async removeRewardShare(rewardShareObject) {
const selectedAddress =
window.parent.reduxStore.getState().app?.selectedAddress
const myPercentageShare = -1
// Check for valid...
this.removeRewardShareLoading = true
// Get Last Ref
const getLastRef = async () => {
let myRef = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/lastreference/${selectedAddress?.address}`,
})
return myRef
}
// Remove Reward Share
const removeReceiver = async () => {
let lastRef = await getLastRef()
let myTransaction = await makeTransactionRequest(lastRef)
getTxnRequestResponse(myTransaction)
}
// Make Transaction Request
const makeTransactionRequest = async (lastRef) => {
let mylastRef = lastRef
let rewarddialog5 = get("transactions.rewarddialog5")
let rewarddialog6 = get("transactions.rewarddialog6")
let myTxnrequest = await parentEpml.request("transaction", {
type: 381,
nonce: selectedAddress?.nonce,
params: {
rewardShareKeyPairPublicKey:
rewardShareObject.rewardSharePublicKey,
recipient: rewardShareObject.recipient,
percentageShare: myPercentageShare,
lastReference: mylastRef,
rewarddialog5: rewarddialog5,
rewarddialog6: rewarddialog6,
},
})
return myTxnrequest
}
const getTxnRequestResponse = (txnResponse) => {
if (txnResponse.success === false && txnResponse.message) {
this.removeRewardShareLoading = false
parentEpml.request("showSnackBar", txnResponse.message)
throw new Error(txnResponse)
} else if (
txnResponse.success === true &&
!txnResponse.data.error
) {
let err7tring = get("rewardsharepage.rchange22")
this.removeRewardShareLoading = false
parentEpml.request("showSnackBar", `${err7tring}`)
this.sponsorships = this.sponsorships.filter((s)=> s.address !== rewardShareObject.address)
} else {
this.removeRewardShareLoading = false
parentEpml.request("showSnackBar", txnResponse.data.message)
throw new Error(txnResponse)
}
}
removeReceiver()
}
async createRewardShare(e) {
this.error = false
this.createSponsorshipMessage = ""
const recipientPublicKey = this.publicKeyValue
const percentageShare = 0
const selectedAddress =
window.parent.reduxStore.getState().app?.selectedAddress
// Check for valid...
this.isLoadingCreateSponsorship = true
let recipientAddress =
window.parent.base58PublicKeyToAddress(recipientPublicKey)
// Get Last Ref
const getLastRef = async () => {
let myRef = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/lastreference/${selectedAddress.address}`,
})
return myRef
}
// Get Account Details
const getAccountDetails = async () => {
let myAccountDetails = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/${selectedAddress.address}`,
})
return myAccountDetails
}
// Get Reward Relationship if it already exists
const getRewardShareRelationship = async (minterAddr) => {
let isRewardShareExisting = false
let myRewardShareArray = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/rewardshares?minters=${minterAddr}&recipients=${recipientAddress}`,
})
isRewardShareExisting =
myRewardShareArray.length !== 0 ? true : false
return isRewardShareExisting
}
// Validate Reward Share by Level
const validateReceiver = async () => {
let accountDetails = await getAccountDetails()
let lastRef = await getLastRef()
let isExisting = await getRewardShareRelationship(
selectedAddress.address
)
// Check for creating self share at different levels (also adding check for flags...)
if (accountDetails.flags === 1) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
this.error = true
this.createSponsorshipMessage = `Cannot Create Multiple Reward Shares!`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else if (accountDetails.address === recipientAddress) {
if (accountDetails.level >= 1 && accountDetails.level <= 4) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
let err1string = get("rewardsharepage.rchange18")
this.error = true
this.createSponsorshipMessage = `${err1string}`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else if (accountDetails.level >= 5) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
let err2string = get("rewardsharepage.rchange19")
this.error = true
this.createSponsorshipMessage = `${err2string}`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else {
let err3string = get("rewardsharepage.rchange20")
this.error = true
this.createSponsorshipMessage = `${err3string} ${accountDetails.level}`
}
} else {
//Check for creating reward shares
if (accountDetails.level >= 5) {
this.error = false
this.createSponsorshipMessage = ""
let myTransaction = await makeTransactionRequest(lastRef)
if (isExisting === true) {
let err4string = get("rewardsharepage.rchange18")
this.error = true
this.createSponsorshipMessage = `${err4string}`
} else {
// Send the transaction for confirmation by the user
this.error = false
this.createSponsorshipMessage = ""
getTxnRequestResponse(myTransaction)
}
} else {
this.error = true
let err5string = get("rewardsharepage.rchange20")
this.createSponsorshipMessage = `${err5string} ${accountDetails.level}`
}
}
}
// Make Transaction Request
const makeTransactionRequest = async (lastRef) => {
let mylastRef = lastRef
let rewarddialog1 = get("transactions.rewarddialog1")
let rewarddialog2 = get("transactions.rewarddialog2")
let rewarddialog3 = get("transactions.rewarddialog3")
let rewarddialog4 = get("transactions.rewarddialog4")
let myTxnrequest = await parentEpml.request("transaction", {
type: 38,
nonce: selectedAddress.nonce,
params: {
recipientPublicKey,
percentageShare,
lastReference: mylastRef,
rewarddialog1: rewarddialog1,
rewarddialog2: rewarddialog2,
rewarddialog3: rewarddialog3,
rewarddialog4: rewarddialog4,
},
})
return myTxnrequest
}
const getTxnRequestResponse = (txnResponse) => {
if (txnResponse.success === false && txnResponse.message) {
this.error = true
this.createSponsorshipMessage = txnResponse.message
throw new Error(txnResponse)
} else if (
txnResponse.success === true &&
!txnResponse.data.error
) {
let err6string = get("rewardsharepage.rchange21")
this.createSponsorshipMessage = err6string
this.error = false
} else {
this.error = true
this.createSponsorshipMessage = txnResponse.data.message
throw new Error(txnResponse)
}
}
validateReceiver()
this.isLoadingCreateSponsorship = false
}
render() {
return html`
${
this.isPageLoading
? html`
<div class="loadingContainer">
<div class="loading"></div>
</div>
<div class="backdrop"></div>
`
: ""
}
<div class="page-container">
<h1 class="header-title">
${translate("mintingpage.mchange35")}
</h1>
<div class="fullWidth">
<hr class="divider" />
</div>
<div class="inner-container">
${this.sponsorships.length === 0 ? html`
<div class="sub-title">
<p>${translate("sponsorshipspage.schange9")}</p>
</div>
` : ''}
${this.sponsorships.length > 0 ?
html`
<div class="sub-title">
<p>${translate("sponsorshipspage.schange1")}</p>
</div>
<div class="tableGrid table-header">
<div class="grid-item">
<p>${translate("sponsorshipspage.schange2")}</p>
</div>
<div class="grid-item">
<p>${translate("walletprofile.blocksminted")}</p>
</div>
<div class="grid-item">
<p>${translate("becomeMinterPage.bchange17")}</p>
</div>
<div class="grid-item">
</div>
</div>
${this.sponsorships.map(
(sponsorship) => html`
<ul class="tableGrid">
<li class="grid-item">
${sponsorship.address}
</li>
<li class="grid-item">
${+sponsorship.blocksMinted +
+sponsorship.blocksMintedAdjustment}
</li>
<li class="grid-item">
<button-icon-copy
title="${translate(
"becomeMinterPage.bchange17"
)}"
onSuccessMessage="${translate(
"walletpage.wchange4"
)}"
onErrorMessage="${translate(
"walletpage.wchange39"
)}"
textToCopy=${sponsorship.rewardSharePublicKey}
buttonSize="28px"
iconSize="16px"
color="var(--copybutton)"
offsetLeft="4px"
></button-icon-copy>
</li>
<li class="grid-item grid-item-button">
<mwc-button
class=${`red ${sponsorship.blocksRemaining <= 0 && 'btn--sponsorshipfinished'}`}
?disabled=${this
.removeRewardShareLoading}
@click=${() =>
this.removeRewardShare(
sponsorship
)}
><mwc-icon>create</mwc-icon
>${translate(
"rewardsharepage.rchange17"
)}</mwc-button>
</li>
</ul>
`
)}
<div class="summary-box">
<p class="text text--bold">
${translate("sponsorshipspage.schange3")} =
<span class="text text--normal">
${this.sponsorships.length}
</span>
</p>
<p class="text text--bold">
${translate("sponsorshipspage.schange4")} =
<span class="text text--normal">
${this.nextSponsorshipEnding
?.blocksRemaining}
${translate("mintingpage.mchange26")}
</span>
</p>
</div>
`
: ''}
<p class="message">${this.createSponsorshipMessage}</p>
<div class="form-wrapper">
<div class="sponsor-minter-wrapper">
<p class="sponsor-minter-text">${translate("sponsorshipspage.schange5")}</p>
</div>
<div class="form-item form-item--input">
<mwc-textfield
?disabled="${this.isLoadingCreateSponsorship}"
label="${translate("rewardsharepage.rchange10")}"
id="addPublicKey"
@input="${this.inputHandler}"
.value="${this.publicKeyValue || ""}"
fullWidth
>
</mwc-textfield>
</div>
<div class="form-item form-item--button">
<vaadin-button
?disabled="${this.isLoadingCreateSponsorship || !this.publicKeyValue}"
@click="${this.createRewardShare}"
>
${
this.isLoadingCreateSponsorship === false
? html`${translate(
"puzzlepage.pchange15"
)}`
: html`<paper-spinner-lite
active
></paper-spinner-lite>`
}
</vaadin-button>
</div>
</div>
</div>
<mwc-dialog id="showDialog">
<div class="dialog-header" >
<h1>${translate("sponsorshipspage.schange6")}</h1>
<hr />
</div>
<div class="dialog-container">
<p class="dialog-paragraph" style="text-align:center; width:100%">${this.sponsorships.filter(s=> s.blocksRemaining <= 0).length} ${translate("sponsorshipspage.schange7")}!</p>
<p class="dialog-paragraph" style="margin:0px; padding:0px;text-decoration:underline"> ${translate("sponsorshipspage.schange8")}</p>
${this.sponsorships.filter(s=> s.blocksRemaining <= 0).map((ms)=> html`
<p class="dialog-paragraph">${ms.address}</p>
`)}
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
class="red"
>
${translate("general.close")}
</mwc-button>
</mwc-dialog>
</div>
`
}
}
window.customElements.define("sponsorship-list", SponsorshipList)