diff --git a/src/components/App/AppRouter.tsx b/src/components/App/AppRouter.tsx index 5ecae204..8dfe94ae 100644 --- a/src/components/App/AppRouter.tsx +++ b/src/components/App/AppRouter.tsx @@ -42,6 +42,7 @@ import Dispenser from "../Modules/Dispenser/Dispenser"; import NodeStatus from "../Modules/NodeStatus/NodeStatus"; import ArcHome from "../Modules/ArcPortal/Home/ArcHome"; import DevWallets from "../Modules/DevWallets/DevWallets/DevWallets"; +import SetupConfig from "../Modules/SetupConfig/setupConfig"; function AppRouter(): JSX.Element { @@ -107,6 +108,7 @@ function AppRouter(): JSX.Element { }> }> }> + }> }/> diff --git a/src/components/Modules/SetupConfig/setupConfig.scss b/src/components/Modules/SetupConfig/setupConfig.scss new file mode 100644 index 00000000..55395712 --- /dev/null +++ b/src/components/Modules/SetupConfig/setupConfig.scss @@ -0,0 +1,13 @@ +@import 'src/assets/colors'; + +.setup-config-wrapper { + .setup-config-container { + .setup-config-header { + margin-bottom: 15px; + padding-bottom: 20px; + font-size: 20px; + font-weight: bold; + border-bottom: 1px solid $color-grey-light; + } + } +} \ No newline at end of file diff --git a/src/components/Modules/SetupConfig/setupConfig.tsx b/src/components/Modules/SetupConfig/setupConfig.tsx new file mode 100644 index 00000000..73a6bf25 --- /dev/null +++ b/src/components/Modules/SetupConfig/setupConfig.tsx @@ -0,0 +1,273 @@ +import './setupConfig.scss'; +import {Button, FormLabel, Grid, InputBase, InputBaseProps, styled} from "@mui/material"; +import React, {useEffect, useState} from "react"; +import {theme} from "../../../theme"; +import {useSearchParams} from "react-router-dom"; +import {isNumber} from "../../../utils/common"; +import {showSnack} from "../../../redux/common/actions/snackbar"; +import {NodeConnectionParams} from "../../../packages/core-sdk/types"; +import {hideLoader, showLoader} from "../../../redux/common/actions/loader"; +import {Network} from "../../../packages/core-sdk/network"; +import {isBrave} from "../../../packages/core-sdk/utils"; +import {useDispatch} from "react-redux"; + + +const ShadedInput = styled(InputBase)(({ theme }) => { + return { + padding: 5, + paddingLeft: 10, + marginTop: 5, + border: '1px solid ' + theme.palette.grey[200] + }; +}); + +const formLabelStyle = { + marginLeft: '5px', + fontSize: '14px', + fontWeight: 'bold', + color: theme.palette.grey[600] +}; + +interface SetupConfigState{ + algodUrl: string, + algodPort: string, + algodToken: string, + indexerUrl: string, + indexerPort: string, + indexerToken: string +} + +const initialState: SetupConfigState = { + algodPort: "", + algodToken: "", + algodUrl: "", + indexerPort: "", + indexerToken: "", + indexerUrl: "" +}; + +function SetupConfig(): JSX.Element { + + const [searchParams] = useSearchParams(); + const dispatch = useDispatch(); + + + const [ + {algodToken, algodUrl, indexerToken, indexerUrl, indexerPort, algodPort}, + setState + ] = useState(initialState); + + useEffect(() => { + const algodUrl = searchParams.get("algod_url") || ''; + const algodPort = searchParams.get("algod_port") || ''; + const algodToken = searchParams.get("algod_token") || ''; + + const indexerUrl = searchParams.get("indexer_url") || ''; + const indexerPort = searchParams.get("indexer_port") || ''; + const indexerToken = searchParams.get("indexer_token") || ''; + + setState(prevState => ({...prevState, algodUrl, algodPort, algodToken, indexerUrl, indexerPort, indexerToken})); + + saveConfig(algodUrl, algodPort, algodToken, indexerUrl, indexerPort, indexerToken); + }, []); + + + + async function saveConfig(algodUrl: string, algodPort: string, algodToken: string, indexerUrl: string, indexerPort: string, indexerToken: string) { + let message = ''; + let failed = false; + + if (!algodUrl) { + message = 'Invalid Algod url'; + } else if (algodPort && !isNumber(algodPort)) { + message = 'Invalid Algod port'; + } else if (!indexerUrl) { + message = 'Invalid Indexer url'; + } else if (indexerPort && !isNumber(indexerPort)) { + message = 'Invalid Indexer port'; + } + + if (message) { + dispatch(showSnack({ + severity: 'error', + message + })); + return; + } + + const connectionParams: NodeConnectionParams = { + id: 'test', + label: 'Test', + algod: { + url: algodUrl, + port: algodPort, + token: algodToken + }, + indexer: { + url: indexerUrl, + port: indexerPort, + token: indexerToken + } + } + + try { + dispatch(showLoader('Connecting to node ...')); + const network = new Network(connectionParams); + const client = network.getClient(); + await client.status().do(); + dispatch(hideLoader()); + } catch (e) { + dispatch(hideLoader()); + failed = true; + message = 'Node connection failed - Invalid Algod configuration.'; + } + + if (!failed) { + try { + dispatch(showLoader('Connecting to node ...')); + const network = new Network(connectionParams); + const indexer = network.getIndexer(); + await indexer.makeHealthCheck().do(); + dispatch(hideLoader()); + } catch (e) { + dispatch(hideLoader()); + failed = true; + message = 'Node connection failed - Invalid Indexer configuration.'; + } + } + + + if (failed) { + if (isBrave()) { + message += ' If you are using Brave browser, localhost connections are shielded by default. Please turnoff shields and try again. Click here to know more.'; + } + + dispatch(showSnack({ + severity: 'error', + message + })); + + return; + } + dispatch(showLoader('Saving node configuration ...')); + localStorage.setItem('algodUrl', algodUrl); + localStorage.setItem('algodPort', algodPort || ''); + localStorage.setItem('algodToken', algodToken || ''); + localStorage.setItem('indexerUrl', indexerUrl); + localStorage.setItem('indexerPort', indexerPort || ''); + localStorage.setItem('indexerToken', indexerToken || ''); + dispatch(hideLoader()); + + const redirect = searchParams.get("redirect") || '/explorer'; + window.open(redirect,"_self"); + } + + return ( +
+
+
+
+ Setup Config +
+
+ +
+ + + + + Algod url + { + setState(prevState => ({...prevState, algodUrl: ev.target.value})); + }} + fullWidth/> + + + Algod port + { + setState(prevState => ({...prevState, algodPort: ev.target.value})); + }} + fullWidth/> + + + Algod token + { + setState(prevState => ({...prevState, algodToken: ev.target.value})); + }} + fullWidth/> + + + + + + + + Indexer url + { + setState(prevState => ({...prevState, indexerUrl: ev.target.value})); + }} + fullWidth/> + + + Indexer port + { + setState(prevState => ({...prevState, indexerPort: ev.target.value})); + }} + fullWidth/> + + + Indexer token + { + setState(prevState => ({...prevState, indexerToken: ev.target.value})); + }} + fullWidth/> + + +
+ +
+ +
+
+
+
+ + +
+
+
+ ); +} + +export default SetupConfig;