const cardIdentifierPrefix = "test-board-card"; let isExistingCard = false let existingCard = {} document.addEventListener("DOMContentLoaded", async () => { const minterBoardLinks = document.querySelectorAll('a[href="MINTER-BOARD"], a[href="MINTERS"]'); minterBoardLinks.forEach(link => { link.addEventListener("click", async (event) => { event.preventDefault(); if (!userState.isLoggedIn) { await login(); } await loadMinterBoardPage(); }); }); }); async function loadMinterBoardPage() { // Clear existing content on the 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(); } } // Add the "Minter Board" content const mainContent = document.createElement("div"); mainContent.innerHTML = `

Minter Board

`; document.body.appendChild(mainContent); document.getElementById("publish-card-button").addEventListener("click", async () => { existingCard = await fetchExistingCard(); if (existingCard) { const updateCard = confirm("You already have a card. Do you want to update it?"); isExistingCard = true if (updateCard) { loadCardIntoForm(existingCard); document.getElementById("publish-card-view").style.display = "block"; document.getElementById("cards-container").style.display = "none"; } } else { document.getElementById("publish-card-view").style.display = "block"; document.getElementById("cards-container").style.display = "none"; } }); document.getElementById("cancel-publish").addEventListener("click", () => { document.getElementById("publish-card-view").style.display = "none"; document.getElementById("cards-container").style.display = "block"; }); document.getElementById("add-link-button").addEventListener("click", () => { 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 publishCard(); }); await loadCards(); } async function fetchExistingCard() { try { const response = await qortalRequest({ action: "SEARCH_QDN_RESOURCES", service: "BLOG_POST", nameListFilter: userState.accountName, query: cardIdentifierPrefix, }); existingCard = response.find(card => card.name === userState.accountName); if (existingCard) { const cardDataResponse = await qortalRequest({ action: "FETCH_QDN_RESOURCE", name: existingCard.name, service: "BLOG_POST", identifier: existingCard.identifier, }); return cardDataResponse; } return null; } catch (error) { console.error("Error fetching existing card:", error); return null; } } function loadCardIntoForm(cardData) { document.getElementById("card-header").value = cardData.header; document.getElementById("card-content").value = cardData.content; const linksContainer = document.getElementById("links-container"); linksContainer.innerHTML = ""; // Clear previous links cardData.links.forEach(link => { const linkInput = document.createElement("input"); linkInput.type = "text"; linkInput.className = "card-link"; linkInput.value = link; linksContainer.appendChild(linkInput); }); } async function publishCard() { 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 ? existingCard.identifier : `${cardIdentifierPrefix}-${await uid()}`; const pollName = `${cardIdentifier}-poll`; const pollDescription = `Mintership Board Poll for ${userState.accountName}`; const cardData = { header, content, links, creator: userState.accountName, timestamp: Date.now(), poll: pollName, }; // new Date().toISOString() try { let base64CardData = await objectToBase64(cardData); if (!base64CardData) { console.log(`initial base64 object creation with objectToBase64 failed, using btoa...`); base64CardData = btoa(JSON.stringify(cardData)); } // const base64CardData = btoa(JSON.stringify(cardData)); await qortalRequest({ action: "PUBLISH_QDN_RESOURCE", name: userState.accountName, service: "BLOG_POST", identifier: cardIdentifier, data64: base64CardData, }); await qortalRequest({ action: "CREATE_POLL", pollName, pollDescription, pollOptions: ["Yes", "No", "Comment"], pollOwnerAddress: userState.accountAddress, }); alert("Card and poll published successfully!"); document.getElementById("publish-card-form").reset(); document.getElementById("publish-card-view").style.display = "none"; document.getElementById("cards-container").style.display = "block"; await loadCards(); } catch (error) { console.error("Error publishing card or poll:", error); alert("Failed to publish card and poll."); } } async function loadCards() { const cardsContainer = document.getElementById("cards-container"); cardsContainer.innerHTML = "

Loading cards...

"; try { const response = await qortalRequest({ action: "SEARCH_QDN_RESOURCES", service: "BLOG_POST", query: cardIdentifierPrefix, }); if (!response || response.length === 0) { cardsContainer.innerHTML = "

No cards found.

"; return; } cardsContainer.innerHTML = ""; const pollResultsCache = {}; for (const card of response) { const cardDataResponse = await qortalRequest({ action: "FETCH_QDN_RESOURCE", name: card.name, service: "BLOG_POST", identifier: card.identifier, }); const cardData = cardDataResponse; // Cache poll results if (!pollResultsCache[cardData.poll]) { pollResultsCache[cardData.poll] = await fetchPollResults(cardData.poll); } const pollResults = pollResultsCache[cardData.poll]; const cardHTML = await createCardHTML(cardData, pollResults); cardsContainer.insertAdjacentHTML("beforeend", cardHTML); } } catch (error) { console.error("Error loading cards:", error); cardsContainer.innerHTML = "

Failed to load cards.

"; } } const calculatePollResults = (pollData, minterGroupMembers) => { const memberAddresses = minterGroupMembers.map(member => member.member); let adminYes = 0, adminNo = 0, minterYes = 0, minterNo = 0; pollData.votes.forEach(vote => { const voterAddress = vote.voterPublicKey; const isAdmin = minterGroupMembers.some(member => member.member === voterAddress && member.isAdmin); if (vote.optionIndex === 1) { isAdmin ? adminYes++ : memberAddresses.includes(voterAddress) ? minterYes++ : null; } else if (vote.optionIndex === 0) { isAdmin ? adminNo++ : memberAddresses.includes(voterAddress) ? minterNo++ : null; } }); const totalYes = adminYes + minterYes; const totalNo = adminNo + minterNo; return { adminYes, adminNo, minterYes, minterNo, totalYes, totalNo }; }; const postComment = async (cardIdentifier) => { const commentInput = document.getElementById(`new-comment-${cardIdentifier}`); const commentText = commentInput.value.trim(); if (!commentText) { alert('Comment cannot be empty!'); return; } const commentData = { content: commentText, creator: userState.accountName, timestamp: Date.now(), }; const commentIdentifier = `${cardIdentifier}-comment-${await uid()}`; try { const base64CommentData = await objectToBase64(commentData); if (!base64CommentData) { console.log(`initial base64 object creation with objectToBase64 failed, using btoa...`); base64CommentData = btoa(JSON.stringify(commentData)); } // const base64CommentData = btoa(JSON.stringify(commentData)); await qortalRequest({ action: 'PUBLISH_QDN_RESOURCE', name: userState.accountName, service: 'BLOG_POST', identifier: commentIdentifier, data64: base64CommentData, }); alert('Comment posted successfully!'); commentInput.value = ''; // Clear input await displayComments(cardIdentifier); // Refresh comments } catch (error) { console.error('Error posting comment:', error); alert('Failed to post comment.'); } }; const fetchCommentsForCard = async (cardIdentifier) => { try { const response = await qortalRequest({ action: 'SEARCH_QDN_RESOURCES', service: 'BLOG_POST', query: `${cardIdentifier}-comment`, }); return response; } catch (error) { console.error(`Error fetching comments for ${cardIdentifier}:`, error); return []; } }; const displayComments = async (cardIdentifier) => { const comments = await fetchCommentsForCard(cardIdentifier); const commentsContainer = document.getElementById(`comments-container-${cardIdentifier}`); commentsContainer.innerHTML = comments.map(comment => `

${comment.creator}:

${comment.content}

${timestampToHumanReadableDate(comment.timestamp)}

`).join(''); }; const toggleComments = async (cardIdentifier) => { const commentsSection = document.getElementById(`comments-section-${cardIdentifier}`); if (commentsSection.style.display === 'none' || !commentsSection.style.display) { await displayComments(cardIdentifier); commentsSection.style.display = 'block'; } else { commentsSection.style.display = 'none'; } }; async function loadCards() { const cardsContainer = document.getElementById("cards-container"); cardsContainer.innerHTML = "

Loading cards...

"; try { const response = await qortalRequest({ action: "SEARCH_QDN_RESOURCES", service: "BLOG_POST", query: cardIdentifierPrefix, }); if (!response || response.length === 0) { cardsContainer.innerHTML = "

No cards found.

"; return; } cardsContainer.innerHTML = ""; const pollResultsCache = {}; for (const card of response) { const cardDataResponse = await qortalRequest({ action: "FETCH_QDN_RESOURCE", name: card.name, service: "BLOG_POST", identifier: card.identifier, }); const cardData = cardDataResponse; // Cache poll results if (!pollResultsCache[cardData.poll]) { pollResultsCache[cardData.poll] = await fetchPollResults(cardData.poll); } const pollResults = pollResultsCache[cardData.poll]; const cardHTML = await createCardHTML(cardData, pollResults); cardsContainer.insertAdjacentHTML("beforeend", cardHTML); } } catch (error) { console.error("Error loading cards:", error); cardsContainer.innerHTML = "

Failed to load cards.

"; } } function toggleFullContent(cardIdentifier, fullContent) { const contentPreview = document.getElementById(`content-preview-${cardIdentifier}`); const toggleButton = document.getElementById(`toggle-content-${cardIdentifier}`); const isExpanded = contentPreview.getAttribute("data-expanded") === "true"; if (isExpanded) { // Collapse the content contentPreview.innerText = `${fullContent.substring(0, 150)}...`; toggleButton.innerText = "Display Full Text"; contentPreview.setAttribute("data-expanded", "false"); } else { // Expand the content contentPreview.innerText = fullContent; toggleButton.innerText = "Show Less"; contentPreview.setAttribute("data-expanded", "true"); } } async function createCardHTML(cardData, pollResults) { const { header, content, links, creator, timestamp, poll } = cardData; const formattedDate = new Date(timestamp).toLocaleString(); const linksHTML = links.map((link, index) => ` `).join(""); const minterGroupMembers = await fetchMinterGroupMembers(); const { adminYes, adminNo, minterYes, minterNo, totalYes, totalNo } = calculatePollResults(pollResults, minterGroupMembers); const trimmedContent = content.length > 150 ? `${content.substring(0, 150)}...` : content; return `

${creator}

${header}

Minter's Message
${trimmedContent}
${ content.length > 150 ? `` : "" }
Admin Yes: ${adminYes} Admin No: ${adminNo}
Minter Yes: ${minterYes} Minter No: ${minterNo}
Total Yes: ${totalYes} Total No: ${totalNo}
Support Minter

Published by: ${creator} on ${formattedDate}

` }