Compare commits
6 Commits
35e6595311
...
e0c5a09378
Author | SHA1 | Date | |
---|---|---|---|
e0c5a09378 | |||
509e3bf357 | |||
07f4fa3e6e | |||
7afa06623f | |||
51921992e2 | |||
f5ce634ff5 |
@ -708,31 +708,6 @@ body {
|
||||
}
|
||||
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.publish-card-view {
|
||||
width: 90%;
|
||||
padding: 2vh;
|
||||
}
|
||||
|
||||
.publish-card-button {
|
||||
font-size: 1.8vh;
|
||||
padding: 1.5vh;
|
||||
}
|
||||
|
||||
.publish-card-form button {
|
||||
font-size: 1.8vh;
|
||||
padding: 1.2vh;
|
||||
}
|
||||
}
|
||||
|
||||
.refresh-cards-button {
|
||||
border-color: white;
|
||||
border-radius: 1.5vh;
|
||||
background-color: black;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.publish-card-view {
|
||||
@ -754,8 +729,14 @@ body {
|
||||
.refresh-cards-button {
|
||||
border-color: white;
|
||||
border-radius: 1.5vh;
|
||||
background-color: black;
|
||||
background-color: rgba(0, 0, 0, 0.089);
|
||||
color: white;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.refresh-cards-button:hover {
|
||||
background-color: rgba(35, 129, 136, 0.137);
|
||||
color: rgba(90, 201, 221, 0.793);
|
||||
}
|
||||
/* Two cards per row on medium screens */
|
||||
|
||||
|
@ -60,11 +60,13 @@ const loadAddRemoveAdminPage = async () => {
|
||||
<h3 style="color: #ddd;">Existing Promotion/Demotion Proposals</h3>
|
||||
<button id="refresh-cards-button" class="refresh-cards-button" style="padding: 10px;">Refresh Proposal Cards</button>
|
||||
<select id="time-range-select" style="margin-left: 10px; padding: 5px; font-size: 1.25rem; color: white; background-color: black;">
|
||||
<option value="0">Show All</option>
|
||||
<option value="1">Last 1 day</option>
|
||||
<option value="7">Last 7 days</option>
|
||||
<option value="30" selected>Last 30 days</option>
|
||||
<option value="90">Last 90 days</option>
|
||||
<option value="0">All Creation Dates</option>
|
||||
<option value="1">Last 1 Day</option>
|
||||
<option value="7">Last 7 Days</option>
|
||||
<option value="30">...Within 30 Days</option>
|
||||
<option value="45" selected>Published Within Last 45 Days</option>
|
||||
<option value="60">...Within 60 Days</option>
|
||||
<option value="90">...Within 90 Days</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="cards-container" class="cards-container" style="margin-top: 1rem"">
|
||||
@ -117,6 +119,13 @@ const loadAddRemoveAdminPage = async () => {
|
||||
linksContainer.appendChild(newLinkInput)
|
||||
})
|
||||
|
||||
const timeRangeSelectCheckbox = document.getElementById('time-range-select')
|
||||
if (timeRangeSelectCheckbox) {
|
||||
timeRangeSelectCheckbox.addEventListener('change', async (event) => {
|
||||
await loadCards(addRemoveIdentifierPrefix)
|
||||
})
|
||||
}
|
||||
|
||||
document.getElementById("publish-card-form").addEventListener("submit", async (event) => {
|
||||
event.preventDefault()
|
||||
await publishARCard(addRemoveIdentifierPrefix)
|
||||
|
@ -84,12 +84,14 @@ const loadAdminBoardPage = async () => {
|
||||
<option value="most-votes">Most Votes</option>
|
||||
</select>
|
||||
<select id="time-range-select" style="margin-left: 10px; padding: 5px; font-size: 1.25rem; color: white; background-color: black;">
|
||||
<option value="0">Show All</option>
|
||||
<option value="1">Last 1 day</option>
|
||||
<option value="7">Last 7 days</option>
|
||||
<option value="30" selected>Last 30 days</option>
|
||||
<option value="90">Last 90 days</option>
|
||||
</select>
|
||||
<option value="0">All Creation Dates</option>
|
||||
<option value="1">Last 1 Day</option>
|
||||
<option value="7">Last 7 Days</option>
|
||||
<option value="30">...Within 30 Days</option>
|
||||
<option value="45" selected>Published Within Last 45 Days</option>
|
||||
<option value="60">...Within 60 Days</option>
|
||||
<option value="90">...Within 90 Days</option>
|
||||
</select>
|
||||
<div class="show-card-checkbox" style="margin-top: 1em;">
|
||||
<input type="checkbox" id="admin-show-hidden-checkbox" name="adminHidden" />
|
||||
<label for="admin-show-hidden-checkbox">Show User-Hidden Cards?</label>
|
||||
@ -1078,7 +1080,7 @@ const createRemoveButtonHtml = (name, cardIdentifier) => {
|
||||
|
||||
const handleKickMinter = async (minterName) => {
|
||||
try {
|
||||
isAddress = await getAddressInfo(minterName)
|
||||
let isAddress = await getAddressInfo(minterName)
|
||||
|
||||
// Optional block check
|
||||
let txGroupId = 0
|
||||
@ -1091,7 +1093,7 @@ const handleKickMinter = async (minterName) => {
|
||||
|
||||
// Get the minter address from name info
|
||||
let minterAddress
|
||||
if (!isAddress){
|
||||
if (!isAddress.address || !isAddress.address != minterName){
|
||||
const minterNameInfo = await getNameInfo(minterName)
|
||||
minterAddress = minterNameInfo?.owner
|
||||
} else {
|
||||
@ -1107,7 +1109,7 @@ const handleKickMinter = async (minterName) => {
|
||||
const reason = 'Kicked by Minter Admins'
|
||||
const fee = 0.01
|
||||
|
||||
const rawKickTransaction = await createGroupKickTransaction(minterAddress, adminPublicKey, 694, minterAddress, reason, txGroupId, fee)
|
||||
const rawKickTransaction = await createGroupKickTransaction(adminPublicKey, 694, minterAddress, reason, txGroupId, fee)
|
||||
|
||||
const signedKickTransaction = await qortalRequest({
|
||||
action: "SIGN_TRANSACTION",
|
||||
@ -1138,7 +1140,7 @@ const handleKickMinter = async (minterName) => {
|
||||
}
|
||||
|
||||
const handleBanMinter = async (minterName) => {
|
||||
isAddress = await getAddressInfo(minterName)
|
||||
let isAddress = await getAddressInfo(minterName)
|
||||
try {
|
||||
let txGroupId = 0
|
||||
// const { height: currentHeight } = await getLatestBlockInfo()
|
||||
@ -1151,9 +1153,9 @@ const handleBanMinter = async (minterName) => {
|
||||
txGroupId = 694
|
||||
}
|
||||
let minterAddress
|
||||
if (!isAddress) {
|
||||
if (!isAddress.address || !isAddress.address != minterName){
|
||||
const minterNameInfo = await getNameInfo(minterName)
|
||||
const minterAddress = minterNameInfo?.owner
|
||||
minterAddress = minterNameInfo?.owner
|
||||
} else {
|
||||
minterAddress = minterName
|
||||
}
|
||||
|
@ -25,42 +25,99 @@ const loadMinterBoardPage = async () => {
|
||||
const publishButtonColor = '#527c9d'
|
||||
const minterBoardNameColor = '#527c9d'
|
||||
mainContent.innerHTML = `
|
||||
<div class="minter-board-main" style="padding: 20px; text-align: center;">
|
||||
<h1 style="color: ${minterBoardNameColor};">Minter Board</h1>
|
||||
<p style="font-size: 1.25em;"> Publish a Minter Card with Information, and obtain and view the support of the community. Welcome to the Minter Board!</p>
|
||||
<button id="publish-card-button" class="publish-card-button" style="margin: 20px; padding: 10px; background-color: ${publishButtonColor}">Publish Minter Card</button>
|
||||
<button id="refresh-cards-button" class="refresh-cards-button" style="padding: 10px;">Refresh Cards</button>
|
||||
<select id="sort-select" style="margin-left: 10px; padding: 5px; font-size: 1.25rem; color:rgb(38, 106, 106); background-color: black;">
|
||||
<option value="newest" selected>Sort by Date</option>
|
||||
<option value="name">Sort by Name</option>
|
||||
<option value="recent-comments">Newest Comments</option>
|
||||
<option value="least-votes">Least Votes</option>
|
||||
<option value="most-votes">Most Votes</option>
|
||||
</select>
|
||||
<select id="time-range-select" style="margin-left: 10px; padding: 5px; font-size: 1.25rem; color: white; background-color: black;">
|
||||
<option value="0">Show All</option>
|
||||
<option value="1">Last 1 day</option>
|
||||
<option value="7">Last 7 days</option>
|
||||
<option value="30" selected>Last 30 days</option>
|
||||
<option value="90">Last 90 days</option>
|
||||
</select>
|
||||
<div id="cards-container" class="cards-container" style="margin-top: 20px;"></div>
|
||||
<div id="publish-card-view" class="publish-card-view" style="display: none; text-align: left; padding: 20px;">
|
||||
<form id="publish-card-form" class="publish-card-form">
|
||||
<h3>Create or Update Your Card</h3>
|
||||
<label for="card-header">Header:</label>
|
||||
<input type="text" id="card-header" maxlength="100" placeholder="Enter card header" required>
|
||||
<label for="card-content">Content:</label>
|
||||
<textarea id="card-content" placeholder="Enter detailed information about why you would like to be a minter... the more the better, and links to things you have published on QDN will help a lot! Give the Minter Admins things to make decisions by!" required></textarea>
|
||||
<label for="card-links">Links (qortal://...):</label>
|
||||
<div id="links-container">
|
||||
<input type="text" class="card-link" placeholder="Enter QDN link">
|
||||
<div class="minter-board-main" style="padding: 0.5vh; text-align: center;">
|
||||
|
||||
<!-- Board Title + Intro -->
|
||||
<h1 style="color: #527c9d;">The Minter Board</h1>
|
||||
<p style="font-size: 1.2em; color:rgb(85, 119, 101)">
|
||||
The Minter Board is where Minting Rights are Delegated.
|
||||
</p>
|
||||
<p style="font-size: 1.1em; color:rgb(85, 119, 119)">
|
||||
To obtain minting rights, click 'PUBLISH CARD' and create your card. A subsequent vote will approve/deny your card.
|
||||
</p>
|
||||
<p>
|
||||
After your card has received the necessary invite, return to the card and click the Join Group button to join the MINTER group.
|
||||
(A Detailed how-to guide will be coming soon.)
|
||||
</p>
|
||||
|
||||
<div class="card-display-options">
|
||||
<!-- Centered heading -->
|
||||
<h4 class="options-heading"style="color: #527c9d;">CARD DISPLAY OPTIONS</h4>
|
||||
|
||||
<!-- A flex container for all the controls (sort, time range, checkbox) -->
|
||||
<div class="options-row">
|
||||
<!-- Sort by -->
|
||||
<label for="sort-select" class="options-label">Sort By:</label>
|
||||
<select id="sort-select" class="options-select">
|
||||
<option value="newest" selected>Date</option>
|
||||
<option value="name">Name</option>
|
||||
<option value="recent-comments">Newest Comments</option>
|
||||
<option value="least-votes">Least Votes</option>
|
||||
<option value="most-votes">Most Votes</option>
|
||||
</select>
|
||||
|
||||
<!-- Time range -->
|
||||
<label for="time-range-select" class="options-label">Show Cards:</label>
|
||||
<select id="time-range-select" class="options-select">
|
||||
<option value="0">Show ALL Cards Published</option>
|
||||
<option value="1">...Within Last 1 Day</option>
|
||||
<option value="7">...Within Last 7 Days</option>
|
||||
<option value="30">...Within 30 Days</option>
|
||||
<option value="45" selected>Published Within Last 45 Days</option>
|
||||
<option value="60">...Within 60 Days</option>
|
||||
<option value="90">...Within 90 Days</option>
|
||||
</select>
|
||||
|
||||
<!-- Show existing checkbox -->
|
||||
<label class="options-check">
|
||||
<input type="checkbox" id="show-existing-checkbox" />
|
||||
Show Existing Minter Cards (History)
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Card counter heading centered, with actual counter below if desired -->
|
||||
<div style="margin-bottom: 1em;">
|
||||
<div style="text-align: center; margin-top: 0.5em;">
|
||||
<span id="board-card-counter" style="font-size: 1rem; color:rgb(153, 203, 204); padding: 0.5em;">
|
||||
<!-- e.g. "5 cards found" -->
|
||||
</span>
|
||||
</div>
|
||||
<button type="button" id="add-link-button">Add Another Link</button>
|
||||
<button type="submit" id="submit-publish-button">Publish Card</button>
|
||||
<button type="button" id="cancel-publish-button">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Row for Publish / Refresh actions -->
|
||||
<div class="card-actions" style="margin-bottom: 1em;">
|
||||
<button id="publish-card-button" class="publish-card-button">
|
||||
PUBLISH CARD
|
||||
</button>
|
||||
<button id="refresh-cards-button" class="refresh-cards-button"
|
||||
style="padding: 1vh;">
|
||||
REFRESH CARDS
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Container for displayed cards -->
|
||||
<div id="cards-container" class="cards-container" style="margin-top: 2vh;"></div>
|
||||
|
||||
<!-- Hidden Publish Card Form -->
|
||||
<div id="publish-card-view" class="publish-card-view" style="display: none; text-align: left; padding: 2vh;">
|
||||
<form id="publish-card-form" class="publish-card-form">
|
||||
<h3>Create or Update Your Card</h3>
|
||||
<label for="card-header">Header:</label>
|
||||
<input type="text" id="card-header" maxlength="100" placeholder="Enter card header" required>
|
||||
|
||||
<label for="card-content">Content:</label>
|
||||
<textarea id="card-content" placeholder="Enter detailed information about why you would like to be a minter... the more the better..." required>
|
||||
</textarea>
|
||||
|
||||
<label for="card-links">Links (qortal://...):</label>
|
||||
<div id="links-container">
|
||||
<input type="text" class="card-link" placeholder="Enter QDN link">
|
||||
</div>
|
||||
<button type="button" id="add-link-button">Add Another Link</button>
|
||||
<button type="submit" id="submit-publish-button">Publish Card</button>
|
||||
<button type="button" id="cancel-publish-button">Cancel</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
document.body.appendChild(mainContent)
|
||||
@ -144,6 +201,13 @@ const loadMinterBoardPage = async () => {
|
||||
await loadCards(minterCardIdentifierPrefix)
|
||||
})
|
||||
|
||||
const showExistingCardsCheckbox = document.getElementById('show-existing-checkbox')
|
||||
if (showExistingCardsCheckbox) {
|
||||
showExistingCardsCheckbox.addEventListener('change', async (event) => {
|
||||
await loadCards(minterCardIdentifierPrefix)
|
||||
})
|
||||
}
|
||||
|
||||
await featureTriggerCheck()
|
||||
await loadCards(minterCardIdentifierPrefix)
|
||||
}
|
||||
@ -367,6 +431,12 @@ const loadCards = async (cardIdentifierPrefix) => {
|
||||
const cardsContainer = document.getElementById("cards-container")
|
||||
let isARBoard = false
|
||||
cardsContainer.innerHTML = "<p>Loading cards...</p>"
|
||||
const counterSpan = document.getElementById("board-card-counter")
|
||||
|
||||
if (counterSpan) {
|
||||
// Clear or show "Loading..."
|
||||
counterSpan.textContent = "(loading...)"
|
||||
}
|
||||
|
||||
if (cardIdentifierPrefix.startsWith("QM-AR-card")) {
|
||||
isARBoard = true
|
||||
@ -375,6 +445,9 @@ const loadCards = async (cardIdentifierPrefix) => {
|
||||
let afterTime = 0
|
||||
const timeRangeSelect = document.getElementById("time-range-select")
|
||||
|
||||
const showExistingCheckbox = document.getElementById("show-existing-checkbox")
|
||||
const showExisting = showExistingCheckbox && showExistingCheckbox.checked
|
||||
|
||||
if (timeRangeSelect) {
|
||||
const days = parseInt(timeRangeSelect.value, 10)
|
||||
if (days > 0) {
|
||||
@ -440,6 +513,7 @@ const loadCards = async (cardIdentifierPrefix) => {
|
||||
// else 'newest' => do nothing (already sorted newest-first by your process functions).
|
||||
// Create the 'finalCardsArray' that includes the data, etc.
|
||||
let finalCardsArray = []
|
||||
let alreadyMinterCards = []
|
||||
cardsContainer.innerHTML = ''
|
||||
for (const card of finalCards) {
|
||||
try {
|
||||
@ -477,8 +551,14 @@ const loadCards = async (cardIdentifierPrefix) => {
|
||||
} else {
|
||||
const isAlreadyMinter = await verifyMinter(cardDataResponse.creator)
|
||||
if (isAlreadyMinter) {
|
||||
console.warn(`card IS ALREADY a minter, NOT displaying following identifier on the MinterBoard: ${card.identifier}`)
|
||||
console.warn(`card IS ALREADY a minter, adding to alreadyMinterCards array: ${card.identifier}`)
|
||||
removeSkeleton(card.identifier)
|
||||
alreadyMinterCards.push({
|
||||
...card,
|
||||
cardDataResponse,
|
||||
pollPublisherAddress,
|
||||
cardPublisherAddress
|
||||
})
|
||||
continue
|
||||
}
|
||||
}
|
||||
@ -489,6 +569,12 @@ const loadCards = async (cardIdentifierPrefix) => {
|
||||
pollPublisherAddress,
|
||||
cardPublisherAddress,
|
||||
})
|
||||
if (counterSpan) {
|
||||
const displayedCount = finalCardsArray.length
|
||||
const alreadyMinterCount = alreadyMinterCards.length
|
||||
// If you want to show both
|
||||
counterSpan.textContent = `(${displayedCount} cards, ${alreadyMinterCount} existingMinters)`
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(`Error preparing card ${card.identifier}`, err)
|
||||
removeSkeleton(card.identifier)
|
||||
@ -531,9 +617,39 @@ const loadCards = async (cardIdentifierPrefix) => {
|
||||
replaceSkeleton(cardObj.identifier, finalCardHTML)
|
||||
}
|
||||
|
||||
if (showExisting && alreadyMinterCards.length > 0) {
|
||||
console.warn(`Rendering Existing Minter cards because user selected showExisting`)
|
||||
|
||||
for (const mintedCardObj of alreadyMinterCards) {
|
||||
const skeletonHTML = createSkeletonCardHTML(mintedCardObj.identifier)
|
||||
cardsContainer.insertAdjacentHTML("beforeend", skeletonHTML)
|
||||
|
||||
const pollResults = await fetchPollResults(mintedCardObj.cardDataResponse.poll)
|
||||
const commentCount = await countComments(mintedCardObj.identifier)
|
||||
const cardUpdatedTime = mintedCardObj.updated || null
|
||||
const bgColor = generateDarkPastelBackgroundBy(mintedCardObj.name)
|
||||
const isExistingMinter = true
|
||||
|
||||
const finalCardHTML = await createCardHTML(
|
||||
mintedCardObj.cardDataResponse,
|
||||
pollResults,
|
||||
mintedCardObj.identifier,
|
||||
commentCount,
|
||||
cardUpdatedTime,
|
||||
bgColor,
|
||||
mintedCardObj.cardPublisherAddress,
|
||||
isExistingMinter
|
||||
)
|
||||
replaceSkeleton(mintedCardObj.identifier, finalCardHTML)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error("Error loading cards:", error)
|
||||
cardsContainer.innerHTML = "<p>Failed to load cards.</p>"
|
||||
if (counterSpan) {
|
||||
counterSpan.textContent = "(error loading)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,7 +866,6 @@ const loadCardIntoForm = async (cardData) => {
|
||||
|
||||
// Main function to publish a new Minter Card -----------------------------------------------
|
||||
const publishCard = async (cardIdentifierPrefix) => {
|
||||
|
||||
const minterGroupData = await fetchMinterGroupMembers()
|
||||
const minterGroupAddresses = minterGroupData.map(m => m.member)
|
||||
const userAddress = userState.accountAddress
|
||||
@ -759,6 +874,7 @@ const publishCard = async (cardIdentifierPrefix) => {
|
||||
alert("You are already a Minter and cannot publish a new card!")
|
||||
return
|
||||
}
|
||||
|
||||
const header = document.getElementById("card-header").value.trim()
|
||||
const content = document.getElementById("card-content").value.trim()
|
||||
const links = Array.from(document.querySelectorAll(".card-link"))
|
||||
@ -770,8 +886,27 @@ const publishCard = async (cardIdentifierPrefix) => {
|
||||
return
|
||||
}
|
||||
|
||||
const cardIdentifier = isExistingCard ? existingCardIdentifier : `${cardIdentifierPrefix}-${await uid()}`
|
||||
const pollName = `${cardIdentifier}-poll`
|
||||
if (isExistingCard) {
|
||||
if (!existingCardData || Object.keys(existingCardData).length === 0) {
|
||||
const fetched = await fetchExistingCard(cardIdentifierPrefix)
|
||||
if (fetched) {
|
||||
existingCardData = fetched
|
||||
} else {
|
||||
console.warn("fetchExistingCard returned null. Possibly no existing card found.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const cardIdentifier = isExistingCard && existingCardIdentifier
|
||||
? existingCardIdentifier
|
||||
: `${cardIdentifierPrefix}-${await uid()}`
|
||||
|
||||
let existingPollName
|
||||
if (existingCardData && existingCardData.poll) {
|
||||
existingPollName = existingCardData.poll
|
||||
}
|
||||
|
||||
const pollName = existingPollName || `${cardIdentifier}-poll`
|
||||
const pollDescription = `Mintership Board Poll for ${userState.accountName}`
|
||||
|
||||
const cardData = {
|
||||
@ -781,16 +916,16 @@ const publishCard = async (cardIdentifierPrefix) => {
|
||||
creator: userState.accountName,
|
||||
creatorAddress: userState.accountAddress,
|
||||
timestamp: Date.now(),
|
||||
poll: pollName,
|
||||
poll: pollName // either the existing poll or a new one
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
let base64CardData = await objectToBase64(cardData)
|
||||
if (!base64CardData) {
|
||||
console.log(`initial base64 object creation with objectToBase64 failed, using btoa...`)
|
||||
base64CardData = btoa(JSON.stringify(cardData))
|
||||
}
|
||||
|
||||
if (!base64CardData) {
|
||||
console.log(`initial base64 object creation with objectToBase64 failed, using btoa...`)
|
||||
base64CardData = btoa(JSON.stringify(cardData))
|
||||
}
|
||||
|
||||
await qortalRequest({
|
||||
action: "PUBLISH_QDN_RESOURCE",
|
||||
name: userState.accountName,
|
||||
@ -799,7 +934,7 @@ const publishCard = async (cardIdentifierPrefix) => {
|
||||
data64: base64CardData,
|
||||
})
|
||||
|
||||
if (!isExistingCard){
|
||||
if (!isExistingCard || !existingPollName) {
|
||||
await qortalRequest({
|
||||
action: "CREATE_POLL",
|
||||
pollName,
|
||||
@ -807,26 +942,33 @@ const publishCard = async (cardIdentifierPrefix) => {
|
||||
pollOptions: ['Yes, No'],
|
||||
pollOwnerAddress: userState.accountAddress,
|
||||
})
|
||||
alert("Card and poll published successfully!")
|
||||
if (!isExistingCard) {
|
||||
alert("Card and poll published successfully!")
|
||||
} else {
|
||||
alert("Existing card updated, and new poll created (since existing poll was missing)!")
|
||||
}
|
||||
} else {
|
||||
alert("Card updated successfully! (No poll updates possible)")
|
||||
}
|
||||
|
||||
if (isExistingCard){
|
||||
alert("Card Updated Successfully! (No poll updates possible)")
|
||||
if (isExistingCard) {
|
||||
isExistingCard = false
|
||||
existingCardData = {}
|
||||
}
|
||||
|
||||
document.getElementById("publish-card-form").reset()
|
||||
document.getElementById("publish-card-view").style.display = "none"
|
||||
document.getElementById("cards-container").style.display = "flex"
|
||||
|
||||
await loadCards(minterCardIdentifierPrefix)
|
||||
|
||||
} catch (error) {
|
||||
|
||||
console.error("Error publishing card or poll:", error)
|
||||
alert("Failed to publish card and poll.")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let globalVoterMap = new Map()
|
||||
|
||||
const processPollData= async (pollData, minterGroupMembers, minterAdmins, creator, cardIdentifier) => {
|
||||
@ -1193,6 +1335,7 @@ const toggleComments = async (cardIdentifier) => {
|
||||
const commentButton = document.getElementById(`comment-button-${cardIdentifier}`)
|
||||
|
||||
if (!commentsSection || !commentButton) return
|
||||
|
||||
const count = commentButton.dataset.commentCount
|
||||
const isHidden = (commentsSection.style.display === 'none' || !commentsSection.style.display)
|
||||
|
||||
@ -1469,7 +1612,7 @@ const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) =>
|
||||
// fetch all final KICK/BAN tx
|
||||
const { finalKickTxs, finalBanTxs } = await fetchAllKickBanTxData()
|
||||
const { finalInviteTxs, pendingInviteTxs } = await fetchAllInviteTransactions()
|
||||
// check if there's a final (non-pending) KICK or BAN for this user
|
||||
// check if there's a KICK or BAN for this user.
|
||||
const priorKick = finalKickTxs.some(tx => tx.member === minterAddress)
|
||||
const priorBan = finalBanTxs.some(tx => tx.offender === minterAddress)
|
||||
const existingInvite = finalInviteTxs.some(tx => tx.invitee === minterAddress)
|
||||
@ -1480,10 +1623,12 @@ const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) =>
|
||||
// build the normal invite button & groupApprovalHtml
|
||||
let inviteButtonHtml = ""
|
||||
if (existingInvite || pendingInvite){
|
||||
console.warn(`There is an EXISTING INVITE for this user! No invite button being created... existing: (${existingInvite}, pending: ${pendingInvite})`)
|
||||
console.warn(`There is an EXISTING or PENDING INVITE for this user! No invite button being created... existing: (${existingInvite}, pending: ${pendingInvite})`)
|
||||
inviteButtonHtml = ''
|
||||
} else {
|
||||
inviteButtonHtml = isSomeTypaAdmin ? createInviteButtonHtml(creator, cardIdentifier) : ""
|
||||
}
|
||||
inviteButtonHtml = isSomeTypaAdmin ? createInviteButtonHtml(creator, cardIdentifier) : ""
|
||||
|
||||
const groupApprovalHtml = await checkGroupApprovalAndCreateButton(minterAddress, cardIdentifier, "GROUP_INVITE")
|
||||
|
||||
// if user had no prior KICK/BAN
|
||||
@ -1903,7 +2048,7 @@ const getNewestCommentTimestamp = async (cardIdentifier) => {
|
||||
}
|
||||
|
||||
// Create the overall Minter Card HTML -----------------------------------------------
|
||||
const createCardHTML = async (cardData, pollResults, cardIdentifier, commentCount, cardUpdatedTime, bgColor, address) => {
|
||||
const createCardHTML = async (cardData, pollResults, cardIdentifier, commentCount, cardUpdatedTime, bgColor, address, isExistingMinter=false) => {
|
||||
const { header, content, links, creator, creatorAddress, timestamp, poll } = cardData
|
||||
const formattedDate = cardUpdatedTime ? new Date(cardUpdatedTime).toLocaleString() : new Date(timestamp).toLocaleString()
|
||||
const avatarHtml = await getMinterAvatar(creator)
|
||||
@ -1919,7 +2064,7 @@ const createCardHTML = async (cardData, pollResults, cardIdentifier, commentCoun
|
||||
createModal('links')
|
||||
createModal('poll-details')
|
||||
|
||||
const inviteButtonHtml = await checkAndDisplayInviteButton(adminYes, creator, cardIdentifier)
|
||||
const inviteButtonHtml = isExistingMinter ? "" : await checkAndDisplayInviteButton(adminYes, creator, cardIdentifier)
|
||||
let inviteHtmlAdd = (inviteButtonHtml) ? inviteButtonHtml : ''
|
||||
|
||||
let finalBgColor = bgColor
|
||||
@ -1935,6 +2080,9 @@ const createCardHTML = async (cardData, pollResults, cardIdentifier, commentCoun
|
||||
finalBgColor = "rgba(1, 65, 39, 0.41)"; // or any green you want
|
||||
} else if (userVote === 1) {
|
||||
finalBgColor = "rgba(107, 3, 3, 0.3)"; // or any red you want
|
||||
} else if (isExistingMinter){
|
||||
finalBgColor = "rgb(99, 99, 99)"
|
||||
invitedText = `<h4 style="color:rgb(135, 55, 16); margin-bottom: 0.5em;">EXISTING MINTER</h4>`
|
||||
} else if (hasMinterInvite) {
|
||||
// If so, override background color & add an "INVITED" label
|
||||
finalBgColor = "black";
|
||||
|
@ -1,4 +1,4 @@
|
||||
const Q_MINTERSHIP_VERSION = "1.06"
|
||||
const Q_MINTERSHIP_VERSION = "1.06.4"
|
||||
|
||||
const messageIdentifierPrefix = `mintership-forum-message`
|
||||
const messageAttachmentIdentifierPrefix = `mintership-forum-attachment`
|
||||
|
@ -224,6 +224,12 @@ const getUserAddress = async () => {
|
||||
}
|
||||
|
||||
const getAddressInfo = async (address) => {
|
||||
const qortalAddressPattern = /^Q[A-Za-z0-9]{33}$/ // Q + 33 almum = 34 total length
|
||||
|
||||
if (!qortalAddressPattern.test(address)) {
|
||||
console.warn(`Not a valid Qortal address format, returning same thing that was passed to not break other functions: ${address}`)
|
||||
return address
|
||||
}
|
||||
try {
|
||||
const response = await fetch (`${baseUrl}/addresses/${address}`, {
|
||||
headers: { 'Accept': 'application/json' },
|
||||
@ -786,18 +792,20 @@ const searchSimple = async (service, identifier, name, limit=1500, offset=0, roo
|
||||
|
||||
if (name && !identifier && !room) {
|
||||
console.log('name only searchSimple', name)
|
||||
urlSuffix = `service=${service}&name=${name}&limit=${limit}&prefix=true&reverse=${reverse}`
|
||||
urlSuffix = `service=${service}&name=${name}&limit=${limit}&prefix=true&reverse=${reverse}&after=${after}`
|
||||
console.log(`urlSuffix used: ${urlSuffix}`)
|
||||
|
||||
} else if (!name && identifier && !room) {
|
||||
console.log('identifier only searchSimple', identifier)
|
||||
urlSuffix = `service=${service}&identifier=${identifier}&limit=${limit}&prefix=true&reverse=${reverse}`
|
||||
urlSuffix = `service=${service}&identifier=${identifier}&limit=${limit}&prefix=true&reverse=${reverse}&after=${after}`
|
||||
console.log(`urlSuffix used: ${urlSuffix}`)
|
||||
|
||||
} else if (!name && !identifier && !room) {
|
||||
console.error(`name: ${name} AND identifier: ${identifier} not passed. Must include at least one...`)
|
||||
return null
|
||||
|
||||
} else {
|
||||
console.log(`final searchSimple params = service: '${service}', identifier: '${identifier}', name: '${name}', limit: '${limit}', offset: '${offset}', room: '${room}', reverse: '${reverse}'`)
|
||||
console.log(`final searchSimple params = service: '${service}', identifier: '${identifier}', name: '${name}', limit: '${limit}', offset: '${offset}', room: '${room}', reverse: '${reverse}', after: ${after}`)
|
||||
}
|
||||
|
||||
const response = await fetch(`${baseUrl}/arbitrary/resources/searchsimple?${urlSuffix}`, {
|
||||
@ -1395,16 +1403,16 @@ const createGroupInviteTransaction = async (recipientAddress, adminPublicKey, gr
|
||||
}
|
||||
}
|
||||
|
||||
const createGroupKickTransaction = async (recipientAddress, adminPublicKey, groupId=694, member, reason='Kicked by admins', txGroupId, fee) => {
|
||||
const createGroupKickTransaction = async (adminPublicKey, groupId=694, member, reason='Kicked by admins', txGroupId=694, fee=0.01) => {
|
||||
|
||||
try {
|
||||
// Fetch account reference correctly
|
||||
const accountInfo = await getAddressInfo(recipientAddress)
|
||||
const accountInfo = await getAddressInfo(member)
|
||||
const accountReference = accountInfo.reference
|
||||
|
||||
// Validate inputs before making the request
|
||||
if (!adminPublicKey || !accountReference || !recipientAddress) {
|
||||
throw new Error("Missing required parameters for group invite transaction.")
|
||||
if (!adminPublicKey || !accountReference || !member) {
|
||||
throw new Error("Missing required parameters for group kick transaction.")
|
||||
}
|
||||
|
||||
const payload = {
|
||||
@ -1412,11 +1420,10 @@ const createGroupKickTransaction = async (recipientAddress, adminPublicKey, grou
|
||||
reference: accountReference,
|
||||
fee,
|
||||
txGroupId,
|
||||
recipient: null,
|
||||
adminPublicKey,
|
||||
groupId: groupId,
|
||||
member: member || recipientAddress,
|
||||
reason: reason
|
||||
groupId,
|
||||
member,
|
||||
reason
|
||||
}
|
||||
|
||||
console.log("Sending GROUP_KICK transaction payload:", payload)
|
||||
|
@ -141,7 +141,7 @@
|
||||
<div class="row">
|
||||
|
||||
<div class="col-12 col-lg-4">
|
||||
<div class="card-wrapper" style="justify-content:center; align: center; align-text: center;">
|
||||
<div class="card-wrapper" style="justify-content:center;">
|
||||
<div class="icon-wrapper">
|
||||
<span class="mbr-iconfont mbr-iconfont-btn mbri-file" style="color:aliceblue;"></span>
|
||||
</div>
|
||||
@ -200,14 +200,14 @@
|
||||
<div class="row">
|
||||
<div class="col-12 col-lg-7 card">
|
||||
<div class="title-wrapper">
|
||||
<h2 class="mbr-section-title mbr-fonts-style display-2">
|
||||
v1.06beta 01-31-2025</h2>
|
||||
<h2 class="mbr-section-title mbr-fonts-style display-2 version">
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-lg-5 card">
|
||||
<div class="text-wrapper">
|
||||
<p class="mbr-text mbr-fonts-style display-7">
|
||||
<b><u>v1.06b Fixes</u></b>- <b>EMERGENCY UPDATE </b> - See post in the <a href="MINTERSHIP-FORUM">FORUM</a> for RELEASE NOTES, This is an emergency update that is meant to prevent the issue that took place yesterday and ended up stalling quite a few nodes. This means that Q-Mintership should be the ONLY APP UTILIZED FOR THE FUNCTIONALITY IT PROVIDES.
|
||||
<b class="version"><u>v1.06.4b</u></b>- <b>various improvements</b> - See post in the <a href="MINTERSHIP-FORUM">FORUM</a> for RELEASE NOTES.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user