2024-12-17 22:24:40 -08:00
// // NOTE - Change isTestMode to false prior to actual release ---- !important - You may also change identifier if you want to not show older cards.
2024-12-24 00:27:17 -08:00
const testMode = false ;
const cardIdentifierPrefix = "Minter-board-card" ;
2024-12-11 14:40:32 -08:00
let isExistingCard = false ;
let existingCardData = { } ;
2024-12-16 19:53:37 -08:00
let existingCardIdentifier = { } ;
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
const loadMinterBoardPage = async ( ) => {
2024-12-11 14:40:32 -08:00
// 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" ) ;
2024-12-24 00:27:17 -08:00
const publishButtonColor = '#527c9d'
const minterBoardNameColor = '#527c9d'
2024-12-11 14:40:32 -08:00
mainContent . innerHTML = `
< div class = "minter-board-main" style = "padding: 20px; text-align: center;" >
2024-12-20 22:07:18 -08:00
< h1 style = "color: ${minterBoardNameColor};" > Minter Board < / h 1 >
< 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 < / b u t t o n >
2024-12-16 19:53:37 -08:00
< button id = "refresh-cards-button" class = "refresh-cards-button" style = "padding: 10px;" > Refresh Cards < / b u t t o n >
2024-12-11 14:40:32 -08:00
< div id = "cards-container" class = "cards-container" style = "margin-top: 20px;" > < / d i v >
< div id = "publish-card-view" class = "publish-card-view" style = "display: none; text-align: left; padding: 20px;" >
< form id = "publish-card-form" >
< h3 > Create or Update Your Minter Card < / h 3 >
< label for = "card-header" > Header : < / l a b e l >
< input type = "text" id = "card-header" maxlength = "100" placeholder = "Enter card header" required >
< label for = "card-content" > Content : < / l a b e l >
< textarea id = "card-content" placeholder = "Enter detailed information about why you deserve to be a minter..." required > < / t e x t a r e a >
< label for = "card-links" > Links ( qortal : //...):</label>
< div id = "links-container" >
< input type = "text" class = "card-link" placeholder = "Enter QDN link" >
< / d i v >
< button type = "button" id = "add-link-button" > Add Another Link < / b u t t o n >
< button type = "submit" id = "submit-publish-button" > Publish Card < / b u t t o n >
< button type = "button" id = "cancel-publish-button" > Cancel < / b u t t o n >
< / f o r m >
< / d i v >
< / d i v >
` ;
document . body . appendChild ( mainContent ) ;
document . getElementById ( "publish-card-button" ) . addEventListener ( "click" , async ( ) => {
try {
2024-12-16 19:53:37 -08:00
const fetchedCard = await fetchExistingCard ( ) ;
if ( fetchedCard ) {
// An existing card is found
if ( testMode ) {
// In test mode, ask user what to do
const updateCard = confirm ( "A card already exists. Do you want to update it?" ) ;
if ( updateCard ) {
isExistingCard = true ;
await loadCardIntoForm ( existingCardData ) ;
alert ( "Edit your existing card and publish." ) ;
} else {
alert ( "Test mode: You can now create a new card." ) ;
isExistingCard = false ;
existingCardData = { } ; // Reset
document . getElementById ( "publish-card-form" ) . reset ( ) ;
}
2024-12-11 14:40:32 -08:00
} else {
2024-12-16 19:53:37 -08:00
// 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 ) ;
2024-12-11 14:40:32 -08:00
}
} else {
2024-12-16 19:53:37 -08:00
// No existing card found
2024-12-11 14:40:32 -08:00
alert ( "No existing card found. Create a new card." ) ;
isExistingCard = false ;
}
2024-12-16 19:53:37 -08:00
// Show the form
2024-12-11 14:40:32 -08:00
const publishCardView = document . getElementById ( "publish-card-view" ) ;
publishCardView . style . display = "flex" ;
document . getElementById ( "cards-container" ) . style . display = "none" ;
} catch ( error ) {
console . error ( "Error checking for existing card:" , error ) ;
alert ( "Failed to check for existing card. Please try again." ) ;
}
} ) ;
2024-12-16 19:53:37 -08:00
document . getElementById ( "refresh-cards-button" ) . addEventListener ( "click" , async ( ) => {
const cardsContainer = document . getElementById ( "cards-container" ) ;
cardsContainer . innerHTML = "<p>Refreshing cards...</p>" ;
await loadCards ( ) ;
} ) ;
2024-12-12 17:23:34 -08:00
document . getElementById ( "cancel-publish-button" ) . addEventListener ( "click" , async ( ) => {
2024-12-11 14:40:32 -08:00
const cardsContainer = document . getElementById ( "cards-container" ) ;
cardsContainer . style . display = "flex" ; // Restore visibility
const publishCardView = document . getElementById ( "publish-card-view" ) ;
publishCardView . style . display = "none" ; // Hide the publish form
} ) ;
2024-12-12 17:23:34 -08:00
document . getElementById ( "add-link-button" ) . addEventListener ( "click" , async ( ) => {
2024-12-11 14:40:32 -08:00
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 ( ) ;
}
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
const extractMinterCardsMinterName = async ( cardIdentifier ) => {
// Ensure the identifier starts with the prefix
if ( ! cardIdentifier . startsWith ( ` ${ cardIdentifierPrefix } - ` ) ) {
2024-12-27 23:04:16 -08:00
throw new Error ( 'Invalid identifier format or prefix mismatch' )
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
}
// Split the identifier into parts
2024-12-27 23:04:16 -08:00
const parts = cardIdentifier . split ( '-' )
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
// Ensure the format has at least 3 parts
if ( parts . length < 3 ) {
2024-12-27 23:04:16 -08:00
throw new Error ( 'Invalid identifier format' )
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
}
try {
2024-12-27 23:04:16 -08:00
const searchSimpleResults = await searchSimple ( 'BLOG_POST' , ` ${ cardIdentifier } ` , '' , 1 )
const minterName = await searchSimpleResults . name
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
return minterName
} catch ( error ) {
throw error
}
}
const processMinterCards = async ( validMinterCards ) => {
const latestCardsMap = new Map ( )
// Step 1: Filter and keep the most recent card per identifier
validMinterCards . forEach ( card => {
const timestamp = card . updated || card . created || 0
const existingCard = latestCardsMap . get ( card . identifier )
if ( ! existingCard || timestamp > ( existingCard . updated || existingCard . created || 0 ) ) {
latestCardsMap . set ( card . identifier , card )
}
} )
// Step 2: Extract unique cards
const uniqueValidCards = Array . from ( latestCardsMap . values ( ) )
// Step 3: Group by minterName and select the most recent card per minterName
const minterNameMap = new Map ( )
for ( const card of validMinterCards ) {
const minterName = await extractMinterCardsMinterName ( card . identifier )
const existingCard = minterNameMap . get ( minterName )
const cardTimestamp = card . updated || card . created || 0
const existingTimestamp = existingCard ? . updated || existingCard ? . created || 0
// Keep only the most recent card for each minterName
if ( ! existingCard || cardTimestamp > existingTimestamp ) {
minterNameMap . set ( minterName , card )
}
}
// Step 4: Filter cards to ensure each minterName is included only once
const finalCards = [ ]
const seenMinterNames = new Set ( )
for ( const [ minterName , card ] of minterNameMap . entries ( ) ) {
if ( ! seenMinterNames . has ( minterName ) ) {
finalCards . push ( card )
seenMinterNames . add ( minterName ) // Mark the minterName as seen
}
}
// Step 5: Sort by the most recent timestamp
finalCards . sort ( ( a , b ) => {
const timestampA = a . updated || a . created || 0
const timestampB = b . updated || b . created || 0
return timestampB - timestampA
} )
return finalCards
}
2024-12-12 17:23:34 -08:00
//Main function to load the Minter Cards ----------------------------------------
const loadCards = async ( ) => {
const cardsContainer = document . getElementById ( "cards-container" ) ;
cardsContainer . innerHTML = "<p>Loading cards...</p>" ;
try {
2024-12-27 23:04:16 -08:00
// const response = await qortalRequest({
// action: "SEARCH_QDN_RESOURCES",
// service: "BLOG_POST",
// query: cardIdentifierPrefix,
// mode: "ALL"
// })
const response = await searchSimple ( 'BLOG_POST' , ` ${ cardIdentifierPrefix } ` , '' , 0 )
2024-12-12 17:23:34 -08:00
if ( ! response || ! Array . isArray ( response ) || response . length === 0 ) {
cardsContainer . innerHTML = "<p>No cards found.</p>" ;
return ;
}
2024-12-16 19:53:37 -08:00
// Validate cards and filter
2024-12-12 17:23:34 -08:00
const validatedCards = await Promise . all (
response . map ( async card => {
const isValid = await validateCardStructure ( card ) ;
return isValid ? card : null ;
} )
) ;
const validCards = validatedCards . filter ( card => card !== null ) ;
if ( validCards . length === 0 ) {
cardsContainer . innerHTML = "<p>No valid cards found.</p>" ;
return ;
}
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
const finalCards = await processMinterCards ( validCards )
2024-12-16 19:53:37 -08:00
// Sort cards by timestamp descending (newest first)
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
// validCards.sort((a, b) => {
// const timestampA = a.updated || a.created || 0;
// const timestampB = b.updated || b.created || 0;
// return timestampB - timestampA;
// });
2024-12-14 19:40:31 -08:00
2024-12-16 19:53:37 -08:00
// Display skeleton cards immediately
2024-12-14 19:40:31 -08:00
cardsContainer . innerHTML = "" ;
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
finalCards . forEach ( card => {
2024-12-16 19:53:37 -08:00
const skeletonHTML = createSkeletonCardHTML ( card . identifier ) ;
cardsContainer . insertAdjacentHTML ( "beforeend" , skeletonHTML ) ;
} ) ;
2024-12-14 19:40:31 -08:00
2024-12-16 19:53:37 -08:00
// Fetch and update each card
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
finalCards . forEach ( async card => {
2024-12-16 19:53:37 -08:00
try {
const cardDataResponse = await qortalRequest ( {
action : "FETCH_QDN_RESOURCE" ,
name : card . name ,
service : "BLOG_POST" ,
identifier : card . identifier ,
} ) ;
if ( ! cardDataResponse ) {
console . warn ( ` Skipping invalid card: ${ JSON . stringify ( card ) } ` ) ;
removeSkeleton ( card . identifier ) ;
return ;
2024-12-12 17:23:34 -08:00
}
2024-12-16 19:53:37 -08:00
// Skip cards without polls
if ( ! cardDataResponse . poll ) {
console . warn ( ` Skipping card with no poll: ${ card . identifier } ` ) ;
removeSkeleton ( card . identifier ) ;
return ;
}
// Fetch poll results
const pollResults = await fetchPollResults ( cardDataResponse . poll ) ;
2024-12-20 22:07:18 -08:00
const BgColor = generateDarkPastelBackgroundBy ( card . name )
2024-12-16 19:53:37 -08:00
// Generate final card HTML
2024-12-20 22:07:18 -08:00
const commentCount = await countComments ( card . identifier )
2024-12-24 00:27:17 -08:00
const cardUpdatedTime = card . updated || null
const finalCardHTML = await createCardHTML ( cardDataResponse , pollResults , card . identifier , commentCount , cardUpdatedTime , BgColor ) ;
2024-12-20 22:07:18 -08:00
2024-12-16 19:53:37 -08:00
replaceSkeleton ( card . identifier , finalCardHTML ) ;
} catch ( error ) {
console . error ( ` Error processing card ${ card . identifier } : ` , error ) ;
removeSkeleton ( card . identifier ) ; // Silently remove skeleton on error
}
} ) ;
2024-12-12 17:23:34 -08:00
} catch ( error ) {
console . error ( "Error loading cards:" , error ) ;
cardsContainer . innerHTML = "<p>Failed to load cards.</p>" ;
}
} ;
2024-12-16 19:53:37 -08:00
const removeSkeleton = ( cardIdentifier ) => {
const skeletonCard = document . getElementById ( ` skeleton- ${ cardIdentifier } ` ) ;
if ( skeletonCard ) {
skeletonCard . remove ( ) ; // Remove the skeleton silently
}
} ;
2024-12-12 17:23:34 -08:00
2024-12-16 19:53:37 -08:00
const replaceSkeleton = ( cardIdentifier , htmlContent ) => {
const skeletonCard = document . getElementById ( ` skeleton- ${ cardIdentifier } ` ) ;
if ( skeletonCard ) {
skeletonCard . outerHTML = htmlContent ;
}
} ;
// Function to create a skeleton card
const createSkeletonCardHTML = ( cardIdentifier ) => {
return `
< div id = "skeleton-${cardIdentifier}" class = "skeleton-card" style = "padding: 10px; border: 1px solid gray; margin: 10px 0;" >
< div style = "display: flex; align-items: center;" >
2024-12-20 22:07:18 -08:00
< div > < p style = "color:rgb(174, 174, 174)" > LOADING CARD ... < / p > < / d i v >
2024-12-16 19:53:37 -08:00
< div style = "width: 50px; height: 50px; background-color: #ccc; border-radius: 50%;" > < / d i v >
< div style = "margin-left: 10px;" >
< div style = "width: 120px; height: 20px; background-color: #ccc; margin-bottom: 5px;" > < / d i v >
< div style = "width: 80px; height: 15px; background-color: #ddd;" > < / d i v >
< / d i v >
< / d i v >
< div style = "margin-top: 10px;" >
2024-12-20 22:07:18 -08:00
< div style = "width: 100%; height: 80px; background-color: #eee; color:rgb(17, 24, 28); padding: 0.22vh" > < p > PLEASE BE PATIENT < / p > < p s t y l e = " c o l o r : # 1 1 1 2 1 c " > W h i l e d a t a l o a d s f r o m Q D N . . . < / d i v >
2024-12-16 19:53:37 -08:00
< / d i v >
< / d i v >
` ;
} ;
2024-12-14 19:40:31 -08:00
2024-12-12 17:23:34 -08:00
// Function to check and fech an existing Minter Card if attempting to publish twice ----------------------------------------
const fetchExistingCard = async ( ) => {
2024-12-11 14:40:32 -08:00
try {
// Step 1: Perform the search
2024-12-27 23:04:16 -08:00
// const response = await qortalRequest({
// action: "SEARCH_QDN_RESOURCES",
// service: "BLOG_POST",
// identifier: cardIdentifierPrefix,
// name: userState.accountName,
// mode: "ALL",
// exactMatchNames: true // Search for the exact userName only when finding existing cards
// })
// Changed to searchSimple to improve load times.
const response = await searchSimple ( 'BLOG_POST' , ` ${ cardIdentifierPrefix } ` , ` ${ userState . accountName } ` , 0 )
2024-12-11 14:40:32 -08:00
console . log ( ` SEARCH_QDN_RESOURCES response: ${ JSON . stringify ( response , null , 2 ) } ` ) ;
// Step 2: Check if the response is an array and not empty
if ( ! response || ! Array . isArray ( response ) || response . length === 0 ) {
console . log ( "No cards found for the current user." ) ;
return null ;
2024-12-27 23:04:16 -08:00
} else if ( response . length === 1 ) { // we don't need to go through all of the rest of the checks and filtering nonsense if there's only a single result, just return it.
return response [ 0 ]
2024-12-11 14:40:32 -08:00
}
2024-12-27 23:04:16 -08:00
// Validate cards asynchronously, check that they are not comments, etc.
2024-12-12 17:23:34 -08:00
const validatedCards = await Promise . all (
response . map ( async card => {
const isValid = await validateCardStructure ( card ) ;
return isValid ? card : null ;
} )
) ;
2024-12-27 23:04:16 -08:00
// Filter out invalid cards
2024-12-12 17:23:34 -08:00
const validCards = validatedCards . filter ( card => card !== null ) ;
2024-12-11 14:40:32 -08:00
if ( validCards . length > 0 ) {
2024-12-27 23:04:16 -08:00
// Sort by most recent timestamp
2024-12-11 14:40:32 -08:00
const mostRecentCard = validCards . sort ( ( a , b ) => b . created - a . created ) [ 0 ] ;
2024-12-27 23:04:16 -08:00
// Fetch full card data
2024-12-12 17:23:34 -08:00
const cardDataResponse = await qortalRequest ( {
action : "FETCH_QDN_RESOURCE" ,
name : userState . accountName , // User's account name
service : "BLOG_POST" ,
identifier : mostRecentCard . identifier
} ) ;
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
existingCardIdentifier = mostRecentCard . identifier ;
existingCardData = cardDataResponse ;
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
console . log ( "Full card data fetched successfully:" , cardDataResponse ) ;
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
return cardDataResponse ;
}
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
console . log ( "No valid cards found." ) ;
return null ;
2024-12-11 14:40:32 -08:00
} catch ( error ) {
console . error ( "Error fetching existing card:" , error ) ;
return null ;
}
2024-12-12 17:23:34 -08:00
} ;
// Validate that a card is indeed a card and not a comment. -------------------------------------
const validateCardStructure = async ( card ) => {
2024-12-11 14:40:32 -08:00
return (
typeof card === "object" &&
card . name &&
card . service === "BLOG_POST" &&
card . identifier && ! card . identifier . includes ( "comment" ) &&
card . created
) ;
}
2024-12-12 17:23:34 -08:00
// Load existing card data passed, into the form for editing -------------------------------------
const loadCardIntoForm = async ( cardData ) => {
console . log ( "Loading existing card data:" , cardData ) ;
2024-12-11 14:40:32 -08:00
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 ) ;
} ) ;
}
2024-12-12 17:23:34 -08:00
// Main function to publish a new Minter Card -----------------------------------------------
const publishCard = async ( ) => {
2024-12-11 14:40:32 -08:00
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 ;
}
2024-12-11 16:27:29 -08:00
const cardIdentifier = isExistingCard ? existingCardIdentifier : ` ${ cardIdentifierPrefix } - ${ await uid ( ) } ` ;
2024-12-11 14:40:32 -08:00
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 ,
} ;
2024-12-12 17:23:34 -08:00
2024-12-11 14:40:32 -08:00
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 ,
} ) ;
2024-12-11 16:41:20 -08:00
if ( ! isExistingCard ) {
await qortalRequest ( {
action : "CREATE_POLL" ,
pollName ,
pollDescription ,
pollOptions : [ 'Yes, No' ] ,
pollOwnerAddress : userState . accountAddress ,
} ) ;
2024-12-11 14:40:32 -08:00
2024-12-11 16:41:20 -08:00
alert ( "Card and poll published successfully!" ) ;
}
if ( isExistingCard ) {
alert ( "Card Updated Successfully! (No poll updates are possible at this time...)" )
}
2024-12-11 14:40:32 -08:00
document . getElementById ( "publish-card-form" ) . reset ( ) ;
document . getElementById ( "publish-card-view" ) . style . display = "none" ;
document . getElementById ( "cards-container" ) . style . display = "flex" ;
await loadCards ( ) ;
} catch ( error ) {
console . error ( "Error publishing card or poll:" , error ) ;
alert ( "Failed to publish card and poll." ) ;
}
}
2024-12-12 17:23:34 -08:00
//Calculate the poll results passed from other functions with minterGroupMembers and minterAdmins ---------------------------
const calculatePollResults = async ( pollData , minterGroupMembers , minterAdmins ) => {
const memberAddresses = minterGroupMembers . map ( member => member . member )
2024-12-14 19:40:31 -08:00
const minterAdminAddresses = minterAdmins . map ( member => member . member )
const adminGroupsMembers = await fetchAllAdminGroupsMembers ( )
const groupAdminAddresses = adminGroupsMembers . map ( member => member . member )
const adminAddresses = [ ] ;
adminAddresses . push ( ... minterAdminAddresses , ... groupAdminAddresses ) ;
2024-12-11 17:44:04 -08:00
2024-12-12 17:23:34 -08:00
let adminYes = 0 , adminNo = 0 , minterYes = 0 , minterNo = 0 , yesWeight = 0 , noWeight = 0
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
pollData . voteWeights . forEach ( weightData => {
if ( weightData . optionName === 'Yes' ) {
yesWeight = weightData . voteWeight
} else if ( weightData . optionName === 'No' ) {
noWeight = weightData . voteWeight
2024-12-11 14:40:32 -08:00
}
2024-12-12 17:23:34 -08:00
} )
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
for ( const vote of pollData . votes ) {
const voterAddress = await getAddressFromPublicKey ( vote . voterPublicKey )
2024-12-27 23:04:16 -08:00
// console.log(`voter address: ${voterAddress}`)
2024-12-11 14:40:32 -08:00
2024-12-11 18:32:48 -08:00
if ( vote . optionIndex === 0 ) {
2024-12-12 17:23:34 -08:00
adminAddresses . includes ( voterAddress ) ? adminYes ++ : memberAddresses . includes ( voterAddress ) ? minterYes ++ : console . log ( ` voter ${ voterAddress } is not a minter nor an admin...Not including results... ` )
2024-12-11 18:32:48 -08:00
} else if ( vote . optionIndex === 1 ) {
2024-12-12 17:23:34 -08:00
adminAddresses . includes ( voterAddress ) ? adminNo ++ : memberAddresses . includes ( voterAddress ) ? minterNo ++ : console . log ( ` voter ${ voterAddress } is not a minter nor an admin...Not including results... ` )
2024-12-11 14:40:32 -08:00
}
2024-12-12 17:23:34 -08:00
}
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
// TODO - create a new function to calculate the weights of each voting MINTER only.
// This will give ALL weight whether voter is in minter group or not...
// until that is changed on the core we must calculate manually.
const totalYesWeight = yesWeight
const totalNoWeight = noWeight
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
const totalYes = adminYes + minterYes
const totalNo = adminNo + minterNo
return { adminYes , adminNo , minterYes , minterNo , totalYes , totalNo , totalYesWeight , totalNoWeight }
}
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
// Post a comment on a card. ---------------------------------
2024-12-11 14:40:32 -08:00
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 = ` comment- ${ cardIdentifier } - ${ 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 ) ) ;
}
2024-12-12 17:23:34 -08:00
2024-12-11 14:40:32 -08:00
await qortalRequest ( {
action : 'PUBLISH_QDN_RESOURCE' ,
name : userState . accountName ,
service : 'BLOG_POST' ,
identifier : commentIdentifier ,
data64 : base64CommentData ,
} ) ;
2024-12-11 16:41:20 -08:00
2024-12-11 14:40:32 -08:00
alert ( 'Comment posted successfully!' ) ;
commentInput . value = '' ; // Clear input
2024-12-14 19:40:31 -08:00
// await displayComments(cardIdentifier); // Refresh comments - We don't need to do this as comments will be displayed only after confirmation.
2024-12-11 14:40:32 -08:00
} catch ( error ) {
console . error ( 'Error posting comment:' , error ) ;
alert ( 'Failed to post comment.' ) ;
}
} ;
2024-12-12 17:23:34 -08:00
//Fetch the comments for a card with passed card identifier ----------------------------
2024-12-11 14:40:32 -08:00
const fetchCommentsForCard = async ( cardIdentifier ) => {
try {
2024-12-27 23:04:16 -08:00
// const response = await qortalRequest({
// action: 'SEARCH_QDN_RESOURCES',
// service: 'BLOG_POST',
// query: `comment-${cardIdentifier}`,
// mode: "ALL"
// })
const response = await searchSimple ( 'BLOG_POST' , ` comment- ${ cardIdentifier } ` , '' , 0 )
return response
2024-12-11 14:40:32 -08:00
} catch ( error ) {
2024-12-27 23:04:16 -08:00
console . error ( ` Error fetching comments for ${ cardIdentifier } : ` , error )
return [ ]
2024-12-11 14:40:32 -08:00
}
2024-12-27 23:04:16 -08:00
}
2024-12-11 14:40:32 -08:00
2024-12-12 17:23:34 -08:00
// display the comments on the card, with passed cardIdentifier to identify the card --------------
2024-12-11 14:40:32 -08:00
const displayComments = async ( cardIdentifier ) => {
try {
const comments = await fetchCommentsForCard ( cardIdentifier ) ;
const commentsContainer = document . getElementById ( ` comments-container- ${ cardIdentifier } ` ) ;
// Fetch and display each comment
for ( const comment of comments ) {
const commentDataResponse = await qortalRequest ( {
action : "FETCH_QDN_RESOURCE" ,
name : comment . name ,
service : "BLOG_POST" ,
identifier : comment . identifier ,
} ) ;
const timestamp = await timestampToHumanReadableDate ( commentDataResponse . timestamp ) ;
2024-12-12 17:23:34 -08:00
//TODO - add fetching of poll results and checking to see if the commenter has voted and display it as 'supports minter' section.
2024-12-11 14:40:32 -08:00
const commentHTML = `
< div class = "comment" style = "border: 1px solid gray; margin: 1vh 0; padding: 1vh; background: #1c1c1c;" >
< p > < strong > < u > $ { commentDataResponse . creator } < / s t r o n g > : < / p > < / u >
< p > $ { commentDataResponse . content } < / p >
< p > < i > $ { timestamp } < /p></i >
< / d i v >
` ;
commentsContainer . insertAdjacentHTML ( 'beforeend' , commentHTML ) ;
}
} catch ( error ) {
2024-12-27 23:04:16 -08:00
console . error ( ` Error displaying comments (or no comments) for ${ cardIdentifier } : ` , error ) ;
2024-12-11 14:40:32 -08:00
}
} ;
2024-12-12 17:23:34 -08:00
// Toggle comments from being shown or not, with passed cardIdentifier for comments being toggled --------------------
2024-12-11 14:40:32 -08:00
const toggleComments = async ( cardIdentifier ) => {
const commentsSection = document . getElementById ( ` comments-section- ${ cardIdentifier } ` ) ;
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
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 ) ;
if ( isHidden ) {
// Show comments
commentButton . textContent = "LOADING..." ;
2024-12-11 14:40:32 -08:00
await displayComments ( cardIdentifier ) ;
commentsSection . style . display = 'block' ;
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
// Change the button text to 'HIDE COMMENTS'
commentButton . textContent = 'HIDE COMMENTS' ;
2024-12-11 14:40:32 -08:00
} else {
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
// Hide comments
2024-12-11 14:40:32 -08:00
commentsSection . style . display = 'none' ;
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
commentButton . textContent = ` COMMENTS ( ${ count } ) ` ;
2024-12-11 14:40:32 -08:00
}
} ;
2024-12-20 22:07:18 -08:00
const countComments = async ( cardIdentifier ) => {
try {
2024-12-27 23:04:16 -08:00
// const response = await qortalRequest({
// action: 'SEARCH_QDN_RESOURCES',
// service: 'BLOG_POST',
// query: `comment-${cardIdentifier}`,
// mode: "ALL"
// })
// Changed to searchSimple to hopefully improve load times...
const response = await searchSimple ( 'BLOG_POST' , ` comment- ${ cardIdentifier } ` , '' , 0 )
2024-12-20 22:07:18 -08:00
// Just return the count; no need to decrypt each comment here
return Array . isArray ( response ) ? response . length : 0 ;
} catch ( error ) {
console . error ( ` Error fetching comment count for ${ cardIdentifier } : ` , error ) ;
return 0 ;
}
} ;
2024-12-12 17:23:34 -08:00
const createModal = async ( ) => {
const modalHTML = `
< div id = "modal" style = "display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.8); z-index: 1000;" >
2024-12-12 21:49:14 -08:00
< div style = "position: relative; margin: 10% auto; width: 95%; height: 80%; background: white; border-radius: 10px; overflow: hidden;" >
2024-12-12 17:23:34 -08:00
< iframe id = "modalContent" src = "" style = "width: 100%; height: 100%; border: none;" > < / i f r a m e >
< button onclick = "closeModal()" style = "position: absolute; top: 10px; right: 10px; background: red; color: white; border: none; padding: 5px 10px; border-radius: 5px;" > Close < / b u t t o n >
< / d i v >
< / d i v >
` ;
document . body . insertAdjacentHTML ( 'beforeend' , modalHTML ) ;
}
// Function to open the modal
const openModal = async ( link ) => {
const processedLink = await processLink ( link ) // Process the link to replace `qortal://` for rendering in modal
const modal = document . getElementById ( 'modal' ) ;
const modalContent = document . getElementById ( 'modalContent' ) ;
modalContent . src = processedLink ; // Set the iframe source to the link
modal . style . display = 'block' ; // Show the modal
}
// Function to close the modal
const closeModal = async ( ) => {
const modal = document . getElementById ( 'modal' ) ;
const modalContent = document . getElementById ( 'modalContent' ) ;
modal . style . display = 'none' ; // Hide the modal
modalContent . src = '' ; // Clear the iframe source
}
const processLink = async ( link ) => {
if ( link . startsWith ( 'qortal://' ) ) {
2024-12-12 21:49:14 -08:00
const match = link . match ( /^qortal:\/\/([^/]+)(\/.*)?$/ ) ;
if ( match ) {
2024-12-20 22:07:18 -08:00
const firstParam = match [ 1 ] . toUpperCase ( ) ;
const remainingPath = match [ 2 ] || "" ;
const themeColor = window . _qdnTheme || 'default' ; // Fallback to 'default' if undefined
// Simulating async operation if needed
await new Promise ( resolve => setTimeout ( resolve , 10 ) ) ;
// Append theme as a query parameter
return ` /render/ ${ firstParam } ${ remainingPath } ?theme= ${ themeColor } ` ;
2024-12-12 21:49:14 -08:00
}
2024-12-12 17:23:34 -08:00
}
2024-12-20 22:07:18 -08:00
return link ;
} ;
// Hash the name and map it to a dark pastel color
const generateDarkPastelBackgroundBy = ( name ) => {
// 1) Basic string hashing
let hash = 0 ;
for ( let i = 0 ; i < name . length ; i ++ ) {
hash = ( hash << 5 ) - hash + name . charCodeAt ( i ) ;
hash |= 0 ; // Convert to 32-bit integer
}
const safeHash = Math . abs ( hash ) ;
// 2) Restrict hue to a 'blue-ish' range (150..270 = 120 degrees total)
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
const hueSteps = 69.69 ;
2024-12-20 22:07:18 -08:00
const hueIndex = safeHash % hueSteps ;
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
const hueRange = 288 ;
const hue = 140 + ( hueIndex * ( hueRange / hueSteps ) ) ;
2024-12-20 22:07:18 -08:00
// 3) Satura tion:
const satSteps = 13.69 ;
const satIndex = safeHash % satSteps ;
const saturation = 18 + ( satIndex * 1.333 ) ;
// 4) Lightness:
const lightSteps = 3.69 ;
const lightIndex = safeHash % lightSteps ;
const lightness = 7 + lightIndex ;
// 5) Return the HSL color string
return ` hsl( ${ hue } , ${ saturation } %, ${ lightness } %) ` ;
} ;
2024-12-12 17:23:34 -08:00
// Create the overall Minter Card HTML -----------------------------------------------
2024-12-24 00:27:17 -08:00
const createCardHTML = async ( cardData , pollResults , cardIdentifier , commentCount , cardUpdatedTime , BgColor ) => {
2024-12-11 14:40:32 -08:00
const { header , content , links , creator , timestamp , poll } = cardData ;
2024-12-24 00:27:17 -08:00
const formattedDate = cardUpdatedTime ? new Date ( cardUpdatedTime ) . toLocaleString ( ) : new Date ( timestamp ) . toLocaleString ( )
2024-12-20 22:07:18 -08:00
// const avatarUrl = `/arbitrary/THUMBNAIL/${creator}/qortal_avatar`;
const avatarHtml = await getMinterAvatar ( creator )
2024-12-11 14:40:32 -08:00
const linksHTML = links . map ( ( link , index ) => `
2024-12-12 17:23:34 -08:00
< button onclick = "openModal('${link}')" >
2024-12-11 14:40:32 -08:00
$ { ` Link ${ index + 1 } - ${ link } ` }
< / b u t t o n >
` ).join("");
const minterGroupMembers = await fetchMinterGroupMembers ( ) ;
2024-12-12 17:23:34 -08:00
const minterAdmins = await fetchMinterGroupAdmins ( ) ;
const { adminYes = 0 , adminNo = 0 , minterYes = 0 , minterNo = 0 , totalYes = 0 , totalNo = 0 , totalYesWeight = 0 , totalNoWeight = 0 } = await calculatePollResults ( pollResults , minterGroupMembers , minterAdmins )
await createModal ( )
2024-12-11 14:40:32 -08:00
return `
2024-12-20 22:07:18 -08:00
< div class = "minter-card" style = "background-color: ${BgColor}" >
2024-12-11 14:40:32 -08:00
< div class = "minter-card-header" >
2024-12-20 22:07:18 -08:00
$ { avatarHtml }
2024-12-11 14:40:32 -08:00
< h3 > $ { creator } < / h 3 >
< p > $ { header } < / p >
< / d i v >
2024-12-20 22:07:18 -08:00
< div class = "support-header" > < h5 > MINTER ' S POST < / h 5 > < / d i v >
2024-12-11 14:40:32 -08:00
< div class = "info" >
$ { content }
< / d i v >
2024-12-20 22:07:18 -08:00
< div class = "support-header" > < h5 > MINTER ' S LINKS < / h 5 > < / d i v >
2024-12-11 14:40:32 -08:00
< div class = "info-links" >
$ { linksHTML }
< / d i v >
2024-12-20 22:07:18 -08:00
< div class = "results-header support-header" > < h5 > CURRENT RESULTS < / h 5 > < / d i v >
2024-12-11 14:40:32 -08:00
< div class = "minter-card-results" >
< div class = "admin-results" >
< span class = "admin-yes" > Admin Yes : $ { adminYes } < / s p a n >
< span class = "admin-no" > Admin No : $ { adminNo } < / s p a n >
< / d i v >
< div class = "minter-results" >
< span class = "minter-yes" > Minter Yes : $ { minterYes } < / s p a n >
< span class = "minter-no" > Minter No : $ { minterNo } < / s p a n >
< / d i v >
< div class = "total-results" >
< span class = "total-yes" > Total Yes : $ { totalYes } < / s p a n >
2024-12-20 22:07:18 -08:00
< span class = "total-yes" > Weight : $ { totalYesWeight } < / s p a n >
2024-12-11 14:40:32 -08:00
< span class = "total-no" > Total No : $ { totalNo } < / s p a n >
2024-12-20 22:07:18 -08:00
< span class = "total-no" > Weight : $ { totalNoWeight } < / s p a n >
2024-12-11 14:40:32 -08:00
< / d i v >
< / d i v >
2024-12-20 22:07:18 -08:00
< div class = "support-header" > < h5 > SUPPORT < / h 5 > < h 5 s t y l e = " c o l o r : # f f a e 4 2 ; " > $ { c r e a t o r } < / h 5 >
< p style = "color: #c7c7c7; font-size: .65rem; margin-top: 1vh" > ( click COMMENTS button to open / close card comments ) < / p >
< / d i v >
2024-12-11 14:40:32 -08:00
< div class = "actions" >
< div class = "actions-buttons" >
2024-12-11 18:32:48 -08:00
< button class = "yes" onclick = "voteYesOnPoll('${poll}')" > YES < / b u t t o n >
This version includes many changes and performance improvements. Further performance improvements will be coming soon. This change includes a cache for the published data on the forum. Messages of up to 2000 in number, will be stored locally in browser storage, that way if the message has already been loaded by that computer, it will not have to pull the data again from QDN. It will be stored in encrypted format for the Admin room. This same caching will be applied to the Minter and Admin boards in the future. Also, reply issues that were present before should be resolved, all replies, regardless of when they were published, will now show their previews in the message pane as they are supposed to. Previously if a reply was on another page, it would not load this preview. The encrypted portions of the app now include a method of caching the admin public keys, for faster publishing. The Minter and Admin boards have a new comment loading display when the comments button is clicked to let users know that data is being loaded, on top of the existing comment count. Other new features and additional performance improvements are in planning. Also, the issue preventing comments from those that had not already loaded the forum, in the Admin Board, has been resolved as well.
2024-12-26 20:06:51 -08:00
< button class = "comment" id = "comment-button-${cardIdentifier}" data - comment - count = "${commentCount}" onclick = "toggleComments('${cardIdentifier}')" > COMMENTS ( $ { commentCount } ) < / b u t t o n >
2024-12-11 18:32:48 -08:00
< button class = "no" onclick = "voteNoOnPoll('${poll}')" > NO < / b u t t o n >
2024-12-11 14:40:32 -08:00
< / d i v >
< / d i v >
< div id = "comments-section-${cardIdentifier}" class = "comments-section" style = "display: none; margin-top: 20px;" >
< div id = "comments-container-${cardIdentifier}" class = "comments-container" > < / d i v >
< textarea id = "new-comment-${cardIdentifier}" placeholder = "Write a comment..." style = "width: 100%; margin-top: 10px;" > < / t e x t a r e a >
< button onclick = "postComment('${cardIdentifier}')" > Post Comment < / b u t t o n >
< / d i v >
2024-12-20 22:07:18 -08:00
< p style = "font-size: 0.75rem; margin-top: 3vh; color: #4496a1" > By : $ { creator } - $ { formattedDate } < / p >
2024-12-11 14:40:32 -08:00
< / d i v >
` ;
}