From 3b1b6248ab63e2ba0e124bf9b6b43563a67e1264 Mon Sep 17 00:00:00 2001 From: Daniel Gonzalez Date: Mon, 20 Oct 2025 18:38:58 -0400 Subject: [PATCH] feat(nft): Load NFT card from bch-dex DB --- .../app-body/nfts-for-sale/index.js | 42 +++++++++++++++---- .../app-body/nfts-for-sale/info-button.js | 2 +- .../app-body/nostr/profile/nft-for-sale.js | 2 +- src/components/app-body/slp-tokens/index.js | 2 +- .../app-body/slp-tokens/info-button.js | 2 +- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/components/app-body/nfts-for-sale/index.js b/src/components/app-body/nfts-for-sale/index.js index 6a19e18..ad78efe 100644 --- a/src/components/app-body/nfts-for-sale/index.js +++ b/src/components/app-body/nfts-for-sale/index.js @@ -11,7 +11,7 @@ */ // Global npm libraries -import React, { useState, useEffect, useCallback } from 'react' +import React, { useState, useEffect, useCallback, useRef } from 'react' import { Container, Row, Col, Button, Spinner } from 'react-bootstrap' import axios from 'axios' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' @@ -35,9 +35,13 @@ function NftsForSale (props) { const [iconsAreLoaded, setIconsAreLoaded] = useState(false) const [dataAreLoaded, setDataAreLoaded] = useState(false) const [currentPage, setCurrentPage] = useState(0) + const [lastLoadedPage, setLastLoadedPage] = useState(0) const [totalPages, setTotalPages] = useState(0) const [selectedFilter, setSelectedFilter] = useState('Misc') + // Flag to prevent load data multiple times on component mount! + const componentMountRef = useRef(false) + // Handler for previous page const handlePreviousPage = () => { if (currentPage > 0) { @@ -70,6 +74,20 @@ function NftsForSale (props) { return offer } }, [appData]) + // Function to process token metadata (iconUrl , userData). + const processOfferMetadata = useCallback(async (offer) => { + try { + // Token icon + if (offer.tokenIconUrl) { + offer.icon = offer.tokenIconUrl + offer.iconAlreadyDownloaded = true + offer.userData = JSON.parse(offer.userDataStr) + } + return offer + } catch (error) { + return offer + } + }, []) // Fetch offers const getNftOffers = useCallback(async (page = 0) => { @@ -86,7 +104,8 @@ function NftsForSale (props) { for (let i = 0; i < rawOffers.length; i++) { const offer = rawOffers[i] const processedOffer = await processTokenData(offer) - processedOffers.push(processedOffer) + const processedOfferMetadata = await processOfferMetadata(processedOffer) + processedOffers.push(processedOfferMetadata) } setOffersAreLoaded(true) @@ -97,7 +116,7 @@ function NftsForSale (props) { setOffersAreLoaded(true) throw err } - }, [processTokenData]) + }, [processTokenData, processOfferMetadata]) // This function loads the token data . const lazyLoadTokenData = useCallback(async (tokens) => { @@ -166,6 +185,7 @@ function NftsForSale (props) { const thisToken = tokens[i] // Incon does not need to be downloaded, so continue with the next one + console.log('Icon already downloaded ', thisToken.iconAlreadyDownloaded) if (thisToken.iconAlreadyDownloaded) continue // Try to get token icon url from mutable data. @@ -174,7 +194,7 @@ function NftsForSale (props) { if (iconUrl) { // Set the icon url to the token , this can be used to display the icon in the token card component. thisToken.icon = iconUrl - thisToken.tokenData.userData = userData + thisToken.userData = userData } // Mark token to prevent fetch token icon again. @@ -246,17 +266,23 @@ function NftsForSale (props) { // Effect to load NFTs on component mount useEffect(() => { - console.log('loading nfts for sale') - loadNftOffers() + // Peevent to run multiple times + if (!componentMountRef.current) { + console.log('loading nfts for sale') + loadNftOffers() + componentMountRef.current = true + } }, [loadNftOffers]) // Effect to reload data when page changes useEffect(() => { - if (currentPage >= 0) { + // Validate to prevent load same page again + if (currentPage >= 0 && currentPage !== lastLoadedPage) { console.log('page changed, reloading nfts for sale') loadNftOffers(currentPage) + setLastLoadedPage(currentPage) } - }, [currentPage, loadNftOffers]) + }, [currentPage, loadNftOffers, lastLoadedPage]) // Handler for refresh button const handleRefresh = useCallback(() => { diff --git a/src/components/app-body/nfts-for-sale/info-button.js b/src/components/app-body/nfts-for-sale/info-button.js index 663f572..e4f939c 100644 --- a/src/components/app-body/nfts-for-sale/info-button.js +++ b/src/components/app-body/nfts-for-sale/info-button.js @@ -36,7 +36,7 @@ function InfoButton (props) { // Get token user data if it exists and verify if it contains media or markdown useEffect(() => { try { - const userDataStr = props.token.tokenData.userData + const userDataStr = props.token.userData if (userDataStr) { const userData = JSON.parse(userDataStr) diff --git a/src/components/app-body/nostr/profile/nft-for-sale.js b/src/components/app-body/nostr/profile/nft-for-sale.js index 4c29cd5..e43616b 100644 --- a/src/components/app-body/nostr/profile/nft-for-sale.js +++ b/src/components/app-body/nostr/profile/nft-for-sale.js @@ -145,7 +145,7 @@ function NFTForSale (props) { if (iconUrl) { // Set the icon url to the token , this can be used to display the icon in the token card component. thisToken.icon = iconUrl - thisToken.tokenData.userData = userData + thisToken.userData = userData } // Mark token to prevent fetch token icon again. diff --git a/src/components/app-body/slp-tokens/index.js b/src/components/app-body/slp-tokens/index.js index cee3e83..3a77066 100644 --- a/src/components/app-body/slp-tokens/index.js +++ b/src/components/app-body/slp-tokens/index.js @@ -124,7 +124,7 @@ const SlpTokens = (props) => { if (iconUrl) { // Set the icon url to the token , this can be used to display the icon in the token card component. thisToken.icon = iconUrl - thisToken.tokenData.userData = userData + thisToken.userData = userData } // Mark token to prevent fetch token icon again. diff --git a/src/components/app-body/slp-tokens/info-button.js b/src/components/app-body/slp-tokens/info-button.js index 1fda591..79fac2b 100644 --- a/src/components/app-body/slp-tokens/info-button.js +++ b/src/components/app-body/slp-tokens/info-button.js @@ -59,7 +59,7 @@ function InfoButton (props) { useEffect(() => { try { console.log('props token', props.token) - const userDataStr = props.token.tokenData.userData + const userDataStr = props.token.userData if (userDataStr) { const userData = JSON.parse(userDataStr)