feat(App): Major refactor of App.js to create functional component

This commit is contained in:
Chris Troutner
2023-02-10 09:17:40 -08:00
parent 9d05d83d50
commit 34c71ddf86
3 changed files with 138 additions and 134 deletions
+136 -134
View File
@@ -3,7 +3,7 @@
*/ */
// Global npm libraries // Global npm libraries
import React from 'react' import React, { useState, useEffect } from 'react'
import { useQueryParam, StringParam } from 'use-query-params' import { useQueryParam, StringParam } from 'use-query-params'
// Local libraries // Local libraries
@@ -16,9 +16,6 @@ import Footer from './components/footer'
import NavMenu from './components/nav-menu' import NavMenu from './components/nav-menu'
import AppBody from './components/app-body' import AppBody from './components/app-body'
// Default restURL for a back-end server.
let serverUrl = 'https://free-bch.fullstack.cash'
// Default alternative servers. // Default alternative servers.
const defaultServerOptions = [ const defaultServerOptions = [
{ value: 'https://free-bch.fullstack.cash', label: 'https://free-bch.fullstack.cash' }, { value: 'https://free-bch.fullstack.cash', label: 'https://free-bch.fullstack.cash' },
@@ -27,157 +24,178 @@ const defaultServerOptions = [
{ value: 'https://wa-usa-bch-consumer.fullstackcash.nl', label: 'https://wa-usa-bch-consumer.fullstackcash.nl' } { value: 'https://wa-usa-bch-consumer.fullstackcash.nl', label: 'https://wa-usa-bch-consumer.fullstackcash.nl' }
] ]
let _this // let _this
class App extends React.Component { function App (props) {
constructor (props) { // BEGIN STATE
super(props)
// Encasulate dependencies // Get the CashStack URL from a query parameter, if it exists.
this.asyncLoad = new AsyncLoad() const [restURL] = useQueryParam('restURL', StringParam)
console.log('restURL: ', restURL)
// Set default CashStack URL value if there is now query parameter.
const [serverUrl, setServerUrl] = useState('https://free-bch.fullstack.cash')
if (restURL) setServerUrl(restURL)
this.state = { const [menuState, setMenuState] = useQueryParam(0)
wallet: false, // BCH wallet instance const [wallet, setWallet] = useState(false)
menuState: 0, // The current View being displayed in the app const [servers, setServers] = useState(defaultServerOptions)
serverUrl, // Stores the URL for the currently selected server.
servers: defaultServerOptions, // A list of back end servers.
// Startup Modal // Startup state
showStartModal: true, // Should the startup modal be visible? // When the page is loaded, it goes through a series of async network calls
asyncInitFinished: false, // Did startup finish? // to initialize the app. These variables track the state of this startup
asyncInitSucceeded: null, // Did startup finish successfully? // process.
modalBody: [], // Strings displayed in the modal const [asyncInitStarted, setAsyncInitStarted] = useState(false)
hideSpinner: false, // Spinner gif in modal const [asyncInitFinished, setAsyncInitFinished] = useState(false)
denyClose: false const [asyncInitSucceeded, setAsyncInitSucceeded] = useState(null)
}
this.cnt = 0 // Startup Modal
const [showStartModal, setShowStartModal] = useState(true)
const [modalBody, setModalBody] = useState([])
const [hideSpinner, setHideSpinner] = useState(false)
const [denyClose, setDenyClose] = useState(false)
_this = this // Load all the app state into a single object that can be passed to child
// components.
const appData = {
wallet,
setWallet,
servers,
setServers,
showStartModal,
setShowStartModal,
menuState,
setMenuState,
asyncInitFinished,
setAsyncInitFinished,
asyncInitSucceeded,
setAsyncInitSucceeded,
modalBody,
setModalBody,
hideSpinner,
setHideSpinner,
denyClose,
setDenyClose
} }
async componentDidMount () { // END STATE
try {
this.addToModal('Loading minimal-slp-wallet')
this.setState({ // Encasulate dependencies
denyClose: true const asyncLoad = new AsyncLoad()
})
await this.asyncLoad.loadWalletLib() useEffect(() => {
async function asyncEffect () {
// console.log('asyncInitStarted: ', asyncInitStarted)
if (!asyncInitStarted) {
try {
setAsyncInitStarted(true)
this.addToModal('Getting alternative servers') addToModal('Loading minimal-slp-wallet', appData)
const servers = await this.asyncLoad.getServers()
// console.log('servers: ', servers)
this.addToModal('Initializing wallet') setDenyClose(true)
// console.log(`Initializing wallet with back end server ${serverUrl}`)
const wallet = await this.asyncLoad.initWallet(serverUrl) const Wallet = await asyncLoad.loadWalletLib()
console.log('Wallet: ', Wallet)
this.setState({ addToModal('Getting alternative servers', appData)
wallet, const gistServers = await asyncLoad.getServers()
serverUrl, setServers(gistServers)
// queryParamExists, console.log('servers: ', servers)
servers,
showStartModal: false,
asyncInitFinished: true,
asyncInitSucceeded: true,
denyClose: false
})
} catch (err) {
this.modalBody = [
`Error: ${err.message}`,
'Try selecting a different back end server using the drop-down menu at the bottom of the app.'
]
this.setState({ // throw new Error('test error')
modalBody: this.modalBody,
hideSpinner: true,
showStartModal: true,
asyncInitFinished: true,
asyncInitSucceeded: false,
denyClose: false
})
}
}
render () { addToModal('Initializing wallet', appData)
// console.log('App component rendered. this.state.wallet: ', this.state.wallet) console.log(`Initializing wallet with back end server ${serverUrl}`)
// console.log(`App component menuState: ${this.state.menuState}`)
// console.log(`render() this.state.serverUrl: ${this.state.serverUrl}`)
// This is a macro object that is passed to all child components. It gathers const walletTemp = await asyncLoad.initWallet(serverUrl)
// all the data and handlers used throughout the app. setWallet(walletTemp)
const appData = {
servers: this.state.servers, // Alternative back end servers
wallet: this.state.wallet
}
return ( // Update state
<> setShowStartModal(false)
<GetRestUrl /> setDenyClose(false)
<LoadScripts />
<NavMenu menuHandler={this.onMenuClick} />
{ // Update the startup state.
this.state.showStartModal setAsyncInitFinished(true)
? <UninitializedView setAsyncInitSucceeded(true)
modalBody={this.state.modalBody} console.log('useEffect() startup finished successfully')
hideSpinner={this.state.hideSpinner} } catch (err) {
appData={appData} const errModalBody = [
denyClose={this.state.denyClose} `Error: ${err.message}`,
/> 'Try selecting a different back end server using the drop-down menu at the bottom of the app.'
: <InitializedView wallet={this.state.wallet} menuState={this.state.menuState} appData={appData} /> ]
setModalBody(errModalBody)
// Update Modal State
setHideSpinner(true)
setShowStartModal(true)
setDenyClose(false)
// Update the startup state.
setAsyncInitFinished(true)
setAsyncInitSucceeded(false)
} }
}
}
asyncEffect()
})
<SelectServerButton menuHandler={this.onMenuClick} /> return (
<Footer appData={appData} /> <>
</> <LoadScripts />
) <NavMenu menuHandler={onMenuClick} />
}
// Add a new line to the waiting modal. {
addToModal (inStr) { showStartModal
const modalBody = this.state.modalBody ? (<UninitializedView
appData={appData}
/>)
: (<InitializedView
appData={appData}
/>)
}
modalBody.push(inStr) <SelectServerButton menuHandler={onMenuClick} />
<Footer appData={appData} />
</>
)
}
this.setState({ // Add a new line to the waiting modal.
modalBody function addToModal (inStr, appData) {
}) console.log('addToModal() inStr: ', inStr)
}
// This handler is passed into the child menu component. When an item in the appData.setModalBody(prevBody => {
// nav menu is clicked, this handler will update the state. The state is // console.log('prevBody: ', prevBody)
// used by the AppBody component to determine which View component to display. prevBody.push(inStr)
onMenuClick (menuState) { return prevBody
// console.log('menuState: ', menuState) })
}
_this.setState({ // This handler is passed into the child menu component. When an item in the
menuState // 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.
} function onMenuClick (menuState, appData) {
// console.log('menuState: ', menuState)
appData.setMenuState(menuState)
} }
// This is rendered *before* the BCH wallet is initialized. // This is rendered *before* the BCH wallet is initialized.
function UninitializedView (props) { function UninitializedView (props = {}) {
// console.log('UninitializedView props: ', props) // console.log('UninitializedView props: ', props)
const heading = 'Loading Blockchain Data...' const heading = 'Connecting to BCH blockchain...'
return ( return (
<> <>
<WaitingModal <WaitingModal
heading={heading} heading={heading}
body={props.modalBody} body={props.appData.modalBody}
hideSpinner={props.hideSpinner} hideSpinner={props.appData.hideSpinner}
denyClose={props.denyClose} denyClose={props.appData.denyClose}
/> />
{ {
_this.state.asyncInitFinished props.asyncInitFinished
? <AppBody menuState={100} wallet={props.wallet} appData={props.appData} /> ? <AppBody menuState={100} wallet={props.appData.wallet} appData={props.appData} />
: null : null
} }
</> </>
@@ -186,28 +204,12 @@ function UninitializedView (props) {
// This is rendered *after* the BCH wallet is initialized. // This is rendered *after* the BCH wallet is initialized.
function InitializedView (props) { function InitializedView (props) {
// console.log(`InitializedView props.menuState: ${props.menuState}`)
// console.log(`InitializedView _this.state.menuState: ${_this.state.menuState}`)
return ( return (
<> <>
<br /> <br />
<AppBody menuState={_this.state.menuState} wallet={props.wallet} appData={props.appData} /> <AppBody menuState={props.appData.menuState} wallet={props.appData.wallet} appData={props.appData} />
</> </>
) )
} }
// Get the restURL query parameter.
function GetRestUrl (props) {
const [restURL] = useQueryParam('restURL', StringParam)
// console.log('restURL: ', restURL)
if (restURL) {
serverUrl = restURL
// queryParamExists = true
}
return (<></>)
}
export default App export default App
+1
View File
@@ -45,6 +45,7 @@ function ModalTemplate (props) {
function BodyList (props) { function BodyList (props) {
const items = props.body const items = props.body
// console.log('BodyList items: ', items)
const listItems = [] const listItems = []
+1
View File
@@ -17,6 +17,7 @@ class AsyncLoad {
// attached to the global 'window' object. // attached to the global 'window' object.
async loadWalletLib () { async loadWalletLib () {
do { do {
console.log('window.SlpWallet: ', window.SlpWallet)
if (typeof window !== 'undefined' && window.SlpWallet) { if (typeof window !== 'undefined' && window.SlpWallet) {
this.BchWallet = window.SlpWallet this.BchWallet = window.SlpWallet