Refreshing cards...
"
+ // Re-load the cards using the same function that handles sorting logic
+ await loadCards(addRemoveIdentifierPrefix)
+ })
+
document.getElementById("cancel-publish-button").addEventListener("click", async () => {
// const cardsContainer = document.getElementById("existing-proposals-section")
// cardsContainer.style.display = "flex" // Restore visibility
@@ -133,6 +147,19 @@ const toggleProposeButton = () => {
proposeButton.style.display === 'flex' ? 'none' : 'flex'
}
+const toggleAdminTable = () => {
+ const tableContainer = document.getElementById("adminTableContainer")
+ const toggleBtn = document.getElementById("toggleAdminTableButton")
+
+ if (tableContainer.style.display === "none") {
+ tableContainer.style.display = "block"
+ toggleBtn.textContent = "Hide Minter Admins"
+ } else {
+ tableContainer.style.display = "none"
+ toggleBtn.textContent = "Show Minter Admins"
+ }
+}
+
const fetchAllARTxData = async () => {
const addAdmTx = "ADD_GROUP_ADMIN"
const remAdmTx = "REMOVE_GROUP_ADMIN"
@@ -216,6 +243,9 @@ const displayExistingMinterAdmins = async () => {
// 1) Fetch addresses
const admins = await fetchMinterGroupAdmins()
minterAdminAddresses = admins.map(m => m.member)
+ // Compute total admin count and signatures needed (40%, rounded up)
+ const totalAdmins = admins.length;
+ const signaturesNeeded = Math.ceil(totalAdmins * 0.40);
let rowsHtml = "";
for (const adminAddr of admins) {
if (adminAddr.member === nullAddress) {
@@ -262,6 +292,22 @@ const displayExistingMinterAdmins = async () => {
}
// 3) Build the table
const tableHtml = `
+
@@ -274,8 +320,13 @@ const displayExistingMinterAdmins = async () => {
${rowsHtml}
+
`
- adminListContainer.innerHTML = tableHtml
+ adminListContainer.innerHTML = `
+
Existing Minter Admins: ${totalAdmins}
+ Signatures for Group Approval (40%): ${signaturesNeeded}
+ ${tableHtml}
+ `;
} catch (err) {
console.error("Error fetching minter admins:", err)
adminListContainer.innerHTML =
@@ -550,7 +601,7 @@ const checkAndDisplayActions = async (adminYes, name, cardIdentifier) => {
} else if ((minterAdmins) && (minterAdmins.length > 1) && isBlockPassed){
const totalAdmins = minterAdmins.length
const fortyPercent = totalAdmins * 0.40
- minAdminCount = Math.round(fortyPercent)
+ minAdminCount = Math.ceil(fortyPercent)
console.warn(`this is another check to ensure minterAdmin group has more than 1 admin. IF so we will calculate the 40% needed for GROUP_APPROVAL, that number is: ${minAdminCount}`)
}
const addressInfo = await getNameInfo(name)
@@ -711,6 +762,47 @@ const handleRemoveMinterGroupAdmin = async (name, address) => {
}
}
+// ADDED: A simple function to effectively 'delete' an AR Board card
+// by publishing an empty card with the same identifier and prefix
+const deleteARCard = async (cardIdentifier, prefix) => {
+ try {
+ const confirmed = confirm("Are you sure you want to delete this card? This action cannot be undone.")
+ if (!confirmed) return
+
+ // A minimal blank object
+ const blankData = {
+ header: "",
+ content: "",
+ links: [],
+ creator: userState.accountName,
+ timestamp: Date.now(),
+ poll: "" // or null. This ensures it won't appear as a valid poll card
+ }
+
+ let base64Data = await objectToBase64(blankData)
+ if (!base64Data) {
+ base64Data = btoa(JSON.stringify(blankData))
+ }
+
+ await qortalRequest({
+ action: "PUBLISH_QDN_RESOURCE",
+ name: userState.accountName,
+ service: "BLOG_POST", // same as all ARBoard content
+ identifier: cardIdentifier,
+ data64: base64Data,
+ })
+
+ alert("Your card has been effectively deleted.")
+
+ // Now reload the existing ARBoard cards so the UI no longer shows the old card
+ await loadCards(prefix)
+
+ } catch (error) {
+ console.error("Error deleting AR card:", error)
+ alert("Failed to delete the card. Check console for details.")
+ }
+}
+
const fallbackMinterCheck = async (minterName, minterGroupMembers, minterAdmins) => {
// Ensure we have addresses
if (!minterGroupMembers) {
@@ -909,6 +1001,16 @@ const createARCardHTML = async (cardData, pollResults, cardIdentifier, commentCo
+ ${creator === userState.accountName ? `
+
Loading cards...
" + cardsContainer.innerHTML = `Loading cards...
` if (cardIdentifierPrefix.startsWith("QM-AR-card")) { isARBoard = true @@ -1118,6 +1118,11 @@ const displayComments = async (cardIdentifier) => { const commentHTMLArray = await Promise.all( comments.map(async (comment) => { try { + // If the name of the commenter is in the "spamNames" array, return null + if (spamNames.includes(comment.name)) { + console.warn(`Commenter ${comment.name} is in the spamNames array, skipping...`) + return null + } const commentDataResponse = await qortalRequest({ action: "FETCH_QDN_RESOURCE", name: comment.name, @@ -1394,10 +1399,18 @@ const handleInviteMinter = async (minterName) => { } } +function escapeForHtmlAttribute(str) { + return str + .replace(/'/g, ''') + .replace(/"/g, '"'); +} + const createInviteButtonHtml = (creator, cardIdentifier) => { + // Safely escape special chars so they won't break the HTML attribute + const safeCreator = escapeForHtmlAttribute(creator); return `
@@ -572,12 +576,12 @@Q-Mintership (v1.04b)
+Q-Mintership v1.04beta
+