mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex-taker-v2.git
synced 2026-09-21 16:52:01 -07:00
Fixed merge conflicts
This commit is contained in:
Generated
+1177
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@
|
||||
"react": "19.0.0",
|
||||
"react-bootstrap": "2.10.7",
|
||||
"react-dom": "19.0.0",
|
||||
"react-markdown": "10.1.0",
|
||||
"react-router-dom": "7.1.3",
|
||||
"react-scripts": "5.0.1",
|
||||
"stream-browserify": "3.0.0",
|
||||
|
||||
@@ -25,7 +25,7 @@ import SignMessage from './sign/index.js'
|
||||
import ServerSelectView from './configuration/select-server-view'
|
||||
import NostrPost from './nostr/nostr-post/index.js'
|
||||
import NostrRead from './nostr/nostr-read/index.js'
|
||||
|
||||
import UserDataReview from './user-data-review'
|
||||
function AppBody (props) {
|
||||
// Dependency injection through props
|
||||
const appData = props.appData
|
||||
@@ -47,7 +47,7 @@ function AppBody (props) {
|
||||
<Route path='/configuration' element={<ServerSelectView appData={appData} />} />
|
||||
<Route path='/nostr-post' element={<NostrPost appData={appData} />} />
|
||||
<Route path='/nostr-read' element={<NostrRead appData={appData} />} />
|
||||
|
||||
<Route path='/user-data/:cid' element={<UserDataReview appData={appData} />} />
|
||||
</Routes>
|
||||
{/** Show in all paths except the servers view */}
|
||||
{/* {appData.currentPath !== '/servers' && <SelectServerButton linkTo='/servers' appData={appData} />} */}
|
||||
|
||||
@@ -102,8 +102,6 @@ function NftsForSale (props) {
|
||||
if (tokenData) {
|
||||
// Set data to the token object , this can be used to display the token name in the token card component.
|
||||
thisToken.tokenData = tokenData
|
||||
// Update the cache data providing the tokenId to update and the data
|
||||
appData.updateNFTCacheData(thisToken.tokenId, { tokenData })
|
||||
}
|
||||
|
||||
// Mark token to prevent fetch token data again.
|
||||
@@ -117,7 +115,7 @@ function NftsForSale (props) {
|
||||
}, [appData])
|
||||
|
||||
// Fetch mutable data if it exist and get the token icon url
|
||||
const fetchTokenInfo = useCallback(async (token) => {
|
||||
const fetchTokenMutableData = useCallback(async (token) => {
|
||||
try {
|
||||
// Get the token data
|
||||
const tokenData = token.tokenData
|
||||
@@ -137,15 +135,16 @@ function NftsForSale (props) {
|
||||
if (json.fullSizedUrl && json.fullSizedUrl.includes('http')) {
|
||||
iconUrl = json.fullSizedUrl
|
||||
}
|
||||
const userData = json.userData
|
||||
// Return icon url
|
||||
return iconUrl
|
||||
return { iconUrl, userData }
|
||||
} catch (error) {
|
||||
return false
|
||||
}
|
||||
}, [appData])
|
||||
|
||||
// This function loads the token icons from the ipfs gateways.
|
||||
const lazyLoadTokenIcons = useCallback(async (tokens) => {
|
||||
const lazyLoadMutableData = useCallback(async (tokens) => {
|
||||
try {
|
||||
setIconsAreLoaded(false)
|
||||
// map each token and fetch the icon url
|
||||
@@ -156,13 +155,12 @@ function NftsForSale (props) {
|
||||
if (thisToken.iconAlreadyDownloaded) continue
|
||||
|
||||
// Try to get token icon url from mutable data.
|
||||
const iconUrl = await fetchTokenInfo(thisToken)
|
||||
const { iconUrl, userData } = await fetchTokenMutableData(thisToken)
|
||||
console.log('iconUrl', iconUrl)
|
||||
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
|
||||
// Update the cache data providing the tokenId to update and the data
|
||||
appData.updateNFTCacheData(thisToken.tokenId, { tokenIcon: iconUrl })
|
||||
thisToken.tokenData.userData = userData
|
||||
}
|
||||
|
||||
// Mark token to prevent fetch token icon again.
|
||||
@@ -173,16 +171,17 @@ function NftsForSale (props) {
|
||||
} catch (error) {
|
||||
setIconsAreLoaded(true)
|
||||
}
|
||||
}, [fetchTokenInfo, appData])
|
||||
}, [fetchTokenMutableData, appData])
|
||||
|
||||
// Load tokens data from the cache
|
||||
const loadCacheData = useCallback(async (offers) => {
|
||||
const cacheData = appData.nftForSaleData
|
||||
// Check if exiist token data in the cache and add it to the tokens object
|
||||
const reviewNftCachedData = useCallback(async (offers) => {
|
||||
const cacheData = appData.nftForSaleCacheData
|
||||
console.log(`Token data from cache: ${JSON.stringify(cacheData, null, 2)}`)
|
||||
// Map all offers and add cache data to the offers if it exists
|
||||
// Map all offers
|
||||
for (let i = 0; i < offers.length; i++) {
|
||||
const thisToken = offers[i]
|
||||
const cacheToken = cacheData[thisToken.tokenId]
|
||||
// If cache data exists, add it to the token object
|
||||
if (cacheToken) {
|
||||
thisToken.tokenData = cacheToken.tokenData
|
||||
thisToken.icon = cacheToken.tokenIcon
|
||||
@@ -190,24 +189,46 @@ function NftsForSale (props) {
|
||||
}
|
||||
}, [appData])
|
||||
|
||||
// Check if exiist token data in the cache and add it to the tokens object
|
||||
const updateNFTCachedData = useCallback(async (offers) => {
|
||||
// Map all offers
|
||||
for (let i = 0; i < offers.length; i++) {
|
||||
const thisToken = offers[i]
|
||||
// save token icon and token data in cache
|
||||
const newTokenCacheData = {
|
||||
tokenIcon: thisToken.icon,
|
||||
tokenData: thisToken.tokenData
|
||||
}
|
||||
|
||||
console.log('newTokenCacheData: ', newTokenCacheData)
|
||||
appData.updateNFTCachedData(thisToken.tokenId, newTokenCacheData)
|
||||
}
|
||||
}, [appData])
|
||||
|
||||
// Main function to load NFT offers
|
||||
const loadNftOffers = useCallback(async () => {
|
||||
try {
|
||||
setIsLoading(true)
|
||||
// Get tokens in offers
|
||||
const offers = await getNftOffers()
|
||||
await loadCacheData(offers)
|
||||
console.log('offers: ', offers)
|
||||
// Review cached data to populate token data from cached data
|
||||
await reviewNftCachedData(offers)
|
||||
// set state to start displaying tokens cards.
|
||||
setOffers(offers)
|
||||
// Load tokens data
|
||||
// Load tokens data for any updates to the token data
|
||||
await lazyLoadTokenData(offers)
|
||||
// Load tokens icons
|
||||
await lazyLoadTokenIcons(offers)
|
||||
// Load tokens icons from mutable data
|
||||
await lazyLoadMutableData(offers)
|
||||
|
||||
// Update cached data with the latest retrieved data
|
||||
await updateNFTCachedData(offers)
|
||||
setIsLoading(false)
|
||||
} catch (err) {
|
||||
setIsLoading(false)
|
||||
console.error('Error loading NFT offers:', err)
|
||||
}
|
||||
}, [lazyLoadTokenData, lazyLoadTokenIcons, getNftOffers, loadCacheData])
|
||||
}, [lazyLoadTokenData, lazyLoadMutableData, getNftOffers, reviewNftCachedData, updateNFTCachedData])
|
||||
|
||||
// Effect to load NFTs on component mount
|
||||
useEffect(() => {
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
import React, { useState } from 'react'
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { Button, Modal, Container, Row, Col } from 'react-bootstrap'
|
||||
|
||||
function InfoButton (props) {
|
||||
const [show, setShow] = useState(false)
|
||||
const [mutableDataCid, setMutableDataCid] = useState(null)
|
||||
|
||||
const handleClose = () => {
|
||||
console.log('handleClose()')
|
||||
@@ -22,6 +23,32 @@ function InfoButton (props) {
|
||||
console.log('handleOpen()')
|
||||
setShow(true)
|
||||
}
|
||||
// Get Cid from url
|
||||
const parseCid = (url) => {
|
||||
// get the cid from the url format 'ipfs://bafybeicem27xbzs65uvbcgykcmscsgln3lmhbfrcoec3gdttkdgtxv5acq
|
||||
if (url && url.includes('ipfs://')) {
|
||||
const cid = url.split('ipfs://')[1]
|
||||
return cid
|
||||
}
|
||||
return url
|
||||
}
|
||||
|
||||
// Get token user data if it exists and verify if it contains media or markdown
|
||||
useEffect(() => {
|
||||
try {
|
||||
const userDataStr = props.token.tokenData.userData
|
||||
if (userDataStr) {
|
||||
const userData = JSON.parse(userDataStr)
|
||||
|
||||
// If user data contains media or markdown, set the mutable data cid
|
||||
if (userData?.media || userData?.markdown) {
|
||||
setMutableDataCid(parseCid(props.token.tokenData.mutableData))
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// Do nothing
|
||||
}
|
||||
}, [props.token, show])
|
||||
|
||||
// Replace with dummy button until token data is loaded.
|
||||
if (!props.token.tokenData) {
|
||||
@@ -70,6 +97,22 @@ function InfoButton (props) {
|
||||
<Col xs={8}>{props.token.tokenType}</Col>
|
||||
</Row>
|
||||
|
||||
{mutableDataCid && (
|
||||
<Row>
|
||||
<Col xs={4}><b>User Data</b>:</Col>
|
||||
<Col xs={8}>
|
||||
<a
|
||||
href={`/user-data/${mutableDataCid}`}
|
||||
target='_blank'
|
||||
rel='noopener noreferrer'
|
||||
className='btn btn-link p-0'
|
||||
>
|
||||
View User Data
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
|
||||
</Container>
|
||||
</Modal.Body>
|
||||
<Modal.Footer />
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Search in the provided cid of a mutable data, get the data from the user data and show it
|
||||
*/
|
||||
|
||||
// Global npm libraries
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { Container, Row, Col, Tabs, Tab, Spinner } from 'react-bootstrap'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
|
||||
function UserDataReview (props) {
|
||||
const appData = props.appData
|
||||
const [media, setMedia] = useState([])
|
||||
const [markdown, setMarkdown] = useState('')
|
||||
const [activeTab, setActiveTab] = useState('media')
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [error, setError] = useState(null)
|
||||
// Get the id parameter from the URL
|
||||
const { cid } = useParams()
|
||||
|
||||
useEffect(() => {
|
||||
const loadMedia = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const { json } = await appData.wallet.cid2json({ cid })
|
||||
const userDataString = json.userData
|
||||
if (userDataString) {
|
||||
const userData = JSON.parse(userDataString)
|
||||
setMedia(userData.media)
|
||||
setMarkdown(userData.markdown)
|
||||
}
|
||||
} catch (error) {
|
||||
setError(error.message)
|
||||
}
|
||||
setLoading(false)
|
||||
}
|
||||
loadMedia()
|
||||
}, [cid, appData.wallet])
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Row>
|
||||
<Col>
|
||||
{error && <p className='text-danger'>{error}</p>}
|
||||
{loading
|
||||
? (
|
||||
<div className='text-center my-5'>
|
||||
<Spinner animation='border' role='status' variant='primary'>
|
||||
<span className='visually-hidden'>Loading...</span>
|
||||
</Spinner>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<Tabs
|
||||
activeKey={activeTab}
|
||||
onSelect={(k) => setActiveTab(k)}
|
||||
className='mb-4'
|
||||
>
|
||||
<Tab eventKey='media' title='Media'>
|
||||
{media && media.length > 0
|
||||
? (
|
||||
<Row className='mt-3'>
|
||||
{media.map((item, index) => (
|
||||
<Col key={index} xs={12} sm={6} md={4} lg={4} className='mb-3'>
|
||||
<img
|
||||
src={item.url}
|
||||
alt={`Review media ${index + 1}`}
|
||||
style={{ width: '100%', height: '250px', objectFit: 'cover', borderRadius: '8px' }}
|
||||
/>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
)
|
||||
: (
|
||||
<p className='mt-3'>No media content available</p>
|
||||
)}
|
||||
</Tab>
|
||||
<Tab eventKey='markdown' title='Content'>
|
||||
{markdown
|
||||
? (
|
||||
<div className='markdown-content mt-3'>
|
||||
<ReactMarkdown>{markdown}</ReactMarkdown>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<p className='mt-3'>No content available</p>
|
||||
)}
|
||||
</Tab>
|
||||
</Tabs>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default UserDataReview
|
||||
+8
-9
@@ -37,8 +37,8 @@ function useAppState () {
|
||||
const [hideSpinner, setHideSpinner] = useState(false)
|
||||
const [denyClose, setDenyClose] = useState(false)
|
||||
|
||||
// NFTs for sale state data
|
||||
const [nftForSaleData, setNftForSaleData] = useState({})
|
||||
// NFTs for sale stored data to improve performance
|
||||
const [nftForSaleCacheData, setNftForSaleCacheData] = useState({})
|
||||
|
||||
// The wallet state makes this a true progressive web app (PWA). As
|
||||
// balances, UTXOs, and tokens are retrieved, this state is updated.
|
||||
@@ -100,14 +100,13 @@ function useAppState () {
|
||||
}
|
||||
|
||||
// Update NFT for sale tokens data
|
||||
function updateNFTCacheData (tokenId, data) {
|
||||
const allCacheData = nftForSaleData // Get all cache data
|
||||
function updateNFTCachedData (tokenId, data) {
|
||||
const allCacheData = nftForSaleCacheData // Get all cache data
|
||||
const cacheData = allCacheData[tokenId] || {} // Get cache data for the tokenId
|
||||
|
||||
const newCacheData = Object.assign({}, cacheData, data) // Merge the new data with the cache data
|
||||
console.log('newCacheData: ', newCacheData)
|
||||
allCacheData[tokenId] = newCacheData // Update the cache data
|
||||
setNftForSaleData(allCacheData) // Update the state
|
||||
setNftForSaleCacheData(allCacheData) // Update the state
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -146,9 +145,9 @@ function useAppState () {
|
||||
setDexLib,
|
||||
nostr,
|
||||
setNostr,
|
||||
nftForSaleData,
|
||||
setNftForSaleData,
|
||||
updateNFTCacheData
|
||||
nftForSaleCacheData,
|
||||
setNftForSaleCacheData,
|
||||
updateNFTCachedData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user