Add network status button and url param parsing

This commit is contained in:
Justin Starry
2020-03-14 00:02:20 +08:00
committed by Michael Vines
parent 674ee37ee3
commit 95001aa8ee
5 changed files with 759 additions and 4 deletions

View File

@@ -1,4 +1,6 @@
import React from "react";
import { NetworkProvider } from "./providers/network";
import NetworkStatusButton from "./components/networkStatusButton";
function App() {
return (
@@ -11,6 +13,11 @@ function App() {
<h6 className="header-pretitle">Beta</h6>
<h1 className="header-title">Solana Explorer</h1>
</div>
<div className="col-auto">
<NetworkProvider>
<NetworkStatusButton />
</NetworkProvider>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,36 @@
import React from "react";
import { useNetwork, NetworkStatus } from "../providers/network";
function NetworkStatusButton() {
const { status, url } = useNetwork();
switch (status) {
case NetworkStatus.Connected:
return (
<a href="#networkModal" className="btn btn-primary lift">
{url}
</a>
);
case NetworkStatus.Connecting:
return (
<a href="#networkModal" className="btn btn-warning lift">
{"Connecting "}
<span
className="spinner-grow spinner-grow-sm text-dark"
role="status"
aria-hidden="true"
></span>
</a>
);
case NetworkStatus.Failure:
return (
<a href="#networkModal" className="btn btn-danger lift">
Disconnected
</a>
);
}
}
export default NetworkStatusButton;

View File

@@ -0,0 +1,124 @@
import React from "react";
import { testnetChannelEndpoint, Connection } from "@solana/web3.js";
enum NetworkStatus {
Connected,
Connecting,
Failure
}
interface Connecting {
status: NetworkStatus.Connecting;
url: string;
}
interface Connected {
status: NetworkStatus.Connected;
}
interface Failure {
status: NetworkStatus.Failure;
}
type Action = Connected | Connecting | Failure;
type Dispatch = (action: Action) => void;
interface State {
url: string;
status: NetworkStatus;
}
const StateContext = React.createContext<State | undefined>(undefined);
const DispatchContext = React.createContext<Dispatch | undefined>(undefined);
function networkReducer(state: State, action: Action): State {
switch (action.status) {
case NetworkStatus.Connected:
case NetworkStatus.Failure: {
return Object.assign({}, state, { status: action.status });
}
case NetworkStatus.Connecting: {
return { url: action.url, status: action.status };
}
}
}
function findGetParameter(parameterName: string): string | null {
let result = null,
tmp = [];
window.location.search
.substr(1)
.split("&")
.forEach(function(item) {
tmp = item.split("=");
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
});
return result;
}
function init(url: string): State {
const networkUrlParam = findGetParameter("networkUrl");
return {
url: networkUrlParam || url,
status: NetworkStatus.Connecting
};
}
const DEFAULT_URL = testnetChannelEndpoint("stable");
type NetworkProviderProps = { children: React.ReactNode };
function NetworkProvider({ children }: NetworkProviderProps) {
const [state, dispatch] = React.useReducer(networkReducer, DEFAULT_URL, init);
React.useEffect(() => {
// Connect to network immediately
updateNetwork(dispatch, state.url);
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<StateContext.Provider value={state}>
<DispatchContext.Provider value={dispatch}>
{children}
</DispatchContext.Provider>
</StateContext.Provider>
);
}
async function updateNetwork(dispatch: Dispatch, newUrl: string) {
dispatch({
status: NetworkStatus.Connecting,
url: newUrl
});
try {
const connection = new Connection(newUrl);
await connection.getRecentBlockhash();
dispatch({ status: NetworkStatus.Connected });
} catch (error) {
console.error("Failed to update network", error);
dispatch({ status: NetworkStatus.Failure });
}
}
function useNetwork() {
const context = React.useContext(StateContext);
if (!context) {
throw new Error(`useNetwork must be used within a NetworkProvider`);
}
return context;
}
function useNetworkDispatch() {
const context = React.useContext(DispatchContext);
if (!context) {
throw new Error(`useNetworkDispatch must be used within a NetworkProvider`);
}
return context;
}
export {
NetworkProvider,
useNetwork,
useNetworkDispatch,
updateNetwork,
NetworkStatus
};