Version 1.2 includes a dramatic re-write to the card loading on the Minter and MAM Boards, cards now load at least 25x faster. This should be a significant improvement for all. Hence the significant version increase.

This commit is contained in:
crowetic 2025-02-27 17:56:20 -08:00
parent 59bd5cc760
commit 5630f80a54
3 changed files with 305 additions and 183 deletions

View File

@ -284,7 +284,7 @@ const displayPendingInviteDetails = async (pendingInvites) => {
(approvalTx) => approvalTx.pendingSignature === txSig (approvalTx) => approvalTx.pendingSignature === txSig
) )
const { tableHtml, approvalCount } = await buildApprovalTableHtml(approvals, getNameFromAddress) const { tableHtml, approvalCount = approvals.length } = await buildApprovalTableHtml(approvals, getNameFromAddress)
const finalTable = approvals.length > 0 ? tableHtml : "<p>No Approvals Found</p>" const finalTable = approvals.length > 0 ? tableHtml : "<p>No Approvals Found</p>"
html += ` html += `

View File

@ -9,6 +9,8 @@ const GROUP_APPROVAL_FEATURE_TRIGGER_HEIGHT = 2012800 //TODO update this to corr
let featureTriggerPassed = false let featureTriggerPassed = false
let isApproved = false let isApproved = false
let cachedMinterAdmins
let cachedMinterGroup
const loadMinterBoardPage = async () => { const loadMinterBoardPage = async () => {
// Clear existing content on the page // Clear existing content on the page
@ -207,12 +209,35 @@ const loadMinterBoardPage = async () => {
await loadCards(minterCardIdentifierPrefix) await loadCards(minterCardIdentifierPrefix)
}) })
} }
// Initialize Cached Minter Group and Minter Admins
const [minterGroup, minterAdmins] = await Promise.all([
fetchMinterGroupMembers(),
fetchMinterGroupAdmins()
])
cachedMinterAdmins = minterAdmins
cachedMinterGroup = minterGroup
await featureTriggerCheck() await featureTriggerCheck()
await loadCards(minterCardIdentifierPrefix) await loadCards(minterCardIdentifierPrefix)
} }
const runWithConcurrency = async (tasks, concurrency = 5) => {
const results = []
let index = 0
const workers = new Array(concurrency).fill(null).map(async () => {
while (index < tasks.length) {
const currentIndex = index++
const task = tasks[currentIndex]
results[currentIndex] = await task()
}
})
await Promise.all(workers)
return results
}
const extractMinterCardsMinterName = async (cardIdentifier) => { const extractMinterCardsMinterName = async (cardIdentifier) => {
// Ensure the identifier starts with the prefix // Ensure the identifier starts with the prefix
if ((!cardIdentifier.startsWith(minterCardIdentifierPrefix)) && (!cardIdentifier.startsWith(addRemoveIdentifierPrefix))) { if ((!cardIdentifier.startsWith(minterCardIdentifierPrefix)) && (!cardIdentifier.startsWith(addRemoveIdentifierPrefix))) {
@ -429,221 +454,232 @@ const processARBoardCards = async (allValidCards) => {
//Main function to load the Minter Cards ---------------------------------------- //Main function to load the Minter Cards ----------------------------------------
const loadCards = async (cardIdentifierPrefix) => { const loadCards = async (cardIdentifierPrefix) => {
const cardsContainer = document.getElementById("cards-container") const cardsContainer = document.getElementById("cards-container")
let isARBoard = false
cardsContainer.innerHTML = "<p>Loading cards...</p>" cardsContainer.innerHTML = "<p>Loading cards...</p>"
const counterSpan = document.getElementById("board-card-counter") const counterSpan = document.getElementById("board-card-counter")
if (counterSpan) counterSpan.textContent = "(loading...)"
if (counterSpan) { const isARBoard = cardIdentifierPrefix.startsWith("QM-AR-card")
// Clear or show "Loading..."
counterSpan.textContent = "(loading...)"
}
if (cardIdentifierPrefix.startsWith("QM-AR-card")) {
isARBoard = true
console.warn(`ARBoard determined:`, isARBoard)
}
let afterTime = 0
const timeRangeSelect = document.getElementById("time-range-select")
const showExistingCheckbox = document.getElementById("show-existing-checkbox") const showExistingCheckbox = document.getElementById("show-existing-checkbox")
const showExisting = showExistingCheckbox && showExistingCheckbox.checked const showExisting = showExistingCheckbox && showExistingCheckbox.checked
let afterTime = 0
const timeRangeSelect = document.getElementById("time-range-select")
if (timeRangeSelect) { if (timeRangeSelect) {
const days = parseInt(timeRangeSelect.value, 10) const days = parseInt(timeRangeSelect.value, 10)
if (days > 0) { if (days > 0) {
const now = Date.now() const now = Date.now()
const dayMs = 24 * 60 * 60 * 1000 afterTime = now - days * 24 * 60 * 60 * 1000
afterTime = now - days * dayMs // e.g. last X days
console.log(`afterTime for last ${days} days = ${new Date(afterTime).toLocaleString()}`)
} }
} }
try { try {
// 1) Fetch raw "BLOG_POST" entries const rawResults = await searchSimple('BLOG_POST', cardIdentifierPrefix, '', 0, 0, '', false, true, afterTime)
const response = await searchSimple('BLOG_POST', cardIdentifierPrefix, '', 0, 0, '', false, true, afterTime) if (!rawResults || !Array.isArray(rawResults) || rawResults.length === 0) {
if (!response || !Array.isArray(response) || response.length === 0) {
cardsContainer.innerHTML = "<p>No cards found.</p>" cardsContainer.innerHTML = "<p>No cards found.</p>"
return return
} }
// 2) Validate structure
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) { const validated = (await Promise.all(
rawResults.map(async (r) => (await validateCardStructure(r)) ? r : null)
)).filter(Boolean)
if (validated.length === 0) {
cardsContainer.innerHTML = "<p>No valid cards found.</p>" cardsContainer.innerHTML = "<p>No valid cards found.</p>"
return return
} }
// Additional logic for ARBoard or MinterCards
const finalCards = isARBoard
? await processARBoardCards(validCards)
: await processMinterBoardCards(validCards)
// Sort finalCards according to selectedSort let processedCards
let selectedSort = 'newest' if (isARBoard) {
const sortSelect = document.getElementById('sort-select') processedCards = await processARBoardCards(validated)
} else {
processedCards = await processMinterBoardCards(validated)
}
let selectedSort = "newest"
const sortSelect = document.getElementById("sort-select")
if (sortSelect) { if (sortSelect) {
selectedSort = sortSelect.value selectedSort = sortSelect.value
} }
if (selectedSort === "name") {
if (selectedSort === 'name') { processedCards.sort((a, b) => (a.name||"").localeCompare(b.name||""))
finalCards.sort((a, b) => {
const nameA = a.name?.toLowerCase() || ''
const nameB = b.name?.toLowerCase() || ''
return nameA.localeCompare(nameB)
})
} else if (selectedSort === 'recent-comments') { } else if (selectedSort === 'recent-comments') {
// If you need the newest comment timestamp // If you need the newest comment timestamp
for (let card of finalCards) { for (let card of finalCards) {
card.newestCommentTimestamp = await getNewestCommentTimestamp(card.identifier) card.newestCommentTimestamp = await getNewestCommentTimestamp(card.identifier)
}
finalCards.sort((a, b) =>
(b.newestCommentTimestamp || 0) - (a.newestCommentTimestamp || 0)
)
} else if (selectedSort === 'least-votes') {
await applyVoteSortingData(finalCards, /* ascending= */ true)
} else if (selectedSort === 'most-votes') {
await applyVoteSortingData(finalCards, /* ascending= */ false)
} }
// else 'newest' => do nothing (already sorted newest-first by your process functions). finalCards.sort((a, b) =>
// Create the 'finalCardsArray' that includes the data, etc. (b.newestCommentTimestamp || 0) - (a.newestCommentTimestamp || 0)
let finalCardsArray = [] )
let alreadyMinterCards = [] } else if (selectedSort === 'least-votes') {
cardsContainer.innerHTML = '' await applyVoteSortingData(finalCards, /* ascending= */ true)
for (const card of finalCards) { } else if (selectedSort === 'most-votes') {
try { await applyVoteSortingData(finalCards, /* ascending= */ false)
const skeletonHTML = createSkeletonCardHTML(card.identifier) }
cardsContainer.insertAdjacentHTML("beforeend", skeletonHTML)
const cardDataResponse = await qortalRequest({
action: "FETCH_QDN_RESOURCE",
name: card.name,
service: "BLOG_POST",
identifier: card.identifier
})
if (!cardDataResponse || !cardDataResponse.poll) { cardsContainer.innerHTML = "" // reset
// skip for (const card of processedCards) {
console.warn(`Skipping card: missing data/poll. identifier=${card.identifier}`) const skeletonHTML = createSkeletonCardHTML(card.identifier)
removeSkeleton(card.identifier) cardsContainer.insertAdjacentHTML("beforeend", skeletonHTML)
continue }
const finalCardsArray = []
const alreadyMinterCards = []
const tasks = processedCards.map(card => {
return async () => {
// We'll store an object with skip info, QDN data, etc.
const result = {
card,
skip: false,
skipReason: "",
isAlreadyMinter: false,
cardData: null,
} }
// Extra validation: check poll ownership matches card publisher
const pollPublisherAddress = await getPollOwnerAddress(cardDataResponse.poll) try {
const cardPublisherAddress = await fetchOwnerAddressFromName(card.name) const data = await qortalRequest({
if (pollPublisherAddress !== cardPublisherAddress) { action: "FETCH_QDN_RESOURCE",
console.warn(`Poll hijack attack found, discarding card ${card.identifier}`) name: card.name,
removeSkeleton(card.identifier) service: "BLOG_POST",
continue identifier: card.identifier
} })
// If ARBoard, do a quick address check if (!data || !data.poll) {
if (isARBoard) { result.skip = true
const ok = await verifyMinter(cardDataResponse.minterName) result.skipReason = "Missing or invalid poll"
if (!ok) { return result
console.warn(`Card is not a minter nor an admin, not including in ARBoard. identifier: ${card.identifier}`)
removeSkeleton(card.identifier)
continue
} }
} else {
const isAlreadyMinter = await verifyMinter(cardDataResponse.creator) const pollPublisherAddress = await getPollOwnerAddressCached(data.poll)
if (isAlreadyMinter) { const cardPublisherAddress = await fetchOwnerAddressFromNameCached(card.name)
console.warn(`card IS ALREADY a minter, adding to alreadyMinterCards array: ${card.identifier}`) if (pollPublisherAddress !== cardPublisherAddress) {
removeSkeleton(card.identifier) result.skip = true
alreadyMinterCards.push({ result.skipReason = "Poll hijack mismatch"
...card, return result
cardDataResponse,
pollPublisherAddress,
cardPublisherAddress
})
continue
} }
// ARBoard => verify user is minter/admin
if (isARBoard) {
const ok = await verifyMinterCached(data.minterName)
if (!ok) {
result.skip = true
result.skipReason = "Card user not minter => skip from ARBoard"
return result
}
} else {
// MinterBoard => skip if user is minter
const isAlready = await verifyMinterCached(data.creator)
if (isAlready) {
result.skip = true
result.skipReason = "Already a minter"
result.isAlreadyMinter = true
result.cardData = data
return result
}
}
// If we get here => it's a keeper
result.cardData = data
} catch (err) {
console.warn("Error fetching resource or skip logic:", err)
result.skip = true
result.skipReason = "Error: " + err
} }
// **Push** to finalCardsArray for further processing (duplicates, etc.)
return result
}
})
// ADJUST THE CONCURRENCY TO INCREASE THE AMOUNT OF CARDS PROCESSED AT ONCE. INCREASE UNTIL THERE ARE ISSUES.
const concurrency = 30
const results = await runWithConcurrency(tasks, concurrency)
// Fill final arrays
for (const r of results) {
if (r.skip && r.isAlreadyMinter) {
alreadyMinterCards.push({ ...r.card, cardDataResponse: r.cardData })
removeSkeleton(r.card.identifier)
} else if (r.skip) {
console.warn(`Skipping card ${r.card.identifier}, reason=${r.skipReason}`)
removeSkeleton(r.card.identifier)
} else {
// keeper
finalCardsArray.push({ finalCardsArray.push({
...card, ...r.card,
cardDataResponse, cardDataResponse: r.cardData
pollPublisherAddress,
cardPublisherAddress,
}) })
if (counterSpan) {
const displayedCount = finalCardsArray.length
const alreadyMinterCount = alreadyMinterCards.length
// If you want to show both
counterSpan.textContent = `(${displayedCount} cards, ${alreadyMinterCount} existingMinters)`
}
} catch (err) {
console.error(`Error preparing card ${card.identifier}`, err)
removeSkeleton(card.identifier)
} }
} }
// Next, do the actual rendering:
// cardsContainer.innerHTML = ""
for (const cardObj of finalCardsArray) { for (const cardObj of finalCardsArray) {
// Insert a skeleton first if you like try {
// const skeletonHTML = createSkeletonCardHTML(cardObj.identifier) const pollResults = await fetchPollResultsCached(cardObj.cardDataResponse.poll)
// cardsContainer.insertAdjacentHTML("beforeend", skeletonHTML) const commentCount = await countCommentsCached(cardObj.identifier)
// Build final HTML const cardUpdatedTime = cardObj.updated || cardObj.created || null
const pollResults = await fetchPollResults(cardObj.cardDataResponse.poll) const bgColor = generateDarkPastelBackgroundBy(cardObj.name)
const commentCount = await countComments(cardObj.identifier)
const cardUpdatedTime = cardObj.updated || null
const bgColor = generateDarkPastelBackgroundBy(cardObj.name)
// Construct the final HTML for each card
const finalCardHTML = isARBoard
? await createARCardHTML(
cardObj.cardDataResponse,
pollResults,
cardObj.identifier,
commentCount,
cardUpdatedTime,
bgColor,
cardObj.cardPublisherAddress,
cardObj.isDuplicate
)
: await createCardHTML(
cardObj.cardDataResponse,
pollResults,
cardObj.identifier,
commentCount,
cardUpdatedTime,
bgColor,
cardObj.cardPublisherAddress
)
replaceSkeleton(cardObj.identifier, finalCardHTML) // If ARBoard => createARCardHTML else createCardHTML
const finalCardHTML = isARBoard
? await createARCardHTML(
cardObj.cardDataResponse,
pollResults,
cardObj.identifier,
commentCount,
cardUpdatedTime,
bgColor,
await fetchOwnerAddressFromNameCached(cardObj.name),
cardObj.isDuplicate
)
: await createCardHTML(
cardObj.cardDataResponse,
pollResults,
cardObj.identifier,
commentCount,
cardUpdatedTime,
bgColor,
await fetchOwnerAddressFromNameCached(cardObj.name)
)
replaceSkeleton(cardObj.identifier, finalCardHTML)
} catch (err) {
console.error(`Error finalizing card ${cardObj.identifier}:`, err)
removeSkeleton(cardObj.identifier)
}
} }
if (showExisting && alreadyMinterCards.length > 0) { if (showExisting && alreadyMinterCards.length > 0) {
console.warn(`Rendering Existing Minter cards because user selected showExisting`) console.log(`Rendering minted cards because showExisting is checked, count=${alreadyMinterCards.length}`)
for (const minted of alreadyMinterCards) {
for (const mintedCardObj of alreadyMinterCards) { const skeletonHTML = createSkeletonCardHTML(minted.identifier)
const skeletonHTML = createSkeletonCardHTML(mintedCardObj.identifier)
cardsContainer.insertAdjacentHTML("beforeend", skeletonHTML) cardsContainer.insertAdjacentHTML("beforeend", skeletonHTML)
const pollResults = await fetchPollResults(mintedCardObj.cardDataResponse.poll) try {
const commentCount = await countComments(mintedCardObj.identifier) const pollResults = await fetchPollResultsCached(minted.cardDataResponse.poll)
const cardUpdatedTime = mintedCardObj.updated || null const commentCount = await countCommentsCached(minted.identifier)
const bgColor = generateDarkPastelBackgroundBy(mintedCardObj.name) const cardUpdatedTime = minted.updated || minted.created || null
const isExistingMinter = true const bgColor = generateDarkPastelBackgroundBy(minted.name)
const finalCardHTML = await createCardHTML(
const finalCardHTML = await createCardHTML( minted.cardDataResponse,
mintedCardObj.cardDataResponse, pollResults,
pollResults, minted.identifier,
mintedCardObj.identifier, commentCount,
commentCount, cardUpdatedTime,
cardUpdatedTime, bgColor,
bgColor, await fetchOwnerAddressFromNameCached(minted.name),
mintedCardObj.cardPublisherAddress, /* isExistingMinter= */ true
isExistingMinter )
) replaceSkeleton(minted.identifier, finalCardHTML)
replaceSkeleton(mintedCardObj.identifier, finalCardHTML) } catch (err) {
console.error(`Error finalizing minted card ${minted.identifier}:`, err)
removeSkeleton(minted.identifier)
}
} }
} }
if (counterSpan) {
const displayed = finalCardsArray.length
const minted = alreadyMinterCards.length
counterSpan.textContent = `(${displayed} displayed, ${minted} minters)`
}
} catch (error) { } catch (error) {
console.error("Error loading cards:", error) console.error("Error loading cards:", error)
cardsContainer.innerHTML = "<p>Failed to load cards.</p>" cardsContainer.innerHTML = "<p>Failed to load cards.</p>"
@ -653,9 +689,19 @@ const loadCards = async (cardIdentifierPrefix) => {
} }
} }
const verifyMinterCache = new Map()
const verifyMinterCached = async (nameOrAddress) => {
if (verifyMinterCache.has(nameOrAddress)) {
return verifyMinterCache.get(nameOrAddress)
}
const result = await verifyMinter(nameOrAddress)
verifyMinterCache.set(nameOrAddress, result)
return result
}
const verifyMinter = async (minterName) => { const verifyMinter = async (minterName) => {
try { try {
const nameInfo = await getNameInfo(minterName) const nameInfo = await getNameInfoCached(minterName)
if (!nameInfo) return false if (!nameInfo) return false
const minterAddress = nameInfo.owner const minterAddress = nameInfo.owner
@ -663,8 +709,10 @@ const verifyMinter = async (minterName) => {
if (!isValid) return false if (!isValid) return false
// Then check if they're in the minter group // Then check if they're in the minter group
const minterGroup = await fetchMinterGroupMembers() // const minterGroup = await fetchMinterGroupMembers()
const adminGroup = await fetchMinterGroupAdmins() const minterGroup = cachedMinterGroup
// const adminGroup = await fetchMinterGroupAdmins()
const adminGroup = cachedMinterAdmins
const minterGroupAddresses = minterGroup.map(m => m.member) const minterGroupAddresses = minterGroup.map(m => m.member)
const adminGroupAddresses = adminGroup.map(m => m.member) const adminGroupAddresses = adminGroup.map(m => m.member)
@ -677,8 +725,10 @@ const verifyMinter = async (minterName) => {
} }
const applyVoteSortingData = async (cards, ascending = true) => { const applyVoteSortingData = async (cards, ascending = true) => {
const minterGroupMembers = await fetchMinterGroupMembers() // const minterGroupMembers = await fetchMinterGroupMembers()
const minterAdmins = await fetchMinterGroupAdmins() const minterGroupMembers = cachedMinterGroup
// const minterAdmins = await fetchMinterGroupAdmins()
const minterAdmins = cachedMinterAdmins
for (const card of cards) { for (const card of cards) {
try { try {
@ -695,7 +745,7 @@ const applyVoteSortingData = async (cards, ascending = true) => {
card._minterYes = 0 card._minterYes = 0
continue continue
} }
const pollResults = await fetchPollResults(cardDataResponse.poll); const pollResults = await fetchPollResultsCached(cardDataResponse.poll);
const { adminYes, adminNo, minterYes, minterNo } = await processPollData( const { adminYes, adminNo, minterYes, minterNo } = await processPollData(
pollResults, pollResults,
minterGroupMembers, minterGroupMembers,
@ -866,7 +916,8 @@ const loadCardIntoForm = async (cardData) => {
// Main function to publish a new Minter Card ----------------------------------------------- // Main function to publish a new Minter Card -----------------------------------------------
const publishCard = async (cardIdentifierPrefix) => { const publishCard = async (cardIdentifierPrefix) => {
const minterGroupData = await fetchMinterGroupMembers() // const minterGroupData = await fetchMinterGroupMembers()
const minterGroupData = cachedMinterGroup
const minterGroupAddresses = minterGroupData.map(m => m.member) const minterGroupAddresses = minterGroupData.map(m => m.member)
const userAddress = userState.accountAddress const userAddress = userState.accountAddress
@ -1353,6 +1404,16 @@ const toggleComments = async (cardIdentifier) => {
} }
} }
const commentCountCache = new Map()
const countCommentsCached= async (cardIdentifier) => {
if (commentCountCache.has(cardIdentifier)) {
return commentCountCache.get(cardIdentifier)
}
const count = await countComments(cardIdentifier)
commentCountCache.set(cardIdentifier, count)
return count
}
const countComments = async (cardIdentifier) => { const countComments = async (cardIdentifier) => {
try { try {
const response = await searchSimple('BLOG_POST', `comment-${cardIdentifier}`, '', 0, 0, '', 'false') const response = await searchSimple('BLOG_POST', `comment-${cardIdentifier}`, '', 0, 0, '', 'false')
@ -1503,7 +1564,7 @@ const handleInviteMinter = async (minterName) => {
try { try {
const blockInfo = await getLatestBlockInfo() const blockInfo = await getLatestBlockInfo()
const blockHeight = blockInfo.height const blockHeight = blockInfo.height
const minterAccountInfo = await getNameInfo(minterName) const minterAccountInfo = await getNameInfoCached(minterName)
const minterAddress = await minterAccountInfo.owner const minterAddress = await minterAccountInfo.owner
let adminPublicKey let adminPublicKey
let txGroupId let txGroupId
@ -1587,7 +1648,8 @@ const featureTriggerCheck = async () => {
const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) => { const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) => {
const isSomeTypaAdmin = userState.isAdmin || userState.isMinterAdmin const isSomeTypaAdmin = userState.isAdmin || userState.isMinterAdmin
const isBlockPassed = await featureTriggerCheck() const isBlockPassed = await featureTriggerCheck()
const minterAdmins = await fetchMinterGroupAdmins() // const minterAdmins = await fetchMinterGroupAdmins()
const minterAdmins = cachedMinterAdmins
// default needed admin count = 9, or 40% if block has passed // default needed admin count = 9, or 40% if block has passed
let minAdminCount = 9 let minAdminCount = 9
@ -1603,7 +1665,7 @@ const checkAndDisplayInviteButton = async (adminYes, creator, cardIdentifier) =>
} }
console.log(`passed initial button creation checks (adminYes >= ${minAdminCount})`) console.log(`passed initial button creation checks (adminYes >= ${minAdminCount})`)
// get user's address from 'creator' name // get user's address from 'creator' name
const minterNameInfo = await getNameInfo(creator) const minterNameInfo = await getNameInfoCached(creator)
if (!minterNameInfo || !minterNameInfo.owner) { if (!minterNameInfo || !minterNameInfo.owner) {
console.warn(`No valid nameInfo for ${creator}, skipping invite button.`) console.warn(`No valid nameInfo for ${creator}, skipping invite button.`)
return null return null
@ -1690,7 +1752,8 @@ const checkGroupApprovalAndCreateButton = async (address, cardIdentifier, transa
// We are going to be verifying that the address isn't already a minter, before showing GROUP_APPROVAL buttons potentially... // We are going to be verifying that the address isn't already a minter, before showing GROUP_APPROVAL buttons potentially...
if (transactionType === "GROUP_INVITE") { if (transactionType === "GROUP_INVITE") {
console.log(`This is a GROUP_INVITE check for group approval... Checking that user isn't already a minter...`) console.log(`This is a GROUP_INVITE check for group approval... Checking that user isn't already a minter...`)
const minterMembers = await fetchMinterGroupMembers() // const minterMembers = await fetchMinterGroupMembers()
const minterMembers = cachedMinterGroup
const minterGroupAddresses = minterMembers.map(m => m.member) const minterGroupAddresses = minterMembers.map(m => m.member)
if (minterGroupAddresses.includes(address)) { if (minterGroupAddresses.includes(address)) {
console.warn(`User is already a minter, will not be creating group_approval buttons`) console.warn(`User is already a minter, will not be creating group_approval buttons`)
@ -2056,8 +2119,10 @@ const createCardHTML = async (cardData, pollResults, cardIdentifier, commentCoun
</button> </button>
`).join("") `).join("")
const minterGroupMembers = await fetchMinterGroupMembers() // const minterGroupMembers = await fetchMinterGroupMembers()
const minterAdmins = await fetchMinterGroupAdmins() const minterGroupMembers = cachedMinterGroup
// const minterAdmins = await fetchMinterGroupAdmins()
const minterAdmins = cachedMinterAdmins
const { adminYes = 0, adminNo = 0, minterYes = 0, minterNo = 0, totalYes = 0, totalNo = 0, totalYesWeight = 0, totalNoWeight = 0, detailsHtml, userVote } = await processPollData(pollResults, minterGroupMembers, minterAdmins, creator, cardIdentifier) const { adminYes = 0, adminNo = 0, minterYes = 0, minterNo = 0, totalYes = 0, totalNo = 0, totalYesWeight = 0, totalNoWeight = 0, detailsHtml, userVote } = await processPollData(pollResults, minterGroupMembers, minterAdmins, creator, cardIdentifier)
createModal('links') createModal('links')
createModal('poll-details') createModal('poll-details')

View File

@ -6,6 +6,11 @@ let baseUrl = ''
let isOutsideOfUiDevelopment = false let isOutsideOfUiDevelopment = false
let nullAddress = 'QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG' let nullAddress = 'QdSnUy6sUiEnaN87dWmE92g1uQjrvPgrWG'
// Caching to improve performance
const nameInfoCache = new Map(); // name -> nameInfo
const addressInfoCache = new Map(); // address -> addressInfo
const pollResultsCache = new Map(); // pollName -> pollResults
if (typeof qortalRequest === 'function') { if (typeof qortalRequest === 'function') {
console.log('qortalRequest is available as a function. Setting development mode to false and baseUrl to nothing.') console.log('qortalRequest is available as a function. Setting development mode to false and baseUrl to nothing.')
isOutsideOfUiDevelopment = false isOutsideOfUiDevelopment = false
@ -223,6 +228,13 @@ const getUserAddress = async () => {
} }
} }
const getAddressInfoCached = async (address) => {
if (addressInfoCache.has(address)) return addressInfoCache.get(address)
const result = await getAddressInfo(address)
addressInfoCache.set(address, result)
return result
}
const getAddressInfo = async (address) => { const getAddressInfo = async (address) => {
const qortalAddressPattern = /^Q[A-Za-z0-9]{33}$/ // Q + 33 almum = 34 total length const qortalAddressPattern = /^Q[A-Za-z0-9]{33}$/ // Q + 33 almum = 34 total length
@ -254,6 +266,19 @@ const getAddressInfo = async (address) => {
} }
} }
const nameToAddressCache = new Map()
const fetchOwnerAddressFromNameCached = async (name) => {
if (nameToAddressCache.has(name)) {
return nameToAddressCache.get(name)
}
const address = await fetchOwnerAddressFromName(name)
nameToAddressCache.set(name, address)
return address
}
const fetchOwnerAddressFromName = async (name) => { const fetchOwnerAddressFromName = async (name) => {
console.log('fetchOwnerAddressFromName called') console.log('fetchOwnerAddressFromName called')
console.log('name:', name) console.log('name:', name)
@ -333,6 +358,15 @@ const verifyAddressIsAdmin = async (address) => {
} }
} }
const getNameInfoCached = async (name) => {
if (nameInfoCache.has(name)) {
return nameInfoCache.get(name)
}
const result = await getNameInfo(name)
nameInfoCache.set(name, result)
return result
}
const getNameInfo = async (name) => { const getNameInfo = async (name) => {
console.log('getNameInfo called') console.log('getNameInfo called')
console.log('name:', name) console.log('name:', name)
@ -1239,6 +1273,20 @@ const getProductDetails = async (service, name, identifier) => {
// Qortal poll-related calls ---------------------------------------------------------------------- // Qortal poll-related calls ----------------------------------------------------------------------
const pollOwnerAddrCache = new Map()
const getPollOwnerAddressCached = async (pollName) => {
if (pollOwnerAddrCache.has(pollName)) {
return pollOwnerAddrCache.get(pollName)
}
const ownerAddress = await getPollOwnerAddress(pollName)
// Store in cache
pollOwnerAddrCache.set(pollName, ownerAddress)
return ownerAddress
}
const getPollOwnerAddress = async (pollName) => { const getPollOwnerAddress = async (pollName) => {
try { try {
const response = await fetch(`${baseUrl}/polls/${pollName}`, { const response = await fetch(`${baseUrl}/polls/${pollName}`, {
@ -1267,6 +1315,15 @@ const getPollPublisherPublicKey = async (pollName) => {
} }
} }
const fetchPollResultsCached = async (pollName) => {
if (pollResultsCache.has(pollName)) {
return pollResultsCache.get(pollName)
}
const result = await fetchPollResults(pollName)
pollResultsCache.set(pollName, result)
return result
}
const fetchPollResults = async (pollName) => { const fetchPollResults = async (pollName) => {
try { try {
const response = await fetch(`${baseUrl}/polls/votes/${pollName}`, { const response = await fetch(`${baseUrl}/polls/votes/${pollName}`, {