Merge branch 'hn.validator-onboarding' of https://github.com/nimbus-gui/nimbus-gui into hn.validator-onboarding
This commit is contained in:
commit
0d3310d67c
|
@ -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
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
)
|
)
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 }}>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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'}>
|
||||||
|
|
Loading…
Reference in New Issue