From c038085b87d7f0015dbaa3a9bf1802d5d3764ee5 Mon Sep 17 00:00:00 2001 From: Cody Bender Date: Fri, 9 Aug 2024 16:47:21 -0400 Subject: [PATCH 01/11] style: first pass with dark mui theme --- src/App.tsx | 140 +++++++++++++++++------ src/components/Container.tsx | 21 ++++ src/components/Header.tsx | 98 ++++++++++++---- src/components/Layout.tsx | 28 +++++ src/components/TermsAndConditionsBox.tsx | 30 ++--- src/pages/LandingPage.tsx | 55 ++++----- 6 files changed, 275 insertions(+), 97 deletions(-) create mode 100644 src/components/Container.tsx create mode 100644 src/components/Layout.tsx diff --git a/src/App.tsx b/src/App.tsx index 3bd3147..2ac65b1 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,44 +16,116 @@ import Email from "./pages/Email"; import Thanks from "./pages/Thanks"; import Validator from "./pages/Validator"; import ValidatorSuccess from "./pages/ValidatorSuccess"; +import { createTheme, Box, ThemeProvider } from "@mui/material"; + +const darkTheme = createTheme({ + components: { + MuiAccordion: { + defaultProps: { + sx: { + border: "1px solid #48474F", + borderBottomRightRadius: 3, + borderBottomLeftRadius: 3, + }, + }, + }, + MuiButton: { + defaultProps: { + color: "primary", + sx: { + fontFamily: `DM Mono, monospace`, + fontWeight: 400, + }, + }, + }, + MuiLink: { + defaultProps: { + color: "text.primary", + fontSize: "14px", + }, + }, + MuiTypography: { + defaultProps: { + color: "text.primary", + fontWeight: 400, + }, + }, + MuiPaper: { + defaultProps: { + sx: { + backgroundImage: "none", + }, + }, + }, + }, + palette: { + mode: "dark", + primary: { + main: "#0000F4", + }, + secondary: { + main: "#A2A2FF", + }, + error: { + main: "#B20710", + }, + background: { + default: "#0F0F0F", + paper: "#18181A", + }, + text: { + primary: "#FBFBFB", + }, + info: { + main: "#FBFBFB", + }, + }, +}); function App() { return ( -
- - - } /> - } /> - } /> - } /> - } /> - }> - } /> - } - /> - } - /> - } - /> - } - /> - } - /> - - } /> - - + + +
+ + + } /> + } /> + } /> + } /> + } /> + }> + } + /> + } + /> + } /> + } + /> + } /> + } + /> + + } /> + + + + ); } diff --git a/src/components/Container.tsx b/src/components/Container.tsx new file mode 100644 index 0000000..76c737b --- /dev/null +++ b/src/components/Container.tsx @@ -0,0 +1,21 @@ +import { Box, BoxProps } from "@mui/material"; +import React, { PropsWithChildren } from "react"; + +export const Container: React.FC< + PropsWithChildren<{ boxProps?: BoxProps }> +> = ({ children, boxProps = {} }) => ( + + {children} + +); diff --git a/src/components/Header.tsx b/src/components/Header.tsx index c1bd679..d92fdba 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,30 +1,88 @@ -import React from 'react'; -import { Link, useLocation } from 'react-router-dom'; +import React from "react"; +import { Link, useLocation } from "react-router-dom"; -import { AppBar, Toolbar, Avatar, Box, IconButton } from '@mui/material'; +import { + AppBar, + Toolbar, + SvgIcon, + Stack, + Divider, + Typography, +} from "@mui/material"; const Header: React.FC = () => { const location = useLocation(); return ( - + - - - - - Testnet Onboarding - - - + + + + + + + + + + + + + + + + + Testnet Onboarding + ); diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx new file mode 100644 index 0000000..d3b1665 --- /dev/null +++ b/src/components/Layout.tsx @@ -0,0 +1,28 @@ +import { Button, Typography } from "@mui/material"; +import React, { PropsWithChildren } from "react"; +import { Container } from "./Container"; +import { ArrowBack } from "@mui/icons-material"; +import { useNavigate } from "react-router-dom"; + +export const Layout: React.FC< + PropsWithChildren<{ title: string; backLinkTitle?: string }> +> = ({ children, title, backLinkTitle = "Home" }) => { + const navigate = useNavigate(); + + return ( + + + + {title} + + {children} + + ); +}; diff --git a/src/components/TermsAndConditionsBox.tsx b/src/components/TermsAndConditionsBox.tsx index ccc3a3c..6fa0433 100644 --- a/src/components/TermsAndConditionsBox.tsx +++ b/src/components/TermsAndConditionsBox.tsx @@ -1,43 +1,47 @@ -import React, { useState } from 'react'; -import { Document, Page, pdfjs } from 'react-pdf'; +import React, { useState } from "react"; +import { Document, Page, pdfjs } from "react-pdf"; -import { Typography } from '@mui/material'; +import { Typography } from "@mui/material"; // https://github.com/wojtekmaj/react-pdf?tab=readme-ov-file#copy-worker-to-public-directory -pdfjs.GlobalWorkerOptions.workerSrc = process.env.PUBLIC_URL + '/pdf.worker.min.mjs'; +pdfjs.GlobalWorkerOptions.workerSrc = + process.env.PUBLIC_URL + "/pdf.worker.min.mjs"; interface TermsAndConditionsBoxProps { height: string; onLoad?: () => void; } -const TermsAndConditionsBox = ({ height, onLoad }: TermsAndConditionsBoxProps ) => { +const TermsAndConditionsBox = ({ + height, + onLoad, +}: TermsAndConditionsBoxProps) => { const [numPages, setNumPages] = useState(); function onDocumentLoadSuccess({ numPages }: { numPages: number }): void { setNumPages(numPages); - if (onLoad){ + if (onLoad) { onLoad(); - }; + } } return ( <> - + Terms and Conditions
{Array.apply(null, Array(numPages)) diff --git a/src/pages/LandingPage.tsx b/src/pages/LandingPage.tsx index 9fbfd7a..45109de 100644 --- a/src/pages/LandingPage.tsx +++ b/src/pages/LandingPage.tsx @@ -1,9 +1,10 @@ -import React, { useState } from 'react'; -import { useNavigate } from 'react-router-dom'; +import React, { useState } from "react"; +import { useNavigate } from "react-router-dom"; -import { Button, Box, Typography } from '@mui/material'; +import { Button, Box } from "@mui/material"; -import TermsAndConditionsBox from '../components/TermsAndConditionsBox'; +import TermsAndConditionsBox from "../components/TermsAndConditionsBox"; +import { Container } from "../components/Container"; const LandingPage = () => { const navigate = useNavigate(); @@ -11,43 +12,37 @@ const LandingPage = () => { const [isDisabled, setIsDisabled] = useState(true); const handleAccept = () => { - navigate('/verify-email'); + navigate("/verify-email"); }; return ( - <> - + { + setIsDisabled(false); }} - padding={5} - > - - Welcome to the LORO Testnet Onboarding App. The detailed instructions for completing this first step are found in the{' '} - LORO testnet repo. - Once your onboarding transaction has been submitted, await the completion of stage0. The genesis.json file and peer nodes will then be - published in the aforementioned repository for validators to begin stage1. Once enough validators are online and the Laconic chain is running, - those same validators can complete their service provider setup. Once service providers are live, app publishers can start deploying webapps to individual service providers. - - - {setIsDisabled(false);}} /> - + /> + - - + ); }; From ad614aff2fb702f0e5253b6cabc74f999461c511 Mon Sep 17 00:00:00 2001 From: Cody Bender Date: Fri, 9 Aug 2024 16:52:08 -0400 Subject: [PATCH 02/11] style: remove disclaimer and center button --- src/pages/ConnectWallet.tsx | 43 +++++++++---------------------------- 1 file changed, 10 insertions(+), 33 deletions(-) diff --git a/src/pages/ConnectWallet.tsx b/src/pages/ConnectWallet.tsx index e904c33..13c959b 100644 --- a/src/pages/ConnectWallet.tsx +++ b/src/pages/ConnectWallet.tsx @@ -1,13 +1,13 @@ import React, { useEffect } from "react"; -import {useLocation, useNavigate, useSearchParams } from "react-router-dom"; +import { useLocation, useNavigate, useSearchParams } from "react-router-dom"; -import { Button, Box, Container, Typography, colors } from "@mui/material"; +import { Button, Box, Container } from "@mui/material"; import { useWalletConnectContext } from "../context/WalletConnectContext"; -import { WALLET_DISCLAIMER_MSG } from "../constants"; const ConnectWallet = () => { - const { connect, session, signClient, checkPersistedState } = useWalletConnectContext(); + const { connect, session, signClient, checkPersistedState } = + useWalletConnectContext(); const navigate = useNavigate(); const location = useLocation(); @@ -28,13 +28,11 @@ const ConnectWallet = () => { if (redirectTo) { navigate(`/${redirectTo}`, { - state: location.state + state: location.state, }); - } - - else { + } else { navigate("/sign-with-nitro-key", { - state: location.state + state: location.state, }); } }, [session, navigate, redirectTo, location.state]); @@ -44,37 +42,16 @@ const ConnectWallet = () => { }; return ( - - - - Disclaimer - - - {WALLET_DISCLAIMER_MSG} - - + - From 051de434803cd29c21a64efb66257a6da22ff42d Mon Sep 17 00:00:00 2001 From: Cody Bender Date: Fri, 9 Aug 2024 16:59:58 -0400 Subject: [PATCH 03/11] chore: add dm mono --- public/index.html | 121 +++++++++++++++++---------------- src/pages/SignWithNitroKey.tsx | 46 +++++++------ 2 files changed, 87 insertions(+), 80 deletions(-) diff --git a/public/index.html b/public/index.html index 4fbd2e7..7fbd272 100644 --- a/public/index.html +++ b/public/index.html @@ -1,21 +1,24 @@ - + - - - - - - - - - - - Testnet Onboarding App - - - - -
-
-
-
+ } + + + + + +
+
+
- - + + diff --git a/src/pages/SignWithNitroKey.tsx b/src/pages/SignWithNitroKey.tsx index 740090b..376706d 100644 --- a/src/pages/SignWithNitroKey.tsx +++ b/src/pages/SignWithNitroKey.tsx @@ -3,22 +3,15 @@ import { useLocation, useNavigate } from "react-router-dom"; import { enqueueSnackbar } from "notistack"; import canonicalStringify from "canonical-json"; -import { - Select, - MenuItem, - Box, - Typography, -} from "@mui/material"; -import LoadingButton from '@mui/lab/LoadingButton'; +import { Select, MenuItem, Box, Typography } from "@mui/material"; +import LoadingButton from "@mui/lab/LoadingButton"; import { utf8ToHex } from "@walletconnect/encoding"; import { useWalletConnectContext } from "../context/WalletConnectContext"; import { ENABLE_KYC, HASHED_SUBSCRIBER_ID_KEY } from "../constants"; const SignWithNitroKey = () => { - - const { session, signClient, isSessionLoading } = - useWalletConnectContext(); + const { session, signClient, isSessionLoading } = useWalletConnectContext(); const navigate = useNavigate(); const location = useLocation(); @@ -42,14 +35,17 @@ const SignWithNitroKey = () => { const [isLoading, setIsLoading] = useState(false); - const subscriberIdHash = useMemo(()=>{ + const subscriberIdHash = useMemo(() => { return localStorage.getItem(HASHED_SUBSCRIBER_ID_KEY); }, []); useEffect(() => { if (!subscriberIdHash) { setIsLoading(false); - enqueueSnackbar("Subscriber ID not found. Please verify your email and try again", { variant: "error" }); + enqueueSnackbar( + "Subscriber ID not found. Please verify your email and try again", + { variant: "error" }, + ); } }, [subscriberIdHash]); @@ -65,7 +61,9 @@ const SignWithNitroKey = () => { try { setIsLoading(true); - enqueueSnackbar("View and sign the message from your Laconic Wallet", { variant: "info" }); + enqueueSnackbar("View and sign the message from your Laconic Wallet", { + variant: "info", + }); const jsonMessage = canonicalStringify(message); const hexMsg = utf8ToHex(jsonMessage, true); @@ -150,15 +148,19 @@ const SignWithNitroKey = () => { ))} - {(Boolean(ethAddress) && Boolean(cosmosAddress)) && ( -
{canonicalStringify(message, null, 2)} 
-
)} + {Boolean(ethAddress) && Boolean(cosmosAddress) && ( + +
+                {canonicalStringify(message, null, 2)}{" "}
+              
+
+ )} Date: Fri, 9 Aug 2024 17:46:04 -0400 Subject: [PATCH 04/11] style: sign with nitro --- src/App.tsx | 3 +- src/components/Container.tsx | 2 +- src/components/Header.tsx | 151 +++++++++++++++++---------------- src/components/Layout.tsx | 28 ------ src/layout/Layout.tsx | 34 ++++++++ src/layout/SignPageLayout.tsx | 56 ++++++------ src/pages/SignWithNitroKey.tsx | 32 +++---- 7 files changed, 157 insertions(+), 149 deletions(-) delete mode 100644 src/components/Layout.tsx create mode 100644 src/layout/Layout.tsx diff --git a/src/App.tsx b/src/App.tsx index 2ac65b1..cb7cbac 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -16,7 +16,7 @@ import Email from "./pages/Email"; import Thanks from "./pages/Thanks"; import Validator from "./pages/Validator"; import ValidatorSuccess from "./pages/ValidatorSuccess"; -import { createTheme, Box, ThemeProvider } from "@mui/material"; +import { createTheme, Box, ThemeProvider, CssBaseline } from "@mui/material"; const darkTheme = createTheme({ components: { @@ -94,6 +94,7 @@ function App() { }} >
+ } /> diff --git a/src/components/Container.tsx b/src/components/Container.tsx index 76c737b..c738e46 100644 --- a/src/components/Container.tsx +++ b/src/components/Container.tsx @@ -9,7 +9,7 @@ export const Container: React.FC< sx={{ width: "100%", maxWidth: "752px", - marginX: "auto", + mx: "auto", backgroundColor: "background.paper", padding: 3, borderRadius: 2, diff --git a/src/components/Header.tsx b/src/components/Header.tsx index d92fdba..a533ddb 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -1,89 +1,90 @@ import React from "react"; import { Link, useLocation } from "react-router-dom"; -import { - AppBar, - Toolbar, - SvgIcon, - Stack, - Divider, - Typography, -} from "@mui/material"; +import { AppBar, SvgIcon, Stack, Divider, Typography } from "@mui/material"; const Header: React.FC = () => { const location = useLocation(); return ( - - - + + - - - - - - - - - - - - - - - - Testnet Onboarding - - + + + + + + + + + + + + + + + Testnet Onboarding + ); }; diff --git a/src/components/Layout.tsx b/src/components/Layout.tsx deleted file mode 100644 index d3b1665..0000000 --- a/src/components/Layout.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { Button, Typography } from "@mui/material"; -import React, { PropsWithChildren } from "react"; -import { Container } from "./Container"; -import { ArrowBack } from "@mui/icons-material"; -import { useNavigate } from "react-router-dom"; - -export const Layout: React.FC< - PropsWithChildren<{ title: string; backLinkTitle?: string }> -> = ({ children, title, backLinkTitle = "Home" }) => { - const navigate = useNavigate(); - - return ( - - - - {title} - - {children} - - ); -}; diff --git a/src/layout/Layout.tsx b/src/layout/Layout.tsx new file mode 100644 index 0000000..9ba9a19 --- /dev/null +++ b/src/layout/Layout.tsx @@ -0,0 +1,34 @@ +import { Button, Typography } from "@mui/material"; +import React, { PropsWithChildren } from "react"; +import { Container } from "../components/Container"; +import { ArrowBack } from "@mui/icons-material"; +import { useNavigate } from "react-router-dom"; + +export const Layout: React.FC< + PropsWithChildren<{ + title: string; + backLinkTitle?: string; + noBackButton?: boolean; + }> +> = ({ children, title, backLinkTitle = "Home", noBackButton = false }) => { + const navigate = useNavigate(); + + return ( + + {noBackButton ? null : ( + + )} + + {title} + + {children} + + ); +}; diff --git a/src/layout/SignPageLayout.tsx b/src/layout/SignPageLayout.tsx index b985f1c..24bdfbf 100644 --- a/src/layout/SignPageLayout.tsx +++ b/src/layout/SignPageLayout.tsx @@ -1,15 +1,10 @@ import React from "react"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; -import { - Toolbar, - Avatar, - Button, - Typography, - Container -} from "@mui/material"; +import { Avatar, Button, Stack, Typography } from "@mui/material"; import { useWalletConnectContext } from "../context/WalletConnectContext"; +import { Container } from "../components/Container"; const SignPageLayout = () => { const { disconnect, session } = useWalletConnectContext(); @@ -25,24 +20,19 @@ const SignPageLayout = () => { }; return ( - <> - - - - - - + + {session && ( -
+
{ }} > - Connected to: {session.peer.metadata.name}{" "} + Connected to: {session.peer.metadata.name} { />
- Session ID: {session.topic} + Session ID: {session.topic} -
+
)} - +
- + + ); }; diff --git a/src/pages/SignWithNitroKey.tsx b/src/pages/SignWithNitroKey.tsx index 376706d..986f53c 100644 --- a/src/pages/SignWithNitroKey.tsx +++ b/src/pages/SignWithNitroKey.tsx @@ -3,12 +3,13 @@ import { useLocation, useNavigate } from "react-router-dom"; import { enqueueSnackbar } from "notistack"; import canonicalStringify from "canonical-json"; -import { Select, MenuItem, Box, Typography } from "@mui/material"; +import { Select, MenuItem, Box, Typography, Stack } from "@mui/material"; import LoadingButton from "@mui/lab/LoadingButton"; import { utf8ToHex } from "@walletconnect/encoding"; import { useWalletConnectContext } from "../context/WalletConnectContext"; import { ENABLE_KYC, HASHED_SUBSCRIBER_ID_KEY } from "../constants"; +import { Layout } from "../layout/Layout"; const SignWithNitroKey = () => { const { session, signClient, isSessionLoading } = useWalletConnectContext(); @@ -104,17 +105,9 @@ const SignWithNitroKey = () => { }; return ( -
+ {session ? ( - - Sign with Nitro key + Select Laconic account: {Boolean(ethAddress) && Boolean(cosmosAddress) && ( - -
-                {canonicalStringify(message, null, 2)}{" "}
-              
-
+ {canonicalStringify(message, null, 2)} )} { const { session, signClient, isSessionLoading } = useWalletConnectContext(); const navigate = useNavigate(); - const [cosmosAddress, setCosmosAddress] = useState(''); + const [cosmosAddress, setCosmosAddress] = useState(""); const [isLoading, setIsLoading] = useState(false); - const [moniker, setMoniker] = useState(''); - const [pubKey, setPubKey] = useState(''); + const [moniker, setMoniker] = useState(""); + const [pubKey, setPubKey] = useState(""); const [participant, setParticipant] = useState(null); const [isError, setIsError] = useState(false); @@ -40,10 +49,13 @@ const Validator = () => { } const fetchParticipant = async () => { - const registry = new Registry(process.env.REACT_APP_REGISTRY_GQL_ENDPOINT!); + const registry = new Registry( + process.env.REACT_APP_REGISTRY_GQL_ENDPOINT!, + ); try { - const fetchedParticipant = await registry.getParticipantByAddress(cosmosAddress); + const fetchedParticipant = + await registry.getParticipantByAddress(cosmosAddress); if (fetchedParticipant) { setParticipant(fetchedParticipant); } else { @@ -65,7 +77,7 @@ const Validator = () => { const msgCreateValidator: MsgCreateValidator = useMemo(() => { const encodedPubKey = encodePubkey({ type: "tendermint/PubKeyEd25519", - value: pubKey.length === 44 ? pubKey : '', + value: pubKey.length === 44 ? pubKey : "", }); return { @@ -82,8 +94,10 @@ const Validator = () => { rate: "100000000000000000", // 0.1 }, minSelfDelegation: "1", - delegatorAddress: '', - validatorAddress: cosmosAddress && toBech32('laconicvaloper', fromBech32(cosmosAddress).data), + delegatorAddress: "", + validatorAddress: + cosmosAddress && + toBech32("laconicvaloper", fromBech32(cosmosAddress).data), pubkey: encodedPubKey, value: { amount: process.env.REACT_APP_STAKING_AMOUNT!, @@ -93,7 +107,7 @@ const Validator = () => { }, [cosmosAddress, pubKey, moniker]); const msgCreateValidatorEncodeObject: EncodeObject = { - typeUrl: '/cosmos.staking.v1beta1.MsgCreateValidator', + typeUrl: "/cosmos.staking.v1beta1.MsgCreateValidator", value: MsgCreateValidator.toJSON(msgCreateValidator), }; @@ -108,10 +122,15 @@ const Validator = () => { } setIsLoading(true); - enqueueSnackbar("View and sign the message from your Laconic Wallet", { variant: "info" }); + enqueueSnackbar("View and sign the message from your Laconic Wallet", { + variant: "info", + }); try { - const params = { transactionMessage: msgCreateValidatorEncodeObject, signer: cosmosAddress }; + const params = { + transactionMessage: msgCreateValidatorEncodeObject, + signer: cosmosAddress, + }; const response = await signClient!.request<{ code: number }>({ topic: session!.topic, chainId: `cosmos:${process.env.REACT_APP_LACONICD_CHAIN_ID}`, @@ -124,7 +143,9 @@ const Validator = () => { if (response.code !== 0) { throw new Error("Transaction not sent"); } else { - navigate("/validator-success", { state: { validatorAddress: msgCreateValidator.validatorAddress, } }); + navigate("/validator-success", { + state: { validatorAddress: msgCreateValidator.validatorAddress }, + }); } } catch (error) { console.error("Error sending transaction", error); @@ -134,16 +155,15 @@ const Validator = () => { } }; - const replacer = (key: string, value: any): any => { + const replacer = (_key: string, value: any): any => { if (value instanceof Uint8Array) { - return Buffer.from(value).toString('hex'); + return Buffer.from(value).toString("hex"); } return value; }; return ( - - Create a validator + Select Laconic account: