mirror of
https://github.com/fullstack-cash/fullstack-gatsby-theme-bch-wallet.git
synced 2026-09-21 16:52:06 -07:00
feat(token): Added token view to the app
This commit is contained in:
Generated
+24
@@ -6151,6 +6151,11 @@
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001084.tgz",
|
||||
"integrity": "sha512-ftdc5oGmhEbLUuMZ/Qp3mOpzfZLCxPYKcvGv6v2dJJ+8EdqcvZRbAGOiLmkM/PV1QGta/uwBs8/nCl6sokDW6w=="
|
||||
},
|
||||
"canvas-renderer": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/canvas-renderer/-/canvas-renderer-2.1.1.tgz",
|
||||
"integrity": "sha512-/V0XetN7s1Mk3NO7x2wxPZYv0pLMQtGAhecuOuKR88beiYCUle1AbCcFZNLu+4NVzi9RVHS0rXtIgzPEaKidLw=="
|
||||
},
|
||||
"caseless": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
|
||||
@@ -24855,6 +24860,15 @@
|
||||
"resolved": "https://registry.npmjs.org/iterall/-/iterall-1.3.0.tgz",
|
||||
"integrity": "sha512-QZ9qOMdF+QLHxy1QIpUHUU1D5pS2CG2P69LF6L6CPjPYA/XMOmKV3PZpawHoAjHNyB0swdVTRxdYT4tbBbxqwg=="
|
||||
},
|
||||
"jdenticon": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/jdenticon/-/jdenticon-2.2.0.tgz",
|
||||
"integrity": "sha512-WGqwpjN9pab/Sah9pGnFH5tQc3HF3WbLV/tPVbykvk5nuAkxG/zhzQYWC2owvpnS+/A0HmlSx35rtY8kyN+x7Q==",
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"canvas-renderer": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"jest-diff": {
|
||||
"version": "25.5.0",
|
||||
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz",
|
||||
@@ -29646,6 +29660,16 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||
},
|
||||
"react-jdenticon": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/react-jdenticon/-/react-jdenticon-0.0.8.tgz",
|
||||
"integrity": "sha512-+oVYV1Py3JBaCZIvOeOiuj9wmpLLDFGjsp7SCDXtai9l5khhiE2caDYubt/xZEcqlO8DyALcb+ZgRgPgXY70Zg==",
|
||||
"requires": {
|
||||
"jdenticon": "^2.2.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.8.0"
|
||||
}
|
||||
},
|
||||
"react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-helmet": "^6.0.0",
|
||||
"react-jdenticon": "0.0.8",
|
||||
"react-qr-reader": "^2.2.1",
|
||||
"react-redux": "^7.2.0"
|
||||
},
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
text-transform: lowercase;
|
||||
}
|
||||
.components-container{
|
||||
min-height: calc(100vh - 100px);
|
||||
min-height: calc(100vh - var(--footer-height) - 50px);
|
||||
}
|
||||
|
||||
.sidebar-toggle:hover{
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import React from "react"
|
||||
|
||||
import { Content, Row, Col, Box } from "adminlte-2-react"
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
|
||||
class Icons extends React.Component {
|
||||
state = {}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Content>
|
||||
<Row>
|
||||
<Col sm={3} />
|
||||
<Col sm={6}>
|
||||
<Box className="hover-shadow border-none mt-2">
|
||||
<Row>
|
||||
<Col sm={12} className="text-center">
|
||||
<h1>
|
||||
<FontAwesomeIcon
|
||||
className="title-icon"
|
||||
size="xs"
|
||||
icon={"plus"}
|
||||
/>
|
||||
<span>Upload your token icon</span>
|
||||
</h1>
|
||||
</Col>
|
||||
<Col sm={12} className="text-center mt-2 mb-2">
|
||||
<p>
|
||||
You currently have 0 BCH. Go to the Portfolio page and
|
||||
Create a Wallet. Then deposit some BCH to use the SLP Icons
|
||||
tool. Get free BCH from the Bitcoin.com Faucet!
|
||||
</p>
|
||||
</Col>
|
||||
</Row>
|
||||
</Box>
|
||||
</Col>
|
||||
<Col sm={3} />
|
||||
</Row>
|
||||
</Content>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Icons
|
||||
@@ -2,7 +2,7 @@ import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import Audit from "./audit"
|
||||
import Configure from "./configure"
|
||||
import Tokens from "./icons"
|
||||
import Tokens from "./tokens"
|
||||
import Wallet from "./wallet"
|
||||
|
||||
import AdminLTE, { Sidebar, Navbar } from "adminlte-2-react"
|
||||
@@ -71,7 +71,11 @@ class AdminLTEPage extends React.Component {
|
||||
setBchWallet={_this.props.setBchWallet}
|
||||
/>
|
||||
)}
|
||||
{_this.state.section === "Tokens" && <Tokens />}
|
||||
{_this.state.section === "Tokens" &&
|
||||
<Tokens
|
||||
walletInfo={_this.props.walletInfo}
|
||||
bchWallet={_this.props.bchWallet} />
|
||||
}
|
||||
{_this.state.section === "Configure" && (
|
||||
<Configure
|
||||
walletInfo={_this.props.walletInfo}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { Content, Row, Col, Box } from "adminlte-2-react"
|
||||
import TokenCard from "./token-card"
|
||||
import TokenModal from "./token-modal"
|
||||
import Spinner from "../../../images/loader.gif"
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
|
||||
let _this
|
||||
class Tokens extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
_this = this
|
||||
this.state = {
|
||||
tokens: [],
|
||||
selectedToken: "",
|
||||
showModal: false,
|
||||
inFetch: true,
|
||||
onEmptyTokensMsg: "No tokens found on this wallet..",
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { JWT } = _this.props.walletInfo
|
||||
|
||||
return (
|
||||
<>
|
||||
{_this.state.inFetch ? (
|
||||
<div className="spinner">
|
||||
<img alt="Loading..." src={Spinner} width={100} />
|
||||
</div>
|
||||
) : (
|
||||
<Content>
|
||||
{!JWT && (
|
||||
<Box padding="true" className="container-nofound">
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<FontAwesomeIcon
|
||||
className="icon btn-animation"
|
||||
size="lg"
|
||||
icon={"exclamation-triangle"}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
<Col xs={12}>
|
||||
<em>
|
||||
You don't have a registered JWT, you could encounter
|
||||
errors viewing some of your tokens.
|
||||
</em>
|
||||
</Col>
|
||||
</Row>
|
||||
</Box>
|
||||
)}
|
||||
<br></br>
|
||||
{!_this.state.tokens.length && (
|
||||
<Box padding="true" className="container-nofound">
|
||||
<Row>
|
||||
<Col xs={12}>
|
||||
<em>{_this.state.onEmptyTokensMsg}</em>
|
||||
</Col>
|
||||
</Row>
|
||||
</Box>
|
||||
)}
|
||||
{_this.state.tokens.length && (
|
||||
<Row>
|
||||
{_this.state.tokens.map((val, i) => {
|
||||
return (
|
||||
<Col sm={4} key={`token-${i}`}>
|
||||
<TokenCard
|
||||
key={`token-${i}`}
|
||||
id={`token-${i}`}
|
||||
token={val}
|
||||
showToken={_this.showToken}
|
||||
/>
|
||||
</Col>
|
||||
)
|
||||
})}
|
||||
</Row>
|
||||
)}
|
||||
</Content>
|
||||
)}
|
||||
<TokenModal
|
||||
token={_this.state.selectedToken ? _this.state.selectedToken : {}}
|
||||
onHide={_this.toggleModal}
|
||||
show={_this.state.showModal}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
async componentDidMount() {
|
||||
const { mnemonic } = _this.props.walletInfo
|
||||
const bchWallet = _this.props.bchWallet
|
||||
let tokens = []
|
||||
let { onEmptyTokensMsg } = _this.state
|
||||
|
||||
if (mnemonic && bchWallet) {
|
||||
|
||||
try {
|
||||
await bchWallet.walletInfoPromise
|
||||
tokens = await bchWallet.listTokens()
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
if (error.error.match("rate limits")) onEmptyTokensMsg = error.error
|
||||
}
|
||||
} else {
|
||||
onEmptyTokensMsg =
|
||||
"You need to create or import a wallet first, to view tokens"
|
||||
}
|
||||
|
||||
|
||||
_this.setState({
|
||||
tokens,
|
||||
inFetch: false,
|
||||
onEmptyTokensMsg,
|
||||
})
|
||||
}
|
||||
showToken(selectedToken) {
|
||||
console.log("selectedToken", selectedToken)
|
||||
_this.setState({
|
||||
selectedToken,
|
||||
})
|
||||
_this.toggleModal()
|
||||
}
|
||||
toggleModal() {
|
||||
_this.setState({
|
||||
showModal: !_this.state.showModal,
|
||||
})
|
||||
}
|
||||
}
|
||||
Tokens.propTypes = {
|
||||
walletInfo: PropTypes.object.isRequired, // wallet info
|
||||
bchWallet: PropTypes.object, // get minimal-slp-wallet instance
|
||||
}
|
||||
export default Tokens
|
||||
@@ -0,0 +1,64 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { Row, Col, Box, Button } from "adminlte-2-react"
|
||||
import Jdenticon from "react-jdenticon"
|
||||
import "./token.css"
|
||||
let _this
|
||||
class TokenCard extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
_this = this
|
||||
this.state = {}
|
||||
}
|
||||
render() {
|
||||
const token = _this.props.token
|
||||
return (
|
||||
<>
|
||||
<Box className="hover-shadow border-none mt-2" id="token-card">
|
||||
<Row className="text-center">
|
||||
<Col sm={12} className="text-center mt-2 ">
|
||||
<Jdenticon size="100" value={token.tokenId} />
|
||||
<hr></hr>
|
||||
</Col>
|
||||
<Col sm={12} className="flex justify-content-center ">
|
||||
<div className="info-container">
|
||||
<p className="info-content">
|
||||
<b>Ticker: </b>
|
||||
<span> {token.ticker}</span>
|
||||
</p>
|
||||
<p className="info-content">
|
||||
<b>Name: </b>
|
||||
<span>{token.name}</span>
|
||||
</p>
|
||||
|
||||
<p className="info-content">
|
||||
<b>Balance</b>
|
||||
<span>{token.qty}</span>
|
||||
</p>
|
||||
</div>
|
||||
</Col>
|
||||
|
||||
<Col sm={12} className="text-center ">
|
||||
<Button
|
||||
text="Show Token"
|
||||
type="primary"
|
||||
className="btn-lg"
|
||||
onClick={() => {
|
||||
_this.props.showToken(token)
|
||||
}}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Box>
|
||||
</>
|
||||
)
|
||||
}
|
||||
shouldComponentUpdate() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
TokenCard.propTypes = {
|
||||
token: PropTypes.object.isRequired,
|
||||
showToken: PropTypes.func.isRequired,
|
||||
}
|
||||
export default TokenCard
|
||||
@@ -0,0 +1,163 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import { Content, Row, Col, Box, Button } from "adminlte-2-react"
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||
|
||||
import "./token.css"
|
||||
let _this
|
||||
class TokenModal extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
_this = this
|
||||
this.state = {}
|
||||
}
|
||||
|
||||
modalFooter = (
|
||||
<React.Fragment>
|
||||
<Button text="Close" pullLeft onClick={this.props.onHide} />
|
||||
</React.Fragment>
|
||||
)
|
||||
render() {
|
||||
const token = _this.props.token
|
||||
return (
|
||||
<>
|
||||
<Content
|
||||
title={token.name}
|
||||
modal
|
||||
modalFooter={this.modalFooter}
|
||||
show={_this.props.show}
|
||||
modalCloseButton={true}
|
||||
onHide={_this.props.onHide}
|
||||
>
|
||||
<Row>
|
||||
<Col sm={12}>
|
||||
<Box className=" border-none ">
|
||||
<Row>
|
||||
<Col
|
||||
sm={12}
|
||||
className="text-center tokenModal-info-container"
|
||||
>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>TokenId:</b>
|
||||
</Col>
|
||||
<Col xs={10} sm={8}>
|
||||
{token.tokenId}
|
||||
</Col>
|
||||
<Col xs={2} sm={1}>
|
||||
<FontAwesomeIcon
|
||||
className="icon btn-animation"
|
||||
size="lg"
|
||||
onClick={() => _this.copyToClipBoard("tokenId")}
|
||||
icon={"copy"}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>URL:</b>
|
||||
</Col>
|
||||
<Col xs={12} sm={9}>
|
||||
<a
|
||||
href={`http://${token.url}`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{token.url}
|
||||
</a>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>Ticker:</b>
|
||||
</Col>
|
||||
<Col xs={12} sm={9}>
|
||||
{token.ticker}
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>Name:</b>
|
||||
</Col>
|
||||
<Col xs={12} sm={9}>
|
||||
{token.name}
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>Balance:</b>
|
||||
</Col>
|
||||
<Col xs={12} sm={9}>
|
||||
{token.qty}
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>Decimals:</b>
|
||||
</Col>
|
||||
<Col xs={12} sm={9}>
|
||||
{token.decimals}
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row className="tokenModal-info-content mt-1 text-left">
|
||||
<Col xs={12}>
|
||||
<Row>
|
||||
<Col xs={12} sm={3}>
|
||||
<b>TokenType:</b>
|
||||
</Col>
|
||||
<Col xs={12} sm={9}>
|
||||
{token.tokenType}
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
</Box>
|
||||
</Col>
|
||||
</Row>
|
||||
</Content>
|
||||
</>
|
||||
)
|
||||
}
|
||||
// copy info to clipboard
|
||||
copyToClipBoard(key) {
|
||||
const val = _this.props.token[key]
|
||||
var textArea = document.createElement("textarea")
|
||||
textArea.value = val //copyText.textContent;
|
||||
document.body.appendChild(textArea)
|
||||
textArea.select()
|
||||
document.execCommand("Copy")
|
||||
textArea.remove()
|
||||
}
|
||||
}
|
||||
TokenModal.propTypes = {
|
||||
token: PropTypes.object.isRequired,
|
||||
show: PropTypes.bool.isRequired,
|
||||
onHide: PropTypes.func.isRequired,
|
||||
}
|
||||
export default TokenModal
|
||||
@@ -0,0 +1,50 @@
|
||||
#token-card .info-container{
|
||||
width: fit-content;
|
||||
}
|
||||
#token-card .info-container .info-content{
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
font-size: medium;
|
||||
}
|
||||
#token-card .info-container .info-content b{
|
||||
margin-right: 15px;
|
||||
}
|
||||
#token-card .divider{
|
||||
width: 100%;
|
||||
border-bottom: 1px solid black;
|
||||
}
|
||||
.tokenModal-info-content{
|
||||
/* border:0.7px solid var(--main-color); */
|
||||
border-radius: 5px;
|
||||
max-width: 100%;
|
||||
padding-top: 4px;
|
||||
padding-bottom: 4px;
|
||||
margin-right: 0px;
|
||||
margin-left: 0px;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
border-left: none;
|
||||
font-size: medium;
|
||||
}
|
||||
.tokenModal-info-content div{
|
||||
overflow:hidden;
|
||||
white-space:nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.tokenModal-info-content div b{
|
||||
margin-right: 5px;
|
||||
}
|
||||
.container-nofound {
|
||||
text-align: center;
|
||||
max-width: 80%;
|
||||
margin: 0 auto;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
font-size: large;
|
||||
}
|
||||
.spinner{
|
||||
display: flex;
|
||||
height: calc(100vh - var(--footer-height) - 50px);
|
||||
width: 100%!important;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
:root {
|
||||
--main-color:#00A74F;
|
||||
|
||||
--footer-height: 170px;
|
||||
}
|
||||
.skin-blue .main-header .logo {
|
||||
|
||||
@@ -20,3 +20,13 @@
|
||||
background-color: var(--main-color)!important;
|
||||
border-color: var(--main-color)!important;
|
||||
}
|
||||
.modal-header{
|
||||
background-color: var(--main-color);
|
||||
}
|
||||
.modal-header button , .modal-header h4{
|
||||
color: white;
|
||||
opacity: inherit;
|
||||
}
|
||||
.box{
|
||||
border-color: var(--main-color)!important;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#footer {
|
||||
width: 100%;
|
||||
/*max-height: 50px;*/
|
||||
/*min-height: 50px;*/
|
||||
min-height: var(--footer-height);
|
||||
background-color: var(--main-color);
|
||||
/*display: flex;
|
||||
justify-content: center;
|
||||
|
||||
@@ -637,9 +637,14 @@ pre tt:after {
|
||||
justify-content: center;
|
||||
}
|
||||
.justify-item-center{
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
.max-width{
|
||||
width: 100%!important;
|
||||
}
|
||||
.max-height{
|
||||
height: 100vh!important;
|
||||
}
|
||||
|
||||
.border-none{
|
||||
border: none!important ;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user