mirror of
https://github.com/Permissionless-Software-Foundation/bch-dex-taker-v2.git
synced 2026-09-21 16:52:01 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0da9d4c567 | ||
|
|
3cf69cbd95 | ||
|
|
45b28c168f | ||
|
|
3d622e9d99 | ||
|
|
29ce96ae92 | ||
|
|
a89d4c21cc | ||
|
|
561ffbaaad |
Generated
+17
-2
@@ -21,6 +21,7 @@
|
|||||||
"bch-token-sweep": "2.2.1",
|
"bch-token-sweep": "2.2.1",
|
||||||
"bootstrap": "5.2.0",
|
"bootstrap": "5.2.0",
|
||||||
"crypto-browserify": "3.12.1",
|
"crypto-browserify": "3.12.1",
|
||||||
|
"marked": "^15.0.12",
|
||||||
"nostr-tools": "2.10.4",
|
"nostr-tools": "2.10.4",
|
||||||
"p2wdb": "2.4.1",
|
"p2wdb": "2.4.1",
|
||||||
"process": "0.11.10",
|
"process": "0.11.10",
|
||||||
@@ -18223,8 +18224,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/marked": {
|
"node_modules/marked": {
|
||||||
"version": "12.0.2",
|
"version": "15.0.12",
|
||||||
"dev": true,
|
"resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz",
|
||||||
|
"integrity": "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"marked": "bin/marked.js"
|
"marked": "bin/marked.js"
|
||||||
@@ -26496,6 +26498,19 @@
|
|||||||
"js-yaml": "bin/js-yaml.js"
|
"js-yaml": "bin/js-yaml.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/semantic-release/node_modules/marked": {
|
||||||
|
"version": "12.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz",
|
||||||
|
"integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"marked": "bin/marked.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/semantic-release/node_modules/npm-run-path": {
|
"node_modules/semantic-release/node_modules/npm-run-path": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
"bch-token-sweep": "2.2.1",
|
"bch-token-sweep": "2.2.1",
|
||||||
"bootstrap": "5.2.0",
|
"bootstrap": "5.2.0",
|
||||||
"crypto-browserify": "3.12.1",
|
"crypto-browserify": "3.12.1",
|
||||||
|
"marked": "15.0.12",
|
||||||
"nostr-tools": "2.10.4",
|
"nostr-tools": "2.10.4",
|
||||||
"p2wdb": "2.4.1",
|
"p2wdb": "2.4.1",
|
||||||
"process": "0.11.10",
|
"process": "0.11.10",
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Card, Spinner } from 'react-bootstrap'
|
|||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||||
import * as nip19 from 'nostr-tools/nip19'
|
import * as nip19 from 'nostr-tools/nip19'
|
||||||
|
import NostrFormat from '../nostr-format'
|
||||||
|
|
||||||
function FeedCard (props) {
|
function FeedCard (props) {
|
||||||
const { post, appData, profiles } = props
|
const { post, appData, profiles } = props
|
||||||
@@ -87,7 +88,7 @@ function FeedCard (props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className='mb-4'>
|
<div className='mb-4'>
|
||||||
<div className='fs-5 ms-5 text-dark' style={{ lineHeight: '1.3' }}>
|
<div className='fs-5 ms-5 text-dark' style={{ lineHeight: '1.3' }}>
|
||||||
{post.content}
|
<NostrFormat content={post.content} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* Parse nostr content to html , support markdown , links , line breaks
|
||||||
|
*/
|
||||||
|
import React from 'react'
|
||||||
|
import { marked } from 'marked' // https://www.npmjs.com/package/marked/v/0.3.9
|
||||||
|
|
||||||
|
const NostrFormat = ({ content }) => {
|
||||||
|
const formatContent = (content) => {
|
||||||
|
if (!content) return ''
|
||||||
|
// create marked renderer
|
||||||
|
const renderer = new marked.Renderer()
|
||||||
|
// customize link renderer to open in new tab
|
||||||
|
renderer.link = function ({ href, text }) {
|
||||||
|
return `<a href="${href}" target="_blank" >${text}</a>`
|
||||||
|
}
|
||||||
|
// set marked options
|
||||||
|
marked.setOptions({
|
||||||
|
renderer,
|
||||||
|
breaks: true
|
||||||
|
|
||||||
|
})
|
||||||
|
// parse content to html
|
||||||
|
const html = marked.parse(content)
|
||||||
|
|
||||||
|
return html
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: formatContent(content) }} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NostrFormat
|
||||||
@@ -7,7 +7,7 @@ import { Container, Button } from 'react-bootstrap'
|
|||||||
import CopyOnClick from '../../bch-wallet/copy-on-click.js'
|
import CopyOnClick from '../../bch-wallet/copy-on-click.js'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import NostrFormat from '../nostr-format'
|
||||||
import { RelayPool } from 'nostr'
|
import { RelayPool } from 'nostr'
|
||||||
|
|
||||||
function ProfileRead (props) {
|
function ProfileRead (props) {
|
||||||
@@ -74,7 +74,9 @@ function ProfileRead (props) {
|
|||||||
</span>
|
</span>
|
||||||
<CopyOnClick walletProp='npub' appData={props.appData} value={bchWalletState.nostrKeyPair.npub} />
|
<CopyOnClick walletProp='npub' appData={props.appData} value={bchWalletState.nostrKeyPair.npub} />
|
||||||
</div>
|
</div>
|
||||||
<div className='fs-6 text-secondary'>{post.about}</div>
|
<div className='fs-6 text-secondary'>
|
||||||
|
<NostrFormat content={post.about} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='d-flex gap-2 align-items-center flex-wrap justify-content-center'>
|
<div className='d-flex gap-2 align-items-center flex-wrap justify-content-center'>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import React, { useEffect, useState } from 'react'
|
|||||||
import { Container, Card, Spinner } from 'react-bootstrap'
|
import { Container, Card, Spinner } from 'react-bootstrap'
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
|
||||||
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
import { faUser } from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import NostrFormat from '../nostr-format'
|
||||||
import { RelayPool } from 'nostr'
|
import { RelayPool } from 'nostr'
|
||||||
|
|
||||||
function PublicRead (props) {
|
function PublicRead (props) {
|
||||||
@@ -72,7 +72,7 @@ function PublicRead (props) {
|
|||||||
</div>
|
</div>
|
||||||
<div className='mb-4'>
|
<div className='mb-4'>
|
||||||
<div className='fs-5 ms-5 text-dark' style={{ lineHeight: '1.3' }}>
|
<div className='fs-5 ms-5 text-dark' style={{ lineHeight: '1.3' }}>
|
||||||
{post.content}
|
<NostrFormat content={post.content} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card.Body>
|
</Card.Body>
|
||||||
|
|||||||
@@ -85,6 +85,53 @@ function Offers (props) {
|
|||||||
console.warn('Error in getOffers() ', err)
|
console.warn('Error in getOffers() ', err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const handleBuy = useCallback(async (event) => {
|
||||||
|
try {
|
||||||
|
console.log('Buy button clicked. Event: ', event)
|
||||||
|
|
||||||
|
const targetOfferEventId = event.target.id
|
||||||
|
console.log('targetOfferEventId: ', targetOfferEventId)
|
||||||
|
|
||||||
|
// Initialize modal
|
||||||
|
setShowModal(true)
|
||||||
|
setModalBody(['Generating Counter Offer...', '(This can take a couple minutes)'])
|
||||||
|
setHideSpinner(false)
|
||||||
|
setDenyClose(true)
|
||||||
|
|
||||||
|
// Generate a counter offer.
|
||||||
|
const bchDexLib = appData.dexLib
|
||||||
|
const { offerData, partialHex } = await bchDexLib.take.takeOffer(
|
||||||
|
targetOfferEventId
|
||||||
|
)
|
||||||
|
|
||||||
|
// Upload the counter offer to Nostr.
|
||||||
|
const nostr = appData.nostr
|
||||||
|
const { eventId, noteId } = await nostr.testNostrUpload({
|
||||||
|
offerData,
|
||||||
|
partialHex
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('eventId: ', eventId)
|
||||||
|
console.log('noteId: ', noteId)
|
||||||
|
|
||||||
|
// update output modal
|
||||||
|
const newModalBody = []
|
||||||
|
newModalBody.push('Success!')
|
||||||
|
newModalBody.push('What happens next:')
|
||||||
|
newModalBody.push('The money has not yet left your wallet! It is still under your control.')
|
||||||
|
newModalBody.push('If the sellers node is online, they will accept the Counter Offer you just generated in a few minutes.')
|
||||||
|
newModalBody.push('If the tokens never show up, you can sweep the funds back into your wallet.')
|
||||||
|
|
||||||
|
setModalBody(newModalBody)
|
||||||
|
setHideSpinner(true)
|
||||||
|
setDenyClose(false)
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Error in handleBuy() ', error)
|
||||||
|
setModalBody(['Buy failed: ', error.message])
|
||||||
|
setHideSpinner(true)
|
||||||
|
setDenyClose(false)
|
||||||
|
}
|
||||||
|
}, [appData]) // Dependencies: appData since it's used inside the callback
|
||||||
|
|
||||||
// Get Offer data and manipulate it for the sake of presentation.
|
// Get Offer data and manipulate it for the sake of presentation.
|
||||||
const handleOffers = useCallback(async () => {
|
const handleOffers = useCallback(async () => {
|
||||||
@@ -129,54 +176,7 @@ function Offers (props) {
|
|||||||
|
|
||||||
setOffers(formattedOffers)
|
setOffers(formattedOffers)
|
||||||
setIsLoading(false)
|
setIsLoading(false)
|
||||||
}, [appData])
|
}, [appData, handleBuy])
|
||||||
|
|
||||||
const handleBuy = async (event) => {
|
|
||||||
try {
|
|
||||||
console.log('Buy button clicked. Event: ', event)
|
|
||||||
|
|
||||||
const targetOfferEventId = event.target.id
|
|
||||||
console.log('targetOfferEventId: ', targetOfferEventId)
|
|
||||||
|
|
||||||
// Initialize modal
|
|
||||||
setShowModal(true)
|
|
||||||
setModalBody(['Generating Counter Offer...', '(This can take a couple minutes)'])
|
|
||||||
setHideSpinner(false)
|
|
||||||
setDenyClose(true)
|
|
||||||
|
|
||||||
const options = {
|
|
||||||
method: 'post',
|
|
||||||
url: `${SERVER}offer/take`,
|
|
||||||
data: {
|
|
||||||
nostrEventId: targetOfferEventId
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await axios.request(options)
|
|
||||||
const { eventId, noteId } = result.data
|
|
||||||
console.log(`Event Id : ${eventId}`)
|
|
||||||
console.log(`Note Id ${noteId}`)
|
|
||||||
|
|
||||||
// Add link to output
|
|
||||||
const newModalBody = []
|
|
||||||
newModalBody.push('Success!')
|
|
||||||
// newModalBody.push(<a href={`https://p2wdb.fullstack.cash/entry/hash/${p2wdbHash}`} target='_blank' rel='noreferrer'>P2WDB Entry</a>)
|
|
||||||
|
|
||||||
newModalBody.push('What happens next:')
|
|
||||||
newModalBody.push('The money has not yet left your wallet! It is still under your control.')
|
|
||||||
newModalBody.push('If the sellers node is online, they will accept the Counter Offer you just generated in a few minutes.')
|
|
||||||
newModalBody.push('If the tokens never show up, you can sweep the funds back into your wallet.')
|
|
||||||
|
|
||||||
setModalBody(newModalBody)
|
|
||||||
setHideSpinner(true)
|
|
||||||
setDenyClose(false)
|
|
||||||
} catch (error) {
|
|
||||||
console.warn('Error in handleBuy() ', error)
|
|
||||||
setModalBody(['Buy failed: ', error.message])
|
|
||||||
setHideSpinner(true)
|
|
||||||
setDenyClose(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Retrieve initial offer data
|
// Retrieve initial offer data
|
||||||
|
|||||||
+4
-2
@@ -13,7 +13,8 @@ function useAppState () {
|
|||||||
ssr: true,
|
ssr: true,
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
serverUrl: 'https://free-bch.fullstack.cash' // Default server
|
serverUrl: 'https://free-bch.fullstack.cash' // Default server
|
||||||
}
|
},
|
||||||
|
nftData: {}
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log('lsState: ', lsState)
|
console.log('lsState: ', lsState)
|
||||||
@@ -38,7 +39,7 @@ function useAppState () {
|
|||||||
const [denyClose, setDenyClose] = useState(false)
|
const [denyClose, setDenyClose] = useState(false)
|
||||||
|
|
||||||
// NFTs for sale stored data to improve performance
|
// NFTs for sale stored data to improve performance
|
||||||
const [nftForSaleCacheData, setNftForSaleCacheData] = useState({})
|
const [nftForSaleCacheData, setNftForSaleCacheData] = useState(lsState.nftData || {})
|
||||||
|
|
||||||
// The wallet state makes this a true progressive web app (PWA). As
|
// The wallet state makes this a true progressive web app (PWA). As
|
||||||
// balances, UTXOs, and tokens are retrieved, this state is updated.
|
// balances, UTXOs, and tokens are retrieved, this state is updated.
|
||||||
@@ -107,6 +108,7 @@ function useAppState () {
|
|||||||
const newCacheData = Object.assign({}, cacheData, data) // Merge the new data with the cache data
|
const newCacheData = Object.assign({}, cacheData, data) // Merge the new data with the cache data
|
||||||
allCacheData[tokenId] = newCacheData // Update the cache data
|
allCacheData[tokenId] = newCacheData // Update the cache data
|
||||||
setNftForSaleCacheData(allCacheData) // Update the state
|
setNftForSaleCacheData(allCacheData) // Update the state
|
||||||
|
updateLocalStorage({ nftData: allCacheData }) // Update the local storage
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user