Merge pull request #30 from Permissionless-Software-Foundation/router

fix(router): Refactored to add browser router functionality
This commit is contained in:
Chris Troutner
2025-02-01 16:54:16 -07:00
committed by GitHub
10 changed files with 152 additions and 65 deletions
+70
View File
@@ -15,6 +15,7 @@
"react": "19.0.0", "react": "19.0.0",
"react-bootstrap": "2.10.7", "react-bootstrap": "2.10.7",
"react-dom": "19.0.0", "react-dom": "19.0.0",
"react-router-dom": "7.1.3",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"use-query-params": "1.2.3" "use-query-params": "1.2.3"
}, },
@@ -3461,6 +3462,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/cookie": {
"version": "0.6.0",
"resolved": "http://94.130.170.209:4873/@types%2fcookie/-/cookie-0.6.0.tgz",
"integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==",
"license": "MIT"
},
"node_modules/@types/eslint": { "node_modules/@types/eslint": {
"version": "7.29.0", "version": "7.29.0",
"license": "MIT", "license": "MIT",
@@ -12792,6 +12799,8 @@
"node_modules/node-fetch": { "node_modules/node-fetch": {
"name": "@achingbrain/node-fetch", "name": "@achingbrain/node-fetch",
"version": "2.6.7", "version": "2.6.7",
"resolved": "https://registry.npmjs.org/@achingbrain/node-fetch/-/node-fetch-2.6.7.tgz",
"integrity": "sha512-iTASGs+HTFK5E4ZqcMsHmeJ4zodyq8L38lZV33jwqcBJYoUt3HjN4+ot+O9/0b+ke8ddE7UgOtVuZN/OkV19/g==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
@@ -15109,6 +15118,55 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-router": {
"version": "7.1.3",
"resolved": "http://94.130.170.209:4873/react-router/-/react-router-7.1.3.tgz",
"integrity": "sha512-EezYymLY6Guk/zLQ2vRA8WvdUhWFEj5fcE3RfWihhxXBW7+cd1LsIiA3lmx+KCmneAGQuyBv820o44L2+TtkSA==",
"license": "MIT",
"dependencies": {
"@types/cookie": "^0.6.0",
"cookie": "^1.0.1",
"set-cookie-parser": "^2.6.0",
"turbo-stream": "2.4.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
},
"peerDependenciesMeta": {
"react-dom": {
"optional": true
}
}
},
"node_modules/react-router-dom": {
"version": "7.1.3",
"resolved": "http://94.130.170.209:4873/react-router-dom/-/react-router-dom-7.1.3.tgz",
"integrity": "sha512-qQGTE+77hleBzv9SIUIkGRvuFBQGagW+TQKy53UTZAO/3+YFNBYvRsNIZ1GT17yHbc63FylMOdS+m3oUriF1GA==",
"license": "MIT",
"dependencies": {
"react-router": "7.1.3"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": ">=18",
"react-dom": ">=18"
}
},
"node_modules/react-router/node_modules/cookie": {
"version": "1.0.2",
"resolved": "http://94.130.170.209:4873/cookie/-/cookie-1.0.2.tgz",
"integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==",
"license": "MIT",
"engines": {
"node": ">=18"
}
},
"node_modules/react-scripts": { "node_modules/react-scripts": {
"version": "5.0.1", "version": "5.0.1",
"license": "MIT", "license": "MIT",
@@ -16033,6 +16091,12 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-cookie-parser": {
"version": "2.7.1",
"resolved": "http://94.130.170.209:4873/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz",
"integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==",
"license": "MIT"
},
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"license": "ISC" "license": "ISC"
@@ -17131,6 +17195,12 @@
"version": "1.14.1", "version": "1.14.1",
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/turbo-stream": {
"version": "2.4.0",
"resolved": "http://94.130.170.209:4873/turbo-stream/-/turbo-stream-2.4.0.tgz",
"integrity": "sha512-FHncC10WpBd2eOmGwpmQsWLDoK4cqsA/UT/GqNoaKOQnT8uzhtCbg3EoUDMvqpOSAI0S26mr0rkjzbOO6S3v1g==",
"license": "ISC"
},
"node_modules/type-check": { "node_modules/type-check": {
"version": "0.4.0", "version": "0.4.0",
"license": "MIT", "license": "MIT",
+1
View File
@@ -9,6 +9,7 @@
"react": "19.0.0", "react": "19.0.0",
"react-bootstrap": "2.10.7", "react-bootstrap": "2.10.7",
"react-dom": "19.0.0", "react-dom": "19.0.0",
"react-router-dom": "7.1.3",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"use-query-params": "1.2.3" "use-query-params": "1.2.3"
}, },
+5
View File
@@ -21,8 +21,13 @@
.nav-link-active { .nav-link-active {
color: white !important; color: white !important;
text-decoration: none;
padding: 0.5rem;
} }
.nav-link-inactive { .nav-link-inactive {
color: gray !important; color: gray !important;
text-decoration: none;
padding: 0.5rem;
} }
-2
View File
@@ -9,7 +9,6 @@ import React, { useEffect, useCallback } from 'react'
import './App.css' import './App.css'
import LoadScripts from './components/load-scripts' import LoadScripts from './components/load-scripts'
import AsyncLoad from './services/async-load' import AsyncLoad from './services/async-load'
import SelectServerButton from './components/app-body/servers/select-server-button'
import Footer from './components/footer' import Footer from './components/footer'
import NavMenu from './components/nav-menu' import NavMenu from './components/nav-menu'
import useAppState from './hooks/state' import useAppState from './hooks/state'
@@ -99,7 +98,6 @@ function App (props) {
? (<UninitializedView appData={appData} />) ? (<UninitializedView appData={appData} />)
: (<InitializedView menuState={appData.menuState} appData={appData} />) : (<InitializedView menuState={appData.menuState} appData={appData} />)
} }
<SelectServerButton appData={appData} />
</div> </div>
<Footer appData={appData} /> <Footer appData={appData} />
</div> </div>
+11 -22
View File
@@ -8,41 +8,30 @@
// Global npm libraries // Global npm libraries
import React from 'react' import React from 'react'
import { Route, Routes } from 'react-router-dom'
// Local libraries // Local libraries
import GetBalance from './balance' import GetBalance from './balance'
import Placeholder2 from './placeholder2' import Placeholder2 from './placeholder2'
import Placeholder3 from './placeholder3' import Placeholder3 from './placeholder3'
import ServerSelectView from './servers/select-server-view' import ServerSelectView from './servers/select-server-view'
import SelectServerButton from './servers/select-server-button'
function AppBody (props) { function AppBody (props) {
// Dependency injection through props // Dependency injection through props
const appData = props.appData const appData = props.appData
const menuState = props.menuState
// console.log('AppBody() menuState: ', menuState)
function chooseView (menuState) {
// console.log(`chooseView() menuState: ${menuState}`)
switch (menuState) {
case 0:
return (<GetBalance wallet={appData.wallet} />)
case 1:
return (<Placeholder2 />)
case 2:
return (<Placeholder3 />)
// Special Views
case 100:
return (<ServerSelectView appData={appData} />)
default:
return (<GetBalance wallet={appData.wallet} />)
}
}
return ( return (
<> <>
{chooseView(menuState)} <Routes>
<Route path='/' element={<GetBalance wallet={appData.wallet} />} />
<Route path='/balance' element={<GetBalance wallet={appData.wallet} />} />
<Route path='/placeholder2' element={<Placeholder2 />} />
<Route path='/placeholder3' element={<Placeholder3 />} />
<Route path='/servers' element={<ServerSelectView appData={appData} />} />
</Routes>
{/** Show in all paths except the servers view */}
{appData.currentPath !== '/servers' && <SelectServerButton linkTo='/servers' />}
</> </>
) )
} }
@@ -6,32 +6,39 @@
// Global npm libraries // Global npm libraries
import React from 'react' import React from 'react'
import { Container, Row, Col, Button } from 'react-bootstrap' import { Container, Row, Col, Button } from 'react-bootstrap'
import { useNavigate } from 'react-router-dom'
const ServerSelect = (props) => { const ServerSelect = (props) => {
const { appData } = props const { linkTo } = props
// Use the navigate function to navigate to the servers view
const navigate = useNavigate()
// This is a click handler for the server select button. It brings up the // This is a click handler for the server select button. It brings up the
// server selection View. // server selection View.
const handleServerSelect = () => { const handleServerSelect = () => {
console.log('This function should navigate to the server selection view.') console.log('This function should navigate to the server selection view.')
appData.setMenuState(100) navigate(linkTo)
} }
return ( return (
<Container> <Container>
<hr /> <>
<Row> <hr />
<Col style={{ textAlign: 'center', padding: '25px' }}> <Row>
<br /> <Col style={{ textAlign: 'center', padding: '25px' }}>
<h5> <br />
Having trouble loading? Try selecting a different back-end server. <h5>
</h5> Having trouble loading? Try selecting a different back-end server.
<Button variant='warning' onClick={handleServerSelect}> </h5>
Select a different back end server <Button variant='warning' onClick={handleServerSelect}>
</Button> Select a different back end server
<br /> </Button>
</Col> <br />
</Row> </Col>
</Row>
</>
</Container> </Container>
) )
} }
+32 -22
View File
@@ -6,20 +6,29 @@
*/ */
// Global npm libraries // Global npm libraries
import React from 'react' import React, { useState } from 'react'
import { Nav, Navbar, Image } from 'react-bootstrap' import { Nav, Navbar, Image } from 'react-bootstrap' // Used for Navbar Style and Layouts .
import { NavLink } from 'react-router-dom' // Used to navigate between routes
// Assets
import Logo from './psf-logo.png' import Logo from './psf-logo.png'
function NavMenu (props) { function NavMenu (props) {
const selectedMenu = props.appData.menuState // Get the current path
const handleClickEvent = (menuItem) => { const { currentPath } = props.appData
// Pass the selected menu item up to the parent component.
props.appData.setMenuState(menuItem) // Navbar state
const [expanded, setExpanded] = useState(false)
// Handle click event
const handleClickEvent = () => {
// Collapse the navbar
setExpanded(false)
} }
return ( return (
<> <>
<Navbar collapseOnSelect expand='xxxl' bg='dark' variant='dark' style={{ paddingRight: '20px' }}> <Navbar expanded={expanded} onToggle={setExpanded} expand='xxxl' bg='dark' variant='dark' style={{ paddingRight: '20px' }}>
<Navbar.Brand href='#home' style={{ paddingLeft: '20px' }}> <Navbar.Brand href='#home' style={{ paddingLeft: '20px' }}>
<Image src={Logo} thumbnail width='50' />{' '} <Image src={Logo} thumbnail width='50' />{' '}
PSF Web3 Demo PSF Web3 Demo
@@ -28,27 +37,28 @@ function NavMenu (props) {
<Navbar.Toggle aria-controls='responsive-navbar-nav' /> <Navbar.Toggle aria-controls='responsive-navbar-nav' />
<Navbar.Collapse id='responsive-navbar-nav'> <Navbar.Collapse id='responsive-navbar-nav'>
<Nav className='mr-auto'> <Nav className='mr-auto'>
<Nav.Link <NavLink
className={selectedMenu === 0 ? 'nav-link-active' : 'nav-link-inactive'} className={(currentPath === '/balance' || currentPath === '/') ? 'nav-link-active' : 'nav-link-inactive'}
href='#' to='/balance'
onClick={(e) => handleClickEvent(0)} onClick={handleClickEvent}
> >
Check Balance Check Balance
</Nav.Link> </NavLink>
<Nav.Link <NavLink
className={selectedMenu === 1 ? 'nav-link-active' : 'nav-link-inactive'} className={currentPath === '/placeholder2' ? 'nav-link-active' : 'nav-link-inactive'}
href='#' to='/placeholder2'
onClick={(e) => handleClickEvent(1)} onClick={handleClickEvent}
> >
Placeholder2 Placeholder2
</Nav.Link> </NavLink>
<Nav.Link <NavLink
className={selectedMenu === 2 ? 'nav-link-active' : 'nav-link-inactive'} className={currentPath === '/placeholder3' ? 'nav-link-active' : 'nav-link-inactive'}
href='#' to='/placeholder3'
onClick={(e) => handleClickEvent(2)} onClick={handleClickEvent}
> >
Placeholder 3 Placeholder 3
</Nav.Link> </NavLink>
</Nav> </Nav>
</Navbar.Collapse> </Navbar.Collapse>
</Navbar> </Navbar>
-1
View File
@@ -4,7 +4,6 @@
import React from 'react' import React from 'react'
import WaitingModal from './waiting-modal' import WaitingModal from './waiting-modal'
import AppBody from './app-body' import AppBody from './app-body'
// This is rendered *before* the BCH wallet is initialized. // This is rendered *before* the BCH wallet is initialized.
export function UninitializedView (props = {}) { export function UninitializedView (props = {}) {
// console.log('UninitializedView props: ', props) // console.log('UninitializedView props: ', props)
+6 -2
View File
@@ -1,7 +1,9 @@
import { useState } from 'react' import { useState } from 'react'
import { useQueryParam, StringParam } from 'use-query-params' import { useQueryParam, StringParam } from 'use-query-params'
import { useLocation } from 'react-router-dom'
function useAppState () { function useAppState () {
const location = useLocation()
// Get the CashStack URL from query parameter or use default // Get the CashStack URL from query parameter or use default
let [restURL] = useQueryParam('restURL', StringParam) let [restURL] = useQueryParam('restURL', StringParam)
if (!restURL) restURL = 'https://free-bch.fullstack.cash' if (!restURL) restURL = 'https://free-bch.fullstack.cash'
@@ -44,7 +46,9 @@ function useAppState () {
hideSpinner, hideSpinner,
setHideSpinner, setHideSpinner,
denyClose, denyClose,
setDenyClose setDenyClose,
currentPath: location.pathname
} }
} }
+5 -1
View File
@@ -8,12 +8,16 @@ import { QueryParamProvider } from 'use-query-params'
// Importing the Bootstrap CSS // Importing the Bootstrap CSS
import 'bootstrap/dist/css/bootstrap.min.css' import 'bootstrap/dist/css/bootstrap.min.css'
import { BrowserRouter } from 'react-router-dom'
const root = ReactDOM.createRoot(document.getElementById('root')) const root = ReactDOM.createRoot(document.getElementById('root'))
root.render( root.render(
<QueryParamProvider> <QueryParamProvider>
<App /> {/* <BrowserRouter> should be wrap all the components that use react-router-dom */}
<BrowserRouter>
<App />
</BrowserRouter>
</QueryParamProvider> </QueryParamProvider>
) )