Merge branch 'hn.validator-onboarding' of https://github.com/nimbus-gui/nimbus-gui into hn.validator-onboarding

This commit is contained in:
Hristo Nedelkov 2023-08-29 11:17:17 +03:00
commit 0d3310d67c
8 changed files with 139 additions and 74 deletions

View File

@ -0,0 +1,14 @@
import { YStack } from 'tamagui'
import KeyGenerationTitle from './KeyGenerationTitle'
import { Text } from '@status-im/components'
const ConfirmRecoveryPhrase = () => {
return (
<YStack space={'$4'} style={{ width: '100%', marginTop: '20px' }}>
<KeyGenerationTitle />
<Text size={27}>Confirm Recovery Phrase</Text>
</YStack>
)
}
export default ConfirmRecoveryPhrase

View File

@ -1,10 +1,8 @@
import { XStack, YStack } from 'tamagui' import { Stack, XStack, YStack } from 'tamagui'
import { Button, InformationBox, Input, Text } from '@status-im/components' import { Button, InformationBox, Input, Text } from '@status-im/components'
import { ClearIcon, CloseCircleIcon } from '@status-im/icons' import { ClearIcon, CloseCircleIcon } from '@status-im/icons'
import { useState } from 'react' import { useState } from 'react'
import BorderBox from '../../../components/General/BorderBox'
const KeyFiles = () => { const KeyFiles = () => {
const [encryptedPassword, setEncryptedPassword] = useState('') const [encryptedPassword, setEncryptedPassword] = useState('')
const [confirmEncryptedPassword, setConfirmEncryptedPassword] = useState('') const [confirmEncryptedPassword, setConfirmEncryptedPassword] = useState('')
@ -28,10 +26,10 @@ const KeyFiles = () => {
} }
return ( return (
<YStack space={'$2'}> <YStack space={'$4'}>
<XStack space={'$2'} style={{ justifyContent: 'space-between' }}> <XStack space={'$2'} style={{ justifyContent: 'space-between', width: '100%' }}>
<YStack space={'$1'}> <YStack space={'$4'} style={{ width: '66%' }}>
<YStack space={'$2'}> <YStack space={'$4'}>
<Text size={15} color={'#647084'}> <Text size={15} color={'#647084'}>
Encryption Password Encryption Password
</Text> </Text>
@ -68,13 +66,23 @@ const KeyFiles = () => {
/> />
</YStack> </YStack>
</YStack> </YStack>
<BorderBox> <YStack
style={{
border: '1px solid #DCE0E5',
borderRadius: '16px',
padding: '12px 16px',
width: '32%',
marginTop: '3.4%',
}}
>
<Text size={15} weight={'semibold'}> <Text size={15} weight={'semibold'}>
Download Key Files Download Key Files
</Text> </Text>
</BorderBox> </YStack>
</XStack> </XStack>
<Button onPress={generateKeyFilesHandler}>Generate Key files</Button> <Stack style={{ width: 'fit-content' }}>
<Button onPress={generateKeyFilesHandler}>Generate Key files</Button>
</Stack>
<InformationBox <InformationBox
message="You should see that you have one keystore per validator. This keystore contains your signing key, encrypted with your password. Warning: Do not store keys on multiple (backup) validator clients at once" message="You should see that you have one keystore per validator. This keystore contains your signing key, encrypted with your password. Warning: Do not store keys on multiple (backup) validator clients at once"
variant="error" variant="error"

View File

@ -1,36 +1,49 @@
import { YStack } from 'tamagui' import { Stack, YStack } from 'tamagui'
import { Text } from '@status-im/components'
import { useState } from 'react'
import KeyGenerationHeader from './KeyGenerationHeader' import KeyGenerationHeader from './KeyGenerationHeader'
import RecoveryMechanism from './RecoveryMechanism' import RecoveryMechanism from './RecoveryMechanism'
import { Text } from '@status-im/components'
import KeyFiles from './KeyFiles' import KeyFiles from './KeyFiles'
import { useState } from 'react'
import RecoveryPhrase from './RecoveryPhrase' import RecoveryPhrase from './RecoveryPhrase'
import { BOTH_KEY_AND_RECOVERY, KEY_FILES, RECOVERY_PHRASE } from '../../../constants' import { BOTH_KEY_AND_RECOVERY, KEY_FILES, RECOVERY_PHRASE } from '../../../constants'
import ConfirmRecoveryPhrase from './ConfirmRecoveryPhrase'
const KeyGeneration = () => { type KeyGenerationProps = {
isConfirmPhraseStage: boolean
}
const KeyGeneration = ({ isConfirmPhraseStage }: KeyGenerationProps) => {
const [recoveryMechanism, setRecoveryMechanism] = useState(KEY_FILES) const [recoveryMechanism, setRecoveryMechanism] = useState(KEY_FILES)
const handleRecMechanismChange = (value: string) => {
setRecoveryMechanism(value)
}
const isKeyFiles = recoveryMechanism === KEY_FILES || recoveryMechanism === BOTH_KEY_AND_RECOVERY const isKeyFiles = recoveryMechanism === KEY_FILES || recoveryMechanism === BOTH_KEY_AND_RECOVERY
const isRecoveryPhrase = const isRecoveryPhrase =
recoveryMechanism === RECOVERY_PHRASE || recoveryMechanism === BOTH_KEY_AND_RECOVERY recoveryMechanism === RECOVERY_PHRASE || recoveryMechanism === BOTH_KEY_AND_RECOVERY
const handleRecMechanismChange = (value: string) => {
setRecoveryMechanism(value)
}
return ( return (
<YStack space={'$2'} style={{ width: '100%', padding: '16px 32px', alignItems: 'start' }}> <YStack space={'$2'} style={{ width: '100%', padding: '16px 32px', alignItems: 'start' }}>
<KeyGenerationHeader /> {isConfirmPhraseStage && <ConfirmRecoveryPhrase />}
<RecoveryMechanism {isConfirmPhraseStage === false && (
recoveryMechanism={recoveryMechanism} <>
handleRecMechanismChange={handleRecMechanismChange} <KeyGenerationHeader />
/> <RecoveryMechanism
<Text size={27} weight={'semibold'}> recoveryMechanism={recoveryMechanism}
4 Validators handleRecMechanismChange={handleRecMechanismChange}
</Text> />
{isKeyFiles && <KeyFiles />} <Stack style={{ margin: '30px 0' }}>
{isRecoveryPhrase && <RecoveryPhrase />} <Text size={27} weight={'semibold'}>
4 Validators
</Text>
</Stack>
{isKeyFiles && <KeyFiles />}
{isRecoveryPhrase && <RecoveryPhrase isKeyFiles={isKeyFiles} />}
</>
)}
</YStack> </YStack>
) )
} }

View File

@ -1,5 +1,6 @@
import { Text } from '@status-im/components' import { Text } from '@status-im/components'
import { XStack, YStack } from 'tamagui' import { XStack, YStack } from 'tamagui'
import RecoveryMechanismCard from './RecoveryMechanismCard' import RecoveryMechanismCard from './RecoveryMechanismCard'
import { BOTH_KEY_AND_RECOVERY, KEY_FILES, RECOVERY_PHRASE } from '../../../constants' import { BOTH_KEY_AND_RECOVERY, KEY_FILES, RECOVERY_PHRASE } from '../../../constants'
@ -8,6 +9,8 @@ type RecoveryMechanismProps = {
handleRecMechanismChange: (value: string) => void handleRecMechanismChange: (value: string) => void
} }
const cards = [KEY_FILES, RECOVERY_PHRASE, BOTH_KEY_AND_RECOVERY]
const RecoveryMechanism = ({ const RecoveryMechanism = ({
recoveryMechanism, recoveryMechanism,
handleRecMechanismChange, handleRecMechanismChange,
@ -18,21 +21,14 @@ const RecoveryMechanism = ({
Select Recovery Mechanism Select Recovery Mechanism
</Text> </Text>
<XStack space={'$4'} style={{ justifyContent: 'space-between', marginTop: '40px' }}> <XStack space={'$4'} style={{ justifyContent: 'space-between', marginTop: '40px' }}>
<RecoveryMechanismCard {cards.map(value => (
value={KEY_FILES} <RecoveryMechanismCard
recoveryMechanism={recoveryMechanism} key={value}
handleRecMechanismChange={handleRecMechanismChange} value={value}
/> recoveryMechanism={recoveryMechanism}
<RecoveryMechanismCard handleRecMechanismChange={handleRecMechanismChange}
value={RECOVERY_PHRASE} />
recoveryMechanism={recoveryMechanism} ))}
handleRecMechanismChange={handleRecMechanismChange}
/>
<RecoveryMechanismCard
value={BOTH_KEY_AND_RECOVERY}
recoveryMechanism={recoveryMechanism}
handleRecMechanismChange={handleRecMechanismChange}
/>
</XStack> </XStack>
</YStack> </YStack>
) )

View File

@ -1,11 +1,39 @@
import { YStack } from 'tamagui' import { Stack, YStack } from 'tamagui'
import { Button, InformationBox } from '@status-im/components' import { Button, InformationBox, Text } from '@status-im/components'
import { CloseCircleIcon } from '@status-im/icons' import { CloseCircleIcon } from '@status-im/icons'
import { useState } from 'react'
type RecoveryPhraseProps = {
isKeyFiles: boolean
}
const RecoveryPhrase = ({ isKeyFiles }: RecoveryPhraseProps) => {
const [isReveal, setIsReveal] = useState(false)
const revealHandler = () => {
setIsReveal(state => !state)
}
const RecoveryPhrase = () => {
return ( return (
<YStack space={'$2'}> <YStack space={'$4'} style={{ width: '100%', marginTop: isKeyFiles ? '20px' : '0px' }}>
<Button>Reveal Recovery Phrase</Button> <Stack
style={{
border: `1px solid #2A4AF566`,
borderRadius: '16px',
padding: '12px 16px',
backgroundColor: '#f4f6fe',
width: '100%',
}}
>
<Stack style={{ filter: `blur(${isReveal ? '0px' : '4px'})` }}>
<Text size={15} weight={'semibold'}>
asdf
</Text>
</Stack>
</Stack>
<Stack style={{ width: 'fit-content', marginBottom: '12px' }}>
<Button onPress={revealHandler}>Reveal Recovery Phrase</Button>
</Stack>
<InformationBox <InformationBox
message="Write down and keep your Secret Recovery Phrase in a secure place. Make sure no one is looking at your screen." message="Write down and keep your Secret Recovery Phrase in a secure place. Make sure no one is looking at your screen."
variant="error" variant="error"

View File

@ -14,6 +14,7 @@ import ValidatorSetupInstall from './ValidatorSetup/ValidatorInstall'
const ValidatorOnboarding = () => { const ValidatorOnboarding = () => {
const [activeStep, setActiveStep] = useState(0) const [activeStep, setActiveStep] = useState(0)
const [isConfirmPhraseStage, setIsConfirmPhraseStage] = useState(false)
const navigate = useNavigate() const navigate = useNavigate()
const changeActiveStep = (step: number) => { const changeActiveStep = (step: number) => {
@ -21,7 +22,9 @@ const ValidatorOnboarding = () => {
} }
const continueHandler = () => { const continueHandler = () => {
if (activeStep < 4) { if (activeStep === 3 && isConfirmPhraseStage === false) {
setIsConfirmPhraseStage(true)
} else if (activeStep < 4) {
setActiveStep(activeStep + 1) setActiveStep(activeStep + 1)
} else { } else {
navigate('/') navigate('/')
@ -49,7 +52,7 @@ const ValidatorOnboarding = () => {
{activeStep === 0 && <Overview />} {activeStep === 0 && <Overview />}
{activeStep === 1 && <Advicsories />} {activeStep === 1 && <Advicsories />}
{activeStep === 2 && <ValidatorSetupInstall />} {activeStep === 2 && <ValidatorSetupInstall />}
{activeStep === 3 && <KeyGeneration />} {activeStep === 3 && <KeyGeneration isConfirmPhraseStage={isConfirmPhraseStage} />}
{activeStep === 4 && <Activation />} {activeStep === 4 && <Activation />}
</ValidatorBoxWrapper> </ValidatorBoxWrapper>
<Stack style={{ alignItems: 'end', width: '100%', marginTop: '16px', zIndex: 999 }}> <Stack style={{ alignItems: 'end', width: '100%', marginTop: '16px', zIndex: 999 }}>

View File

@ -1,6 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react' import type { Meta, StoryObj } from '@storybook/react'
import ValidatorSetup from './ValidatorSetup' import ValidatorSetup from './ValidatorSetup'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = { const meta = {
title: 'ValidatorOnboarding/ValidatorSetup', title: 'ValidatorOnboarding/ValidatorSetup',
@ -10,6 +11,7 @@ const meta = {
}, },
tags: ['autodocs'], tags: ['autodocs'],
argTypes: {}, argTypes: {},
decorators: [withRouter()],
} satisfies Meta<typeof ValidatorSetup> } satisfies Meta<typeof ValidatorSetup>
export default meta export default meta

View File

@ -4,31 +4,32 @@ import { Text } from '@status-im/components'
import ExecClientCard from './ExecClientCard' import ExecClientCard from './ExecClientCard'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
const execClientCardsContent = [
{
name: 'Nethermind',
icon: '/icons/nethermind-circle.png',
},
{
name: 'Besu',
icon: '/icons/hyperledger-besu-circle.png',
},
{
name: 'Geth',
icon: '/icons/gethereum-mascot-circle.png',
isSelected: true,
},
{
name: 'Erigon',
icon: '/icons/erigon-circle.png',
},
{
name: 'Nimbus',
icon: '/icons/NimbusDisabled.svg',
isComingSoon: true,
},
]
const ValidatorSetup = () => { const ValidatorSetup = () => {
const execClientCardsContent = [
{
name: 'Nethermind',
icon: '/icons/nethermind-circle.png',
},
{
name: 'Besu',
icon: '/icons/hyperledger-besu-circle.png',
},
{
name: 'Geth',
icon: '/icons/gethereum-mascot-circle.png',
isSelected: true,
},
{
name: 'Erigon',
icon: '/icons/erigon-circle.png',
},
{
name: 'Nimbus',
icon: '/icons/NimbusDisabled.svg',
isComingSoon: true,
},
]
return ( return (
<YStack style={{ width: '100%', padding: '16px 32px' }}> <YStack style={{ width: '100%', padding: '16px 32px' }}>
<XStack justifyContent={'space-between'}> <XStack justifyContent={'space-between'}>