new styling + new signin and create account pages

This commit is contained in:
fmtabbara
2021-11-25 17:41:15 +00:00
parent 7d3d0d8874
commit 69b52ae629
9 changed files with 227 additions and 12 deletions
+3
View File
@@ -9,6 +9,7 @@ type TClientContext = {
clientDetails?: TClientDetails
getBalance: TUseGetBalance
showAdmin: boolean
mode: 'light' | 'dark'
handleShowAdmin: () => void
logIn: (clientDetails: TSignInWithMnemonic) => void
logOut: () => void
@@ -23,6 +24,7 @@ export const ClientContextProvider = ({
}) => {
const [clientDetails, setClientDetails] = useState<TClientDetails>()
const [showAdmin, setShowAdmin] = useState(false)
const [mode, setMode] = useState<'light' | 'dark'>('dark')
const history = useHistory()
const getBalance = useGetBalance()
@@ -44,6 +46,7 @@ export const ClientContextProvider = ({
clientDetails,
getBalance,
showAdmin,
mode,
handleShowAdmin,
logIn,
logOut,
+1 -1
View File
@@ -5,7 +5,7 @@ import { BrowserRouter as Router } from 'react-router-dom'
import { Routes } from './routes'
import { ClientContext, ClientContextProvider } from './context/main'
import { ApplicationLayout } from './layouts'
import { SignIn } from './routes/sign-in'
import { SignIn } from './routes/sign-in/'
import { Admin, ErrorFallback } from './components'
import { NymWalletTheme } from './theme'
-4
View File
@@ -6,16 +6,12 @@ import { Bond } from './bond'
import { Delegate } from './delegate'
import { Receive } from './receive'
import { Send } from './send'
import { SignIn } from './sign-in'
import { Unbond } from './unbond'
import { Undelegate } from './undelegate'
import { InternalDocs } from './internal-docs'
export const Routes = () => (
<Switch>
<Route path="/signin">
<SignIn />
</Route>
<Route path="/balance">
<Balance />
</Route>
+1
View File
@@ -199,6 +199,7 @@ const CreateAccountContent = ({ showSignIn }: { showSignIn: () => void }) => {
setError(e)
}
}
return (
<SignInCard>
<Typography variant="h4">Create wallet</Typography>
@@ -0,0 +1,86 @@
import React, { useEffect, useState } from 'react'
import {
Alert,
Button,
Card,
CardActions,
CardContent,
CardHeader,
CircularProgress,
Stack,
Typography,
} from '@mui/material'
import { Box } from '@mui/system'
import { createAccount } from '../../requests'
import { TCreateAccount } from '../../types'
import logo from '../../images/logo-background.svg'
import { CopyToClipboard } from '../../components'
export const CreateAccountContent: React.FC<{ showSignIn: () => void }> = ({
showSignIn,
}) => {
const [accountDetails, setAccountDetails] = useState<TCreateAccount>()
const [isLoading, setIsLoading] = useState(false)
const [error, setError] = useState<Error>()
const handleCreateAccount = async () => {
setIsLoading(true)
setError(undefined)
try {
const res = await createAccount()
setTimeout(() => {
setAccountDetails(res)
setIsLoading(false)
}, 2500)
} catch (e: any) {
setError(e)
}
}
useEffect(() => {
handleCreateAccount()
}, [])
if (isLoading) return <CircularProgress size={70} />
return (
<Stack spacing={4} alignItems="center">
<img src={logo} width={80} />
<Typography variant="h4">Congratulations</Typography>
<Typography variant="h6">Account setup complete!</Typography>
<Alert severity="info" variant="outlined">
<Box sx={{ textAlign: 'center' }} data-testid="mnemonic-warning">
Please store your mnemonic in a safe place. You'll need it to access
your account!
</Box>
</Alert>
<Card variant="outlined" sx={{ bgcolor: 'transparent', p: 2 }}>
<CardHeader title="Mnemonic" />
<CardContent data-testid="mnemonic-phrase">
{accountDetails?.mnemonic}
</CardContent>
<CardActions sx={{ justifyContent: 'flex-end' }}>
<CopyToClipboard text={accountDetails?.mnemonic || ''} />
</CardActions>
</Card>
<Box sx={{ textAlign: 'center' }}>
<Typography variant="body2">Account address:</Typography>
<Typography data-testid="wallet-address">
{accountDetails?.client_address}
</Typography>
</Box>
{error && (
<Alert severity="error" variant="outlined">
{error}
</Alert>
)}
<Button
variant="contained"
onClick={showSignIn}
data-testid="sign-in-button"
>
Back to sign in
</Button>
</Stack>
)
}
+35
View File
@@ -0,0 +1,35 @@
import React, { useContext, useState } from 'react'
import { Box } from '@mui/system'
import { SignInContent } from './sign-in'
import { CreateAccountContent } from './create-account'
export const SignIn = () => {
const [showCreateAccount, setShowCreateAccount] = useState(false)
return (
<Box
sx={{
height: '100vh',
width: '100vw',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Box
sx={{
width: 500,
display: 'flex',
justifyContent: 'center',
}}
>
{showCreateAccount ? (
<CreateAccountContent
showSignIn={() => setShowCreateAccount(false)}
/>
) : (
<SignInContent showCreateAccount={() => setShowCreateAccount(true)} />
)}
</Box>
</Box>
)
}
+96
View File
@@ -0,0 +1,96 @@
import React, { useContext, useState } from 'react'
import {
Button,
CircularProgress,
Grid,
Stack,
Link,
TextField,
Typography,
Alert,
} from '@mui/material'
import logo from '../../images/logo-background.svg'
import { signInWithMnemonic } from '../../requests'
import { ClientContext } from '../../context/main'
export const SignInContent: React.FC<{ showCreateAccount: () => void }> = ({
showCreateAccount,
}) => {
const [mnemonic, setMnemonic] = useState<string>('')
const [inputError, setInputError] = useState<string>()
const [isLoading, setIsLoading] = useState(false)
const { logIn } = useContext(ClientContext)
const handleSignIn = async (e: React.MouseEvent<HTMLElement>) => {
e.preventDefault()
setIsLoading(true)
setInputError(undefined)
try {
const res = await signInWithMnemonic(mnemonic || '')
setIsLoading(false)
logIn(res)
} catch (e: any) {
setIsLoading(false)
setInputError(e)
}
}
return (
<Stack spacing={3} alignItems="center" sx={{ width: '100%' }}>
<img src={logo} style={{ width: 80 }} />
<Typography>Enter Mnemonic and sign in</Typography>
<Grid container direction="column" spacing={1}>
<Grid item>
<TextField
value={mnemonic}
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setMnemonic(e.target.value)
}
size="medium"
variant="outlined"
margin="normal"
required
fullWidth
id="mnemonic"
label="BIP-39 Mnemonic"
name="mnemonic"
autoComplete="mnemonic"
autoFocus
disabled={isLoading}
sx={{ color: 'red' }}
/>
</Grid>
<Grid item>
<Button
fullWidth
variant="contained"
color="primary"
disabled={isLoading}
endIcon={isLoading && <CircularProgress size={20} />}
disableElevation
size="large"
onClick={handleSignIn}
>
{!isLoading ? 'Sign In' : 'Signing in'}
</Button>
</Grid>
{inputError && (
<Grid item sx={{ mt: 1 }}>
<Alert severity="error" variant="outlined" data-testid="error">
{inputError}
</Alert>
</Grid>
)}
</Grid>
<div>
<Typography component="span">Don't have an account?</Typography>{' '}
<Link href="#" onClick={showCreateAccount}>
Create one now
</Link>
</div>
</Stack>
)
}
+4 -5
View File
@@ -1,16 +1,15 @@
import * as React from 'react'
import React, { useContext } from 'react'
import { createTheme, ThemeProvider } from '@mui/material/styles'
import { CssBaseline } from '@mui/material'
import { getDesignTokens } from './theme'
import { ClientContext } from '../context/main'
/**
* Provides the theme for the Network Explorer by reacting to the light/dark mode choice stored in the app context.
*/
export const NymWalletTheme: React.FC = ({ children }) => {
const theme = React.useMemo(
() => createTheme(getDesignTokens('light')),
['light'],
)
const { mode } = useContext(ClientContext)
const theme = React.useMemo(() => createTheme(getDesignTokens(mode)), [mode])
return (
<ThemeProvider theme={theme}>
<CssBaseline />
+1 -2
View File
@@ -31,7 +31,7 @@ const nymPalette: NymPalette = {
const darkMode: NymPaletteVariant = {
mode: 'dark',
background: {
main: '#111826',
main: '#121726',
paper: '#242C3D',
},
text: {
@@ -192,7 +192,6 @@ export const getDesignTokens = (mode: PaletteMode): ThemeOptions => {
easeIn: 'cubic-bezier(0.4, 0, 1, 1)',
},
},
palette,
}
}