diff --git a/assets/images/background1.jpg b/assets/images/background1.jpg new file mode 100644 index 0000000..15f02cf Binary files /dev/null and b/assets/images/background1.jpg differ diff --git a/assets/images/mbr-1-1818x1212.jpg b/assets/images/mbr-1-1818x1212.jpg new file mode 100644 index 0000000..1d9138f Binary files /dev/null and b/assets/images/mbr-1-1818x1212.jpg differ diff --git a/assets/images/mbr-1818x1212.jpg b/assets/images/mbr-1818x1212.jpg new file mode 100644 index 0000000..a0797ec Binary files /dev/null and b/assets/images/mbr-1818x1212.jpg differ diff --git a/assets/js/ARBoard.js b/assets/js/ARBoard.js new file mode 100644 index 0000000..fe97c4c --- /dev/null +++ b/assets/js/ARBoard.js @@ -0,0 +1,911 @@ + +let minterGroupAddresses +let minterAdminAddresses +let isTest = false +let isAddRemoveBoard = true +const addRemoveIdentifierPrefix = "QM-AR-card" +const loadAddRemoveAdminPage = async () => { + console.log("Loading Add/Remove Admin page...") + const bodyChildren = document.body.children + + for (let i = bodyChildren.length - 1; i >= 0; i--) { + const child = bodyChildren[i] + + if (!child.classList.contains("menu")) { + child.remove() + } + } + + const mainContainer = document.createElement("div") + mainContainer.className = "add-remove-admin-main" + mainContainer.style = "padding: 20px; text-align: center;" + mainContainer.innerHTML = ` +

Minter Admin Management

+

+ This page allows proposing the promotion of an existing minter to admin, + or demotion of an existing admin back to a normal minter. +

+ +
+

Existing Minter Admins

+
+
+ +
+ + +
+ +
+

Existing Promotion/Demotion Proposals

+ +
+
+ +
+ + ` + + document.body.appendChild(mainContainer) + + document.getElementById("propose-promotion-button").addEventListener("click", async () => { + try { + const fetchedCard = await fetchExistingARCard(addRemoveIdentifierPrefix) + if (fetchedCard) { + // An existing card is found + if (isTest) { + const updateCard = confirm("You have already published a promotion card, would you like to update that one or publish a new one?") + + if (updateCard) { + isExistingCard = true + await loadCardIntoForm(existingCardData) + alert("Edit your existing card and publish.") + } else { + alert("New Card Selected: You can now create a new promotion card.") + isExistingCard = false + existingCardData = {} + document.getElementById("publish-card-form").reset() + } + + } else { + // Not in test mode, force editing + alert("A card already exists. Publishing of multiple cards is not allowed. Please update your card.") + isExistingCard = true + await loadCardIntoForm(existingCardData) + } + + } else { + // No existing card found + console.log("No existing card found. Creating a new card.") + isExistingCard = false + } + // Show the form + const publishCardView = document.getElementById("promotion-form-container") + publishCardView.style.display = 'flex' + // publishCardView.style.display === "none" ? "flex" : "none" + // document.getElementById("existing-proposals-section").style.display = "none" + const proposeButton = document.getElementById('propose-promotion-button') + proposeButton.style.display = 'none' + // proposeButton.style.display === 'flex' ? 'none' : 'flex' + + } catch (error) { + console.error("Error checking for existing card:", error) + alert("Failed to check for existing card. Please try again.") + } + }) + + document.getElementById("refresh-cards-button").addEventListener("click", async () => { + const cardsContainer = document.getElementById("cards-container") + cardsContainer.innerHTML = "

Refreshing cards...

" + await loadCards(addRemoveIdentifierPrefix) + }) + + document.getElementById("cancel-publish-button").addEventListener("click", async () => { + // const cardsContainer = document.getElementById("existing-proposals-section") + // cardsContainer.style.display = "flex" // Restore visibility + const publishCardView = document.getElementById("promotion-form-container") + publishCardView.style.display = "none" // Hide the publish form + const proposeButton = document.getElementById('propose-promotion-button') + proposeButton.style.display = 'flex' + // proposeButton.style.display === 'flex' ? 'none' : 'flex' + }) + + document.getElementById("add-link-button").addEventListener("click", async () => { + const linksContainer = document.getElementById("links-container") + const newLinkInput = document.createElement("input") + newLinkInput.type = "text" + newLinkInput.className = "card-link" + newLinkInput.placeholder = "Enter QDN link" + linksContainer.appendChild(newLinkInput) + }) + + document.getElementById("publish-card-form").addEventListener("submit", async (event) => { + event.preventDefault() + await publishARCard(addRemoveIdentifierPrefix) + }) + await featureTriggerCheck() + await loadCards(addRemoveIdentifierPrefix) + await displayExistingMinterAdmins() + await fetchAllARTxData() +} + +const toggleProposeButton = () => { + const proposeButton = document.getElementById('propose-promotion-button') + proposeButton.style.display = + proposeButton.style.display === 'flex' ? 'none' : 'flex' +} + +let addAdminTxs +let remAdminTxs + +const fetchAllARTxData = async () => { + const addAdmTx = "ADD_GROUP_ADMIN" + const remAdmTx = "REMOVE_GROUP_ADMIN" + + const filterAddTransactions = (rawTransactions) => { + // Group transactions by member + const memberTxMap = rawTransactions.reduce((map, tx) => { + if (!map[tx.member]) { + map[tx.member] = [] + } + map[tx.member].push(tx) + return map + }, {}) + + // Filter out members with both pending and non-pending transactions + return Object.values(memberTxMap) + .filter(txs => txs.every(tx => tx.approvalStatus !== 'PENDING')) + .flat() + // .filter((txs) => !(txs.some(tx => tx.approvalStatus === 'PENDING') && + // txs.some(tx => tx.approvalStatus !== 'PENDING'))) + // .flat() + } + + const filterRemoveTransactions = (rawTransactions) => { + // Group transactions by member + const adminTxMap = rawTransactions.reduce((map, tx) => { + if (!map[tx.admin]) { + map[tx.admin] = [] + } + map[tx.admin].push(tx) + return map + }, {}) + + // Filter out members with both pending and non-pending transactions + return Object.values(adminTxMap) + .filter((txs) => !(txs.some(tx => tx.approvalStatus === 'PENDING') && + txs.some(tx => tx.approvalStatus !== 'PENDING'))) + .flat() + } + + // Fetch ban transactions + const allAddTxs = await searchTransactions({ + txTypes: [addAdmTx], + confirmationStatus: 'CONFIRMED', + limit: 0, + reverse: true, + offset: 0, + startBlock: 1990000, + blockLimit: 0, + txGroupId: 694, + }) + // Filter out 'PENDING' + addAdminTxs = filterAddTransactions(allAddTxs) + console.warn('addAdminTxData (no PENDING nor past+PENDING):', addAdminTxs) + + // Fetch kick transactions + const allRemTxs = await searchTransactions({ + txTypes: [remAdmTx], + confirmationStatus: 'CONFIRMED', + limit: 0, + reverse: true, + offset: 0, + startBlock: 1990000, + blockLimit: 0, + txGroupId: 694, + }) + // Filter out 'PENDING' + remAdminTxs = filterRemoveTransactions(allRemTxs) + console.warn('remAdminTxData (no PENDING nor past+PENDING):', remAdminTxs) + } + +const displayExistingMinterAdmins = async () => { + const adminListContainer = document.getElementById("admin-list-container") + adminListContainer.innerHTML = + "

Loading existing admins...

" + + try { + // 1) Fetch addresses + const admins = await fetchMinterGroupAdmins() + minterAdminAddresses = admins.map(m => m.member) + let rowsHtml = ""; + for (const adminAddr of admins) { + if (adminAddr.member === nullAddress) { + // Display a "NULL ACCOUNT" row + rowsHtml += ` + + + NULL ACCOUNT + + + ${nullAddress} + + + + — + + + ` + continue + } + // Attempt to get name + let adminName + try { + adminName = await getNameFromAddress(adminAddr.member) + } catch (err) { + console.warn(`Error fetching name for ${adminAddr.member}:`, err) + adminName = null + } + const displayName = adminName && adminName !== adminAddr.member ? adminName : "(No Name)" + rowsHtml += ` + + ${displayName} + ${adminAddr.member} + + + + + ` + } + // 3) Build the table + const tableHtml = ` + + + + + + + + + + ${rowsHtml} + +
Admin NameAdmin AddressActions
+ ` + adminListContainer.innerHTML = tableHtml + } catch (err) { + console.error("Error fetching minter admins:", err) + adminListContainer.innerHTML = + "

Failed to load admins.

" + } +} + +const handleProposeDemotionWrapper = (adminName, adminAddress) => { + // Call the async function and handle any unhandled rejections + handleProposeDemotion(adminName, adminAddress).catch(error => { + console.error(`Error in handleProposeDemotionWrapper:`, error) + alert("An unexpected error occurred. Please try again.") + }) + } + +const handleProposeDemotion = async (adminName, adminAddress) => { + console.log(`Proposing demotion for: ${adminName} (${adminAddress})`) + const proposeButton = document.getElementById('propose-promotion-button') + proposeButton.style.display = 'none' + const fetchedCard = await fetchExistingARCard(addRemoveIdentifierPrefix, adminName) + if (fetchedCard) { + alert("A card already exists. Publishing of multiple cards is not allowed. Please update your card.") + isExistingCard = true + await loadCardIntoForm(fetchedCard) + } + + + // Populate the form with the admin's name + const nameInput = document.getElementById("minter-name-input") + nameInput.value = adminName + + // Display the form if it's hidden + const formContainer = document.getElementById("promotion-form-container") + formContainer.style.display = "flex" + + // Optionally hide other sections (e.g., the existing proposals section) + // const proposalsSection = document.getElementById("existing-proposals-section") + // proposalsSection.style.display = "none" + + // Notify the user to fill out the rest + alert(`Admin "${adminName}" has been selected for demotion. Please fill out the rest of the form.`) + } + + const fetchExistingARCard = async (cardIdentifierPrefix, minterName) => { + try { + // 1. Fetch all cards with the specified prefix + const response = await searchSimple( + 'BLOG_POST', + `${cardIdentifierPrefix}`, + '', // Empty name to fetch all cards + 0, + 0, + '', + true + ) + + console.log(`SEARCH_QDN_RESOURCES response: ${JSON.stringify(response, null, 2)}`) + + if (!response || !Array.isArray(response) || response.length === 0) { + console.log("No cards found.") + return null + } + + // 2. Fetch minterGroupAddresses if not already fetched + if (!minterGroupAddresses) { + const groupData = await fetchMinterGroupMembers() + minterGroupAddresses = groupData.map((m) => m.member) + } + + // 3. Validate all fetched cards and check for duplicate `minterName` + const validatedCards = await Promise.all( + response.map(async (card) => { + const isValid = await validateCardStructure(card) + + if (!isValid) return null + + // Fetch full card data for validation + const cardDataResponse = await qortalRequest({ + action: "FETCH_QDN_RESOURCE", + name: card.name, + service: "BLOG_POST", + identifier: card.identifier, + }) + + // Check if `minterName` matches the input or is a duplicate + if (cardDataResponse.minterName === minterName) { + console.log(`Card with the same minterName found: ${minterName}`) + return { + card, + cardData: cardDataResponse, + } + } + + return null + }) + ) + + // 4. Filter out null results and check for duplicates + const matchingCards = validatedCards.filter((result) => result !== null) + + if (matchingCards.length > 0) { + const { card, cardData } = matchingCards[0] // Use the first matching card + + // Determine if the card is a promotion card + // const nameInfo = await getNameInfo(cardData.minterName) + // const ownerAddress = nameInfo?.owner + + // Set flags and return the existing card data + existingCardIdentifier = card.identifier + existingCardData = cardData + isExistingCard = true + + return { + cardData + } + } + + console.log("No valid cards found or no matching minterName.") + return null + } catch (error) { + console.error("Error fetching existing AR card:", error) + return null + } + } + + +const publishARCard = async (cardIdentifierPrefix) => { + const minterNameInput = document.getElementById("minter-name-input").value.trim() + const potentialNameInfo = await getNameInfo(minterNameInput) + let minterName + let address + let isPromotionCard + + if (potentialNameInfo.owner) { + console.log(`MINTER NAME FOUND:`, minterNameInput) + minterName = minterNameInput + address = potentialNameInfo.owner + } else { + console.warn(`user input an address?...`, minterNameInput) + if (!address){ + const validAddress = await getAddressInfo(minterNameInput) + if (validAddress){ + address = minterNameInput + } else { + console.error(`input address by user INVALID`, minterNameInput) + alert(`You have input an invalid address! Please try again...`) + return + } + } + const checkForName = await getNameFromAddress(minterNameInput) + if (checkForName) { + minterName = checkForName + } else if (!checkForName && address){ + console.warn(`user input an address that has no name...`) + alert(`you have input an address that has no name, the address will need to register a name prior to being able to be promoted`) + return + } else { + console.warn(`Input was either an invalid name, or incorrect address?`, minterNameInput) + alert(`Your input could not be validated, check the name/address and try again!`) + return + } + } + + const minterGroupData = await fetchMinterGroupMembers() + minterGroupAddresses = minterGroupData.map(m => m.member) + + const minterAdminGroupData = await fetchMinterGroupAdmins() + minterAdminAddresses = minterAdminGroupData.map(m => m.member) + + if (minterGroupAddresses.includes(address)) { + isPromotionCard = true + console.warn(`address is a MINTER, this is a promotion card...`) + } + + if (minterAdminAddresses.includes(address)){ + isPromotionCard = false + console.warn(`this is a DEMOTION`, address) + } + + if (!minterAdminAddresses.includes(address) && !minterGroupAddresses.includes(address)) { + console.error(`you cannot publish a card here unless the user is a MINTER or an ADMIN!`) + alert(`Card cannot be published for an account that is neither a minter nor an admin! This board is for Promotions and Demotions of Admins ONLY!`) + 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")) + .map(input => input.value.trim()) + .filter(link => link.startsWith("qortal://")) + + if (!header || !content) { + alert("Header and content are required!") + return + } + + const cardIdentifier = isExistingCard ? existingCardIdentifier : `${cardIdentifierPrefix}-${await uid()}` + const pollName = `${cardIdentifier}-poll` + const pollDescription = `AR Board Card Proposed By: ${userState.accountName}` + + const cardData = { + minterName, + header, + content, + links, + creator: userState.accountName, + timestamp: Date.now(), + poll: pollName, + promotionCard: isPromotionCard + } + + try { + let base64CardData = await objectToBase64(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, + service: "BLOG_POST", + identifier: cardIdentifier, + data64: base64CardData, + }) + + if (!isExistingCard){ + await qortalRequest({ + action: "CREATE_POLL", + pollName, + pollDescription, + pollOptions: ['Yes, No'], + pollOwnerAddress: userState.accountAddress, + }) + alert("Card and poll published successfully!") + } + + if (isExistingCard){ + alert("Card Updated Successfully! (No poll updates are possible at this time...)") + isExistingCard = false + } + + document.getElementById("publish-card-form").reset() + document.getElementById("promotion-form-container").style.display = "none" + // document.getElementById("cards-container").style.display = "flex" + + await loadCards(addRemoveIdentifierPrefix) + + } catch (error) { + + console.error("Error publishing card or poll:", error) + alert("Failed to publish card and poll.") + } +} + +const checkAndDisplayActions = async (adminYes, name, cardIdentifier) => { + const latestBlockInfo = await getLatestBlockInfo() + const isBlockPassed = latestBlockInfo.height >= GROUP_APPROVAL_FEATURE_TRIGGER_HEIGHT + let minAdminCount + const minterAdmins = await fetchMinterGroupAdmins() + + if ((minterAdmins) && (minterAdmins.length === 1)){ + console.warn(`simply a double-check that there is only one MINTER group admin, in which case the group hasn't been transferred to null...keeping default minAdminCount of: ${minAdminCount}`) + minAdminCount = 9 + } else if ((minterAdmins) && (minterAdmins.length > 1) && isBlockPassed){ + const totalAdmins = minterAdmins.length + const fortyPercent = totalAdmins * 0.40 + minAdminCount = Math.round(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) + const address = addressInfo.owner + + if (isBlockPassed) { + console.warn(`feature trigger has passed, checking for approval requirements`) + const addAdminApprovalHtml = await checkGroupApprovalAndCreateButton(address, cardIdentifier, "ADD_GROUP_ADMIN") + const removeAdminApprovalHtml = await checkGroupApprovalAndCreateButton(address, cardIdentifier, "REMOVE_GROUP_ADMIN") + + if (addAdminApprovalHtml) { + return addAdminApprovalHtml + } + + if (removeAdminApprovalHtml) { + return removeAdminApprovalHtml + } + } + + if (!minterGroupAddresses) { + const minterGroupData = await fetchMinterGroupMembers() + minterGroupAddresses = minterGroupData.map(m => m.member) + } + + if (!minterAdminAddresses) { + const adminAddressData = await fetchMinterGroupAdmins() + minterAdminAddresses = adminAddressData.map(m => m.member) + } + + if (!minterGroupAddresses.includes(userState.accountAddress)){ + console.warn(`User is not in the MINTER group, no need for buttons`) + return null + } + + if (adminYes >= minAdminCount && (minterAdminAddresses.includes(address))){ + const removeAdminHtml = createRemoveAdminButton(name, cardIdentifier, address) + return removeAdminHtml + } else if (adminYes >= minAdminCount && (minterGroupAddresses.includes(address))){ + const addAdminHtml = createAddAdminButton(name, cardIdentifier, address) + return addAdminHtml + } +} + +const createAddAdminButton = (name, cardIdentifier, address) => { + return ` +
+ +
+ ` +} + +const createRemoveAdminButton = (name, cardIdentifier, address) => { + return ` +
+ +
+ ` +} + +const handleAddMinterGroupAdmin = async (name, address) => { + try { + // Optional block check + let txGroupId = 0 + let member = address + // const { height: currentHeight } = await getLatestBlockInfo() + const isBlockPassed = await featureTriggerCheck() + if (isBlockPassed) { + console.log(`block height above featureTrigger Height, using group approval method...txGroupId 694`) + txGroupId = 694 + } + + const ownerPublicKey = await getPublicKeyFromAddress(userState.accountAddress) + const fee = 0.01 + + const rawTx = await createAddGroupAdminTransaction(ownerPublicKey, 694, member, txGroupId, fee) + + const signedTx = await qortalRequest({ + action: "SIGN_TRANSACTION", + unsignedBytes: rawTx + }) + + if (!signedTx) { + console.warn(`this only happens if the SIGN_TRANSACTION qortalRequest failed... are you using the legacy UI prior to this qortalRequest being added?`) + alert(`this only happens if the SIGN_TRANSACTION qortalRequest failed... are you using the legacy UI prior to this qortalRequest being added? Please talk to developers.`) + return + } + + let txToProcess = signedTx + + const processTx = await processTransaction(txToProcess) + + if (typeof processTx === 'object') { + console.log("transaction success object:", processTx) + alert(`${name} kick successfully issued! Wait for confirmation...Transaction Response: ${JSON.stringify(processTx)}`) + } else { + console.log("transaction raw text response:", processTx) + alert(`TxResponse: ${JSON.stringify(processTx)}`) + } + + } catch (error) { + console.error("Error removing minter:", error) + alert(`Error:${error}. Please try again.`) + } +} + +const handleRemoveMinterGroupAdmin = async (name, address) => { + try { + // Optional block check + let txGroupId = 0 + const admin = address + // const { height: currentHeight } = await getLatestBlockInfo() + const isBlockPassed = await featureTriggerCheck() + if (isBlockPassed) { + console.log(`block height above featureTrigger Height, using group approval method...txGroupId 694`) + txGroupId = 694 + } + + const ownerPublicKey = await getPublicKeyFromAddress(userState.accountAddress) + const fee = 0.01 + + const rawTx = await createRemoveGroupAdminTransaction(ownerPublicKey, 694, admin, txGroupId, fee) + + const signedTx = await qortalRequest({ + action: "SIGN_TRANSACTION", + unsignedBytes: rawTx + }) + if (!signedTx) { + console.warn(`this only happens if the SIGN_TRANSACTION qortalRequest failed... are you using the legacy UI prior to this qortalRequest being added?`) + alert(`this only happens if the SIGN_TRANSACTION qortalRequest failed... are you using the legacy UI prior to this qortalRequest being added? Please talk to developers.`) + return + } + + let txToProcess = signedTx + + const processTx = await processTransaction(txToProcess) + + if (typeof processTx === 'object') { + console.log("transaction success object:", processTx) + alert(`${name} kick successfully issued! Wait for confirmation...Transaction Response: ${JSON.stringify(processTx)}`) + } else { + console.log("transaction raw text response:", processTx) + alert(`TxResponse: ${JSON.stringify(processTx)}`) + } + + } catch (error) { + console.error("Error removing minter:", error) + alert(`Error:${error}. Please try again.`) + } +} + +const fallbackMinterCheck = async (minterName, minterGroupMembers, minterAdmins) => { + // Ensure we have addresses + if (!minterGroupMembers) { + console.warn("No minterGroupMembers array was passed in fallback check!") + return false + } + const minterGroupAddresses = minterGroupMembers.map(m => m.member) + const adminAddresses = minterAdmins.map(m => m.member) + const minterAcctInfo = await getNameInfo(minterName) + if (!minterAcctInfo || !minterAcctInfo.owner) { + console.warn(`Name info not found or missing 'owner' for ${minterName}`) + return false + } + // If user is already in the group => we call it a "promotion card" + if (adminAddresses.includes(minterAcctInfo.owner)) { + console.warn(`display check found minterAdminCard - NOT a promotion card...`) + return false + } else { + return minterGroupAddresses.includes(minterAcctInfo.owner) + } +} + + +const createARCardHTML = async (cardData, pollResults, cardIdentifier, commentCount) => { + const { minterName, header, content, links, creator, timestamp, poll, promotionCard } = cardData + const formattedDate = new Date(timestamp).toLocaleString() + const minterAvatar = await getMinterAvatar(minterName) + const creatorAvatar = await getMinterAvatar(creator) + const linksHTML = links.map((link, index) => ` + + `).join("") + + const minterGroupMembers = await fetchMinterGroupMembers() + const minterAdmins = await fetchMinterGroupAdmins() + + let showPromotionCard = false + showPromotionCard = await fallbackMinterCheck(minterName, minterGroupMembers, minterAdmins) + + // if (typeof promotionCard === 'boolean') { + // showPromotionCard = promotionCard; + // } else if (typeof promotionCard === 'string') { + // // Could be "true" or "false" or something else + // const lower = promotionCard.trim().toLowerCase() + // if (lower === "true") { + // showPromotionCard = true + // } else if (lower === "false") { + // showPromotionCard = false + // } else { + // // Unexpected string => fallback + // console.warn(`Unexpected string in promotionCard="${promotionCard}"`) + // showPromotionCard = await fallbackMinterCheck(minterName, minterGroupMembers) + // } + // } else if (promotionCard == null) { + // // null or undefined => fallback check + // console.warn(`No promotionCard field in card data, doing manual check...`) + // showPromotionCard = await fallbackMinterCheck(minterName, minterGroupMembers) + // } else { + // // If it’s an object or something else weird => fallback + // console.warn(`promotionCard has unexpected type, fallback...`) + // showPromotionCard = await fallbackMinterCheck(minterName, minterGroupMembers) + // } + + let cardColorCode = (showPromotionCard) ? 'rgb(17, 44, 46)' : 'rgb(57, 11, 13)' + + const promotionDemotionHtml = (showPromotionCard) ? ` +
REGARDING (Promotion):
+

${minterName}

` : + ` +
REGARDING (Demotion):
+ ${minterAvatar} +

${minterName}

` + + if (!promotionDemotionHtml){ + console.warn(`promotionDemotionHtml missing!`) + } + const { adminYes = 0, adminNo = 0, minterYes = 0, minterNo = 0, totalYes = 0, totalNo = 0, totalYesWeight = 0, totalNoWeight = 0, detailsHtml } = await processPollData(pollResults, minterGroupMembers, minterAdmins, creator, cardIdentifier) + + createModal('links') + createModal('poll-details') + + let actionsHtml + let altText + const verifiedName = await validateMinterName(minterName) + + if (verifiedName) { + const accountInfo = await getNameInfo(verifiedName) + const accountAddress = accountInfo.owner + console.log(`name is validated, utilizing for removal features...${verifiedName}`) + const actionsHtmlCheck = await checkAndDisplayActions(adminYes, verifiedName, cardIdentifier) + actionsHtml = actionsHtmlCheck + + if (!addAdminTxs || !remAdminTxs) { + await fetchAllARTxData() + } + + if (addAdminTxs.some((addTx) => addTx.groupId === 694 && addTx.member === accountAddress)){ + console.warn(`account was already adminified(PROMOTED), displaying as such...`) + cardColorCode = 'rgb(3, 11, 24)' + altText = `

PROMOTED to ADMIN

` + actionsHtml = '' + // =============================================================== if 'showPromotedDemoted' is wanted to be added. + // if (!showPromotedDemoted){ + // console.warn(`promoted/demoted show checkbox is unchecked, and card is promoted, not displaying...`) + // return '' + // } + } + + if (remAdminTxs.some((remTx) => remTx.groupId === 694 && remTx.admin === accountAddress)){ + console.warn(`account was already UNadminified(DEMOTED), displaying as such...`) + cardColorCode = 'rgb(29, 4, 6)' + altText = `

DEMOTED from ADMIN

` + actionsHtml = '' + + // if (!showPromotedDemoted) { + // console.warn(`promoted/demoted show checkbox is unchecked, card is demoted, not displaying...`) + // return '' + // } + } + + } else { + console.log(`name could not be validated, assuming topic card (or some other issue with name validation) for removalActions`) + actionsHtml = '' + } + + return ` +
+
+

Created By:

+ ${creatorAvatar} +

${creator}

+ ${promotionDemotionHtml} +

${header}

+ ${altText} +
+
+ ${content} +
+
LINKS
+ +
CURRENT RESULTS
+
+ + + ${actionsHtml} +
+ Admin Support: ${adminYes} + Admin Against: ${adminNo} +
+
+ Minter Yes: ${minterYes} + Minter No: ${minterNo} +
+
+ Total Yes: ${totalYes} + Weight: ${totalYesWeight} + Total No: ${totalNo} + Weight: ${totalNoWeight} +
+
+
ACTIONS FOR
${minterName}
+

(click COMMENTS button to open/close card comments)

+
+
+
+ + + +
+
+ +

By: ${creator} - ${formattedDate}

+
+ ` +} \ No newline at end of file