Merge pull request #2 from Permissionless-Software-Foundation/ct-unstable

Nav Menu used to bring up different Views
This commit is contained in:
Chris Troutner
2022-07-03 11:41:13 -07:00
committed by GitHub
7 changed files with 150 additions and 72 deletions
+3 -1
View File
@@ -10,8 +10,10 @@ This app can be compiled and uploaded to Filecoin via [web3.storage](https://web
- [react-bootstrap](https://react-bootstrap.github.io/) is used for general style and layout control.
- An easily customized *waiting modal* component can be invoked while waiting for network calls to complete.
- [minimal-slp-wallet](https://www.npmjs.com/package/minimal-slp-wallet) is used to access tokens and BCH on the Bitcoin Cash blockchain.
- A 'server selection' dropdown allows the user to select from an array of redundant back end servers.
- A 'server selection' dropdown allows the user to select from an array of redundant [web3 back end servers](https://cashstack.info).
- This site is statically compiled, uploaded to Filecoin, and served over IPFS for censorship resistance and version control.
- A collapsible navigation menu is used to load different views.
- This app can be compiled into an native Android app using [react-bootstrap-web3-android](https://github.com/Permissionless-Software-Foundation/react-bootstrap-web3-android).
## Installation
```bash
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "nft-browser-v2",
"name": "react-bootstrap-web3-spa",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "nft-browser-v2",
"name": "react-bootstrap-web3-spa",
"version": "1.0.0",
"dependencies": {
"axios": "0.27.2",
+22 -32
View File
@@ -10,13 +10,12 @@ import { useQueryParam, StringParam } from 'use-query-params'
// Local libraries
import './App.css'
import LoadScripts from './components/load-scripts'
// import NFTs from './components/nfts'
import WaitingModal from './components/waiting-modal'
import AsyncLoad from './services/async-load'
import ServerSelect from './components/servers'
import Footer from './components/footer'
import GetBalance from './components/balance'
import NavMenu from './components/nav-menu'
import AppBody from './components/app-body'
// Default restURL for a back-end server.
let serverURL = 'https://free-bch.fullstack.cash'
@@ -32,13 +31,13 @@ class App extends React.Component {
// Working array for storing modal output.
this.modalBody = []
this.tokenData = {}
this.state = {
walletInitialized: false,
wallet: false,
modalBody: this.modalBody,
hideSpinner: false
hideSpinner: false,
menuState: 0
}
this.cnt = 0
@@ -56,27 +55,6 @@ class App extends React.Component {
const wallet = await this.asyncLoad.initWallet(serverURL)
// this.addToModal('Getting Group Token Information')
// Get Group Token info
// const groupData = await this.asyncLoad.getGroupData(groupTokenId)
// console.log(`groupData: ${JSON.stringify(groupData, null, 2)}`)
// this.addToModal('Getting NFT Information')
/// Get NFT child info
// const nftData = []
// for (let i = 0; i < groupData.nfts.length; i++) {
// const tokenData = await this.asyncLoad.getTokenData(groupData.nfts[i])
// nftData.push(tokenData)
// }
// console.log(`nft data: ${JSON.stringify(nftData, null, 2)}`)
// this.tokenData = {
// groupData,
// nftData
// }
this.setState({
wallet,
walletInitialized: true
@@ -96,13 +74,14 @@ class App extends React.Component {
render () {
// console.log('App component rendered. this.state.wallet: ', this.state.wallet)
// console.log(`App component menuState: ${this.state.menuState}`)
return (
<>
<GetRestUrl />
<LoadScripts />
<NavMenu />
{this.state.walletInitialized ? <InitializedView wallet={this.state.wallet} tokens={this.tokenData} /> : <UninitializedView modalBody={this.state.modalBody} hideSpinner={this.state.hideSpinner} />}
<NavMenu menuHandler={this.onMenuClick} />
{this.state.walletInitialized ? <InitializedView wallet={this.state.wallet} menuState={this.state.menuState} /> : <UninitializedView modalBody={this.state.modalBody} hideSpinner={this.state.hideSpinner} />}
<ServerSelect />
<Footer />
</>
@@ -117,6 +96,17 @@ class App extends React.Component {
modalBody: this.modalBody
})
}
// This handler is passed into the child menu component. When an item in the
// nav menu is clicked, this handler will update the state. The state is
// used by the AppBody component to determine which View component to display.
onMenuClick (menuState) {
// console.log('menuState: ', menuState)
_this.setState({
menuState
})
}
}
// This is rendered *before* the BCH wallet is initialized.
@@ -132,14 +122,18 @@ function UninitializedView (props) {
// This is rendered *after* the BCH wallet is initialized.
function InitializedView (props) {
// console.log(`InitializedView props.menuState: ${props.menuState}`)
// console.log(`InitializedView _this.state.menuState: ${_this.state.menuState}`)
return (
<>
<br />
<GetBalance wallet={_this.state.wallet} />
<AppBody menuState={_this.state.menuState} wallet={props.wallet} />
</>
)
}
// Get the restURL query parameter.
function GetRestUrl (props) {
const [restURL] = useQueryParam('restURL', StringParam)
// console.log('restURL: ', restURL)
@@ -149,8 +143,4 @@ function GetRestUrl (props) {
return (<></>)
}
// function sleep (ms) {
// return new Promise(resolve => setTimeout(resolve, ms))
// }
export default App
+55
View File
@@ -0,0 +1,55 @@
/*
This Body component is a container for all the different Views of the app.
Views are equivalent to 'pages' in a multi-page app. Views are hidden or
displayed to simulate the use of pages in an SPA.
The Body app contains all the Views and chooses which to show, based on
the state of the Menu component.
*/
// Global npm libraries
import React from 'react'
// Local libraries
import GetBalance from '../balance'
import TakePicture from '../take-picture'
let _this
class AppBody extends React.Component {
constructor (props) {
super(props)
this.state = {
activeView: 0,
menuState: props.menuState,
wallet: props.wallet
}
_this = this
}
render () {
// console.log(`AppBody menu state: ${this.props.menuState}`)
return (
<>
{this.chooseView(this.props.menuState)}
</>
)
}
chooseView (menuState) {
// console.log(`chooseView() menuState: ${menuState}`)
switch (menuState) {
case 0:
return (<GetBalance wallet={_this.state.wallet} />)
case 1:
return (<TakePicture />)
default:
return (<GetBalance wallet={_this.state.wallet} />)
}
}
}
export default AppBody
+2 -2
View File
@@ -34,7 +34,7 @@ class GetBalance extends React.Component {
<Form.Control type='text' placeholder='bitcoincash:qqlrzp23w08434twmvr4fxw672whkjy0py26r63g3d' onChange={e => this.setState({ textInput: e.target.value })} />
</Form.Group>
<Button variant='primary' onClick={this.getBalance}>
<Button variant='primary' onClick={this.handleGetBalance}>
Check Balance
</Button>
</Form>
@@ -51,7 +51,7 @@ class GetBalance extends React.Component {
)
}
async getBalance(event) {
async handleGetBalance (event) {
try {
const textInput = _this.state.textInput
+28 -27
View File
@@ -7,52 +7,53 @@
// Global npm libraries
import React from 'react'
import { Nav, Navbar, NavDropdown, Image } from "react-bootstrap"
import { Nav, Navbar, Image } from 'react-bootstrap'
import Logo from './psf-logo.png'
// import { ReactComponent as Logo } from "./psf-logo.png"
class NavMenu extends React.Component {
constructor (props) {
super(props)
console.log('NavMenu')
// This is the event handler passed in from the Parent component.
this.parentMenuHandler = props.menuHandler
// this.state = {
// selectedMenuItem: 0
// }
}
render () {
// console.log(`selectedMenuItem: ${this.state.selectedMenuItem}`)
// this.handleMenuClick(this.state.selectedMenuItem)
return (
<>
<Navbar collapseOnSelect expand="xxxl" bg="dark" variant="dark" style={{paddingRight: '20px'}} >
<Navbar.Brand href="#home" style={{paddingLeft: '20px'}}>
<Image src={Logo} thumbnail width="50" />{' '}
<Navbar collapseOnSelect expand='xxxl' bg='dark' variant='dark' style={{ paddingRight: '20px' }}>
<Navbar.Brand href='#home' style={{ paddingLeft: '20px' }}>
<Image src={Logo} thumbnail width='50' />{' '}
PSF Web3 Demo
</Navbar.Brand>
<Navbar.Toggle aria-controls="responsive-navbar-nav" />
<Navbar.Collapse id="responsive-navbar-nav">
<Nav className="mr-auto">
<Nav.Link href="#features">Placeholder 1</Nav.Link>
<NavDropdown title="Dropdown" id="collasible-nav-dropdown">
<NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
<NavDropdown.Item href="#action/3.2">
Another action
</NavDropdown.Item>
<NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
<NavDropdown.Divider />
<NavDropdown.Item href="#action/3.4">
Separated link
</NavDropdown.Item>
</NavDropdown>
</Nav>
<Nav>
<Nav.Link href="#deets">Placeholder 2</Nav.Link>
<Nav.Link eventKey={2} href="#memes">
Placeholder 3
</Nav.Link>
<Navbar.Toggle aria-controls='responsive-navbar-nav' />
<Navbar.Collapse id='responsive-navbar-nav'>
<Nav className='mr-auto'>
<Nav.Link href='#' onClick={() => this.handleClickEvent(0)}>Check Balance</Nav.Link>
<Nav.Link href='#' onClick={() => this.handleClickEvent(1)}>Take Picture</Nav.Link>
<Nav.Link href='#'>Placeholder 3</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
</>
)
}
handleClickEvent (menuItem) {
// Update the
// this.setState({selectedMenuItem: menuItem})
// Pass the selected menu item up to the parent component.
this.parentMenuHandler(menuItem)
}
}
export default NavMenu
+30
View File
@@ -0,0 +1,30 @@
/*
This is a View component that allows the user to take a picture with their
webcam or phone.
*/
// Global npm libraries
import React from 'react'
class TakePicture extends React.Component {
constructor (props) {
super(props)
console.log('Take Picture component loaded')
// this.state = {
// activeView: 0,
// menuState: props.menuState
// }
}
render () {
return (
<>
<p>Take Picture Component Placeholder</p>
</>
)
}
}
export default TakePicture