Browse Source

started new plugin

pirate-chain-alphax
Phillip Lang Martinez 2 years ago
parent
commit
9964d7f121
  1. 6
      qortal-ui-core/src/components/sidenav-menu.js
  2. 1
      qortal-ui-core/src/functional-components/side-menu-item-style.js
  3. 4
      qortal-ui-plugins/build-config.js
  4. 9
      qortal-ui-plugins/plugins/core/main.src.js
  5. 53
      qortal-ui-plugins/plugins/core/sponsorship-list/index.html
  6. 306
      qortal-ui-plugins/plugins/core/sponsorship-list/sponsorship-list-css.src.js
  7. 573
      qortal-ui-plugins/plugins/core/sponsorship-list/sponsorship-list.src.js

6
qortal-ui-core/src/components/sidenav-menu.js

@ -158,6 +158,12 @@ class SidenavMenu extends connect(store)(LitElement) {
>
<vaadin-icon icon="vaadin:share-square" slot="icon"></vaadin-icon>
</side-menu-item>
<side-menu-item
label="${translate('mintingpage.mchange35')}"
href="/app/sponsorship-list"
>
<vaadin-icon icon="vaadin:share-square" slot="icon"></vaadin-icon>
</side-menu-item>
</side-menu-item>
<side-menu-item
label="${translate('sidemenu.wallets')}"

1
qortal-ui-core/src/functional-components/side-menu-item-style.js

@ -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 {

4
qortal-ui-plugins/build-config.js

@ -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',

9
qortal-ui-plugins/plugins/core/main.src.js

@ -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',

53
qortal-ui-plugins/plugins/core/sponsorship-list/index.html

@ -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>

306
qortal-ui-plugins/plugins/core/sponsorship-list/sponsorship-list-css.src.js

@ -0,0 +1,306 @@
import { css } from "lit"
export const pageStyles = css`
* {
--mdc-theme-surface: var(--white);
--mdc-dialog-content-ink-color: var(--black);
}
.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;
}
.description {
color: var(--black);
}
.message {
color: var(--gray);
}
.sub-main {
width: 95%;
display: flex;
flex-direction: column;
max-width: 1100px;
}
.level-black {
font-size: 32px;
color: var(--black);
font-weight: 400;
text-align: center;
margin-top: 2rem;
}
.form-wrapper {
display: flex;
align-items: center;
width: 100%;
max-width: 700px;
height: 50px;
}
.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;
}
.center-box {
position: absolute;
width: 100%;
top: 50%;
left: 50%;
transform: translate(-50%, 0%);
text-align: center;
}
.content-box {
border: 1px solid var(--border);
border-radius: 10px;
padding: 10px 25px;
text-align: center;
display: inline-block;
margin-bottom: 5px;
flex-basis: 250px;
}
.gap {
gap: 10px;
}
.level-black {
font-size: 32px;
color: var(--black);
font-weight: 400;
text-align: center;
margin-top: 2rem;
text-align: center;
}
.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
) 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;
}
.grid-item p {
text-decoration: underline;
}
ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.red {
--mdc-theme-primary: #f44336;
}
.grid-item-text {
display: none;
}
@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;
}
}
`

573
qortal-ui-plugins/plugins/core/sponsorship-list/sponsorship-list.src.js

@ -0,0 +1,573 @@
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 { 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 },
sponsorshipKeyValue: { type: String },
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 },
}
}
static styles = [pageStyles]
constructor() {
super()
this.theme = localStorage.getItem("qortalTheme")
? localStorage.getItem("qortalTheme")
: "light"
this.sponsorshipKeyValue = ""
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 = ""
}
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(
"QPsjHoKhugEADrtSQP5xjFgsaQPn9WmE3Y"
)
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}`,
})
const recentBlocksInfo = await parentEpml.request("apiCall", {
type: "api",
url: `/blocks/signer/${rs.recipient}?limit=5&reverse=true`,
})
let blocksRemaining = this._levelUpBlocks(addressInfo)
blocksRemaining = +blocksRemaining > 0 ? +blocksRemaining : 0
return {
...addressInfo,
...rs,
lastActiveBlock: recentBlocksInfo[0]?.height,
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
} catch (error) {
console.error(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.atMount()
} 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() {
console.log({ sponsorships: this.sponsorships })
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">
<div class="tableGrid table-header">
<div class="grid-item">
<p>Account Address</p>
</div>
<div class="grid-item">
<p>Blocks Minted</p>
</div>
<div class="grid-item">
<p>Last Active Block</p>
</div>
<div class="grid-item">
<p>Sponsorship Key</p>
</div>
<div class="grid-item">
<!-- <p>Remove</p> -->
</div>
</div>
${this.sponsorships.map(
(sponsorship) => html`
<ul class="tableGrid">
<li class="grid-item">
<p class="grid-item-text">
Account Address
</p>
${sponsorship.address}
</li>
<li class="grid-item">
<p class="grid-item-text">
Blocks Minted
</p>
${+sponsorship.blocksMinted +
+sponsorship.blocksMintedAdjustment}
</li>
<li class="grid-item">
<p class="grid-item-text">
Last Active Block
</p>
${sponsorship.lastActiveBlock}
</li>
<li class="grid-item">
<p class="grid-item-text">
Copy Sponsorship Key
</p>
<button-icon-copy
title="${translate(
"walletpage.wchange3"
)}"
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"
?disabled=${this
.removeRewardShareLoading}
@click=${() =>
this.removeRewardShare(
sponsorship
)}
><mwc-icon>create</mwc-icon
>${translate(
"rewardsharepage.rchange17"
)}</mwc-button
>
</li>
</ul>
`
)}
</ul>
${
this.sponsorships.length > 0 &&
html`
<div>
<p>
Total Sponsorships active
${this.sponsorships.length}
</p>
<p>
Next sponsorship ending in
${this.nextSponsorshipEnding
?.blocksRemaining}
blocks
</p>
</div>
`
}
<p class="message">${this.createSponsorshipMessage}</p>
<div class="form-wrapper">
<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>
</div>
`
}
}
window.customElements.define("sponsorship-list", SponsorshipList)
Loading…
Cancel
Save