UNPKG

@foreverrbum/ethsign

Version:

This package will allow you to electronically sign documents within your application

447 lines (419 loc) 14.9 kB
import React, { useState, useEffect } from 'react'; import '../styles/main.css'; import '../styles/index.scss'; import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom'; import ReactNotification from 'react-notifications-component'; import 'react-notifications-component/dist/theme.css'; import 'animate.css/animate.compat.css'; import Landing from './Landing'; import Navbar from './Navbar'; import LogIn from './LogIn'; import Dashboard from './Dashboard'; import { getWeb3Credentials } from '../helpers/dashboard'; import {connectNetwork, resetContractAndProvider} from '../helpers/wallets/wallets'; import LoadingScreen from './LoadingScreen'; import NewRevision from './NewRevision'; import SignIn from './SignIn'; import { getBrowserLanguage, loadData } from '../helpers/language'; import { IntlProvider} from 'react-intl'; import Alert from './Alert'; import { chains, getChain } from '../helpers/chains'; import { useIntl } from 'react-intl'; import {useStateWithSessionStorage} from '../helpers/sessionStorage'; import DataVis from './DataVis'; import Footer from './Footer'; import Feedback from './feedback/Feedback'; import * as Sentry from '@sentry/react'; import { FallbackComponent } from './FallbackComponent'; import { ManageProfile } from './email-notification/manage-profile'; import icon from '../assets/contract_alert_announcement.svg'; import { getChainIndexStatus } from '../helpers/graphql.js'; export const App = (props) => { const {handleLanguage, language} = props; const [ethAccount, handleEthAccount] = useState(null) const [ethAlias, handleEthAlias] = useState(null); const [ethAvatar, handleEthAvatar] = useState(null); const [walletName, handleWalletName] = useStateWithSessionStorage('walletName', ''); const [fortmaticPreferredNetwork, handleFortmaticPreferredNetwork] = useStateWithSessionStorage('fortmaticNetworkId', 56) const [torusPreferredNetwork, handleTorusPreferredNetwork] = useStateWithSessionStorage('torusNetworkId', 1) const [networkId, handleNetworkId] = useState('N/A') const [contract, handleContract] = useState(null) const [web3, handleWeb3] = useState(null) const [fm, handleFm] = useState(null); const [torus, handleTorus] = useState(null); const [web3Case, handleWeb3Case] = useStateWithSessionStorage('web3Case', null); const [activePage, handleActivePage] = useState('home'); const [loaded, handleLoaded] = useState(null); const [ensEnabled, handleEnsEnabled] = useState(false); const [networkChanged, handleNetworkChanged] = useState(false); const [networkError, handleNetworkError] = useState(false); const [generalError, handleGeneralError] = useState(false); const [accountError, handleAccountError] = useState(false); const [alertNetworkLoading, handleAlertNetworkLoading] = useState(false); const [shouldShowAnnouncement, handleShouldShowAnnouncement] = useState(false); const [hideAnnouncement, handleHideAnnouncement] = useState(false); const [blocksBehind, handleBlocksBehind] = useState(null); // email notification popup const [open, handleOpen] = useState(false); const { formatMessage } = useIntl(); useEffect(() => { (async () => { if (web3Case != null) { await getWeb3Credentials(web3Case, web3Case === 4 ? torusPreferredNetwork : fortmaticPreferredNetwork).then((result) => { if (!result.ethAccount) { handleActivePage(null); handleWeb3Case(null); location.reload(); return; } handleEthAccount(result.ethAccount?.toLowerCase()); handleNetworkId(result.networkId); handleWeb3(result.web3); handleContract(result.contract); handleFm(result.fm); handleTorus(result.torus); }) .catch(e => { console.log(e); handleGeneralError(true); }); } handleLoaded(true); })(); }, []); useEffect(() => { let accListener = (accounts) => { if((walletName !== 'Metamask' && web3Case !== 2) && (walletName !== 'Torus' && web3Case !== 4)) { return; } if(!accounts[0]) { handleEthAccount(null); handleAccountError(true); } else { handleAccountError(false); handleEthAccount(accounts[0].toLowerCase()); } } let netListener = async (network) => { try { if(web3Case == 4 && torus) { if(network == 'loading') { return; } if(!getChain(parseInt(network)).torusSupport) { throw new Error('Unsupported Torus Network with ID: ' + network) } else { handleTorusPreferredNetwork(parseInt(network)); } } if(!getChain(parseInt(network))) { throw new Error('Unsupported Network with ID: ' + network); } handleNetworkId(parseInt(network)); await resetContractAndProvider(network, handleWeb3, handleContract, web3Case == 4 ? torus : null); handleNetworkChanged(true); handleNetworkError(false); } catch(err) { // storeNotif("Network Changed", "A network switch to an unsupported network has been detected. Please switch to a supported network and log in again.", "danger"); handleNetworkId(null); if(web3Case == null) { handleNetworkChanged(true); } else if(web3Case == 2 || web3Case == 4) { if(window.location.hash === '#/signin') { handleNetworkChanged(true); } handleNetworkError(true); } // Redirect to /login and log the user out } } if(web3Case == 4 && torus) { torus.ethereum.on('accountsChanged', accListener); torus.ethereum.on('networkChanged', netListener); } else if (window.ethereum !== null && window.ethereum !== undefined) { try { window.ethereum.on('accountsChanged', accListener); window.ethereum.on('networkChanged', netListener); } catch(err) { console.log("Error adding network change listener: " + err); Sentry.captureException(err); } } return () => { if(web3Case == 4 && torus) { torus.ethereum.removeListener('accountsChanged', accListener); torus.ethereum.removeListener('networkChanged', netListener); } else if (window.ethereum !== null && window.ethereum !== undefined) { try { window.ethereum.removeListener('accountsChanged', accListener); window.ethereum.removeListener('networkChanged', netListener); } catch(err) { console.log("Error removing network change listener: " + err); Sentry.captureException(err); } } }; }, [web3Case, torus]); useEffect(() => { (async () => { if (web3Case != null && ethAccount != null && web3 != null) { try{ let alias = await web3.lookupAddress(ethAccount); if(alias) { handleEthAlias(alias); const resolver = await web3.getResolver(alias); const avatar = await resolver.getText("avatar"); handleEthAvatar(avatar); } else { handleEthAvatar(null); handleEthAlias(null); } handleEnsEnabled(true); }catch(err){ handleEnsEnabled(false); handleEthAvatar(null); handleEthAlias(null); } } })(); }, [ethAccount, web3, web3Case]); const logout = async () => { handleActivePage(null); handleWeb3Case(null) handleWeb3(null) handleEthAccount(null) handleContract(null); if (fm!=null){ fm.user.logout; handleFm(null); }else if(torus != null){ await torus.logout(); handleTorus(null) } } useEffect(() => { (async () => { if(!networkId || networkId == 'N/A') { return; } let blocksBehind = await getChainIndexStatus(networkId); handleBlocksBehind(blocksBehind); if(blocksBehind > 5) { handleShouldShowAnnouncement(true); } else { handleShouldShowAnnouncement(false); } })(); }, [networkId]); const changeNetwork = (chain) => { connectNetwork(chain, web3, handleWeb3, handleContract, (chain) => { if(torus !== null) { handleNetworkId(chain.chainId); } }, walletName, handleFm, torus, handleTorus, (finished) => { handleNetworkError(!finished); handleAlertNetworkLoading(false); if(finished && fm !== null) { handleFortmaticPreferredNetwork(chain.chainId); } if(finished && torus !== null) { handleTorusPreferredNetwork(chain.chainId); handleNetworkChanged(true); } } ); } const alertChangeNetwork = () => { handleAlertNetworkLoading(true); const chainId = document.getElementById("network-select").value; for(let chain of chains) { if(chain.chainId == chainId) { console.log(chain); changeNetwork(chain); } } } return ( <> <Router> <div className={`flex flex-col relative min-h-screen ${window.location.hash === '#/' && web3Case == null ? " bg-landing" : 'none'}`}> <Navbar announcementShowing={shouldShowAnnouncement && !hideAnnouncement} icon={icon} numberOfBlocksBehind={blocksBehind} handleHideAnnouncement={handleHideAnnouncement} fm={fm} torus={torus} ethAvatar={ethAvatar} ethAlias={ethAlias} provider={web3} changeNetwork={(chain)=>changeNetwork(chain)} appLogout={logout} loggedIn={web3Case !== null && web3 !== null} activePage={activePage} handleActivePage={handleActivePage} handleWeb3Case={handleWeb3Case} ethAccount={ethAccount} handleLanguage={handleLanguage} language={language} handleOpen={handleOpen}/> <Switch> { loaded? <> <Route exact path="/"> { web3Case == null? <Landing handleActivePage={handleActivePage} handleLanguage={handleLanguage} language={language} /> : <Redirect to="/home" /> } </Route> <Route exact path="/verify"> <Landing handleActivePage={handleActivePage} handleLanguage={handleLanguage} language={language} /> </Route> <Route exact path="/signin"> { web3Case == null? <SignIn handleActivePage={handleActivePage} provider={web3} handleProvider={handleWeb3} handleFm={handleFm} torus={torus} handleTorus={handleTorus} networkChanged={networkChanged} handleNetworkChanged={handleNetworkChanged} walletName={walletName} handleWalletName={handleWalletName} fortmaticPreferredNetwork={fortmaticPreferredNetwork} handleFortmaticPreferredNetwork={handleFortmaticPreferredNetwork} torusPreferredNetwork={torusPreferredNetwork} handleTorusPreferredNetwork={handleTorusPreferredNetwork} /> : <Redirect to="/home" /> } </Route> <Route exact path="/login"> { web3Case == null? <LogIn provider={web3} handleEthAccount={handleEthAccount} handleNetworkId={handleNetworkId} handleContract={handleContract} handleWeb3={handleWeb3} handleWeb3Case={handleWeb3Case} handleActivePage={handleActivePage} handleFm={handleFm} handleTorus={handleTorus} /> : <Redirect to="/home" /> } </Route> <Route exact path="/revision"> { web3Case != null? <NewRevision ethAccount={ethAccount} handleActivePage={handleActivePage} web3={web3} fm={fm} contract={contract} appLogout={logout} handleOpen={handleOpen} /> : <Redirect to="/home" /> } </Route> <Route exact path="/manage-profile"> { web3Case != null ? <ManageProfile web3={web3} fm={fm} torus={torus} changeNetwork={changeNetwork} handleOpen={handleOpen} handleActivePage={handleActivePage} walletName={walletName} /> : <Redirect to="/home" /> } </Route> <Route path="/datavis"> <DataVis handleActivePage={handleActivePage} /> </Route> <Dashboard language={language} fm={fm} torus={torus} ethAlias={ethAlias} ethAvatar={ethAvatar} networkId={networkId} networkChanged={networkChanged} handleNetworkChanged={handleNetworkChanged} changeNetwork={(chain)=>changeNetwork(chain)} handleActivePage={handleActivePage} web3Case={web3Case} web3={web3} contract={contract} ethAccount={ethAccount} ensEnabled={ensEnabled} appLogout={logout} open={open} handleOpen={handleOpen}/> </> : <LoadingScreen/> } </Switch> <Footer handleLanguage={handleLanguage} language={language} activePage={activePage}/> {networkError && <Alert loading={alertNetworkLoading} message={formatMessage({id: 'YOU_CURRENT_NETWORK_SELECTION_IS_NOT_SUPPORT'})} closeButtonText={formatMessage({id: 'LOG_OUT'})} closeCallback={() => logout()} closeOnOutsideClick={false} okButtonText={formatMessage({id: 'OK'})} okCallback={() => alertChangeNetwork()} customComponent={ <select id="network-select" name="network" className="select-none bg-transparent h-8 focus:outline-none text-gray-70 rounded-md px-3 border border-gray-70"> {chains.map((chain, key)=>{ if(web3Case == 4 && !chain.torusSupport) { return null; } return ( <option key={key} value={chain.chainId}>{chain.name}</option> ) })} </select> } /> } {generalError && <Alert message={formatMessage({id: 'THERE_HAS_BEEN_A_PROBLEM_FETCHING_DATA'})} type={1} closeOnOutsideClick={false} closeButtonText={formatMessage({id: 'LOG_OUT'})} closeCallback={() => { handleActivePage(null); handleWeb3Case(null); history.pushState(null, null, '/'); }} /> } {accountError && <Alert type={1} message={formatMessage({id: 'NO_ACCOUNT_DETECTED'})} closeButtonText={formatMessage({id: 'LOG_OUT'})} closeOnOutsideClick={false} closeCallback={() => { handleActivePage(null); handleWeb3Case(null); history.pushState(null, null, '/'); }} /> } </div> <Feedback activePage={activePage}/> </Router> </> ); } export const AppContainer = (props) => { const {Application, lang} = props; const [language, handleLanguage] = useStateWithSessionStorage('language', ()=>getBrowserLanguage() ); const [localData, handleLocalData] = useState(null); useEffect(()=>{ handleLocalData(loadData(language)); },[language]); useEffect(()=>{ if(lang){ handleLanguage(lang) } },[lang]); return ( <IntlProvider locale={language} defaultLocale="en" messages={localData} contract='hello' > <Sentry.ErrorBoundary fallback={FallbackComponent} showDialog={false}> <ReactNotification /> <Application handleLanguage={handleLanguage} language={language}/> </Sentry.ErrorBoundary> </IntlProvider> ) } export default {AppContainer, App};