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

This commit is contained in:
Ivana Andersson 2023-09-07 15:12:49 +03:00
commit 4dc83a834a
13 changed files with 238 additions and 17 deletions

View File

@ -1,12 +1,25 @@
import { Stack, XStack, YStack } from 'tamagui' import { Stack, XStack, YStack } from 'tamagui'
import { Input as StatusInput, Text } from '@status-im/components' import { Input as StatusInput, Text } from '@status-im/components'
import { AddIcon, ChevronDownIcon } from '@status-im/icons' import { AddIcon, ChevronDownIcon } from '@status-im/icons'
import { useState } from 'react'
type SetupRowProps = { type SetupRowProps = {
title: string title: string
} }
const SetupRow = ({ title }: SetupRowProps) => { const SetupRow = ({ title }: SetupRowProps) => {
const [validatorCount, setValidatorCount] = useState(0)
const addValidatorHandler = () => {
setValidatorCount((state: number) => state + 1)
}
const changeValidatorCountHandler = (e: any) => {
if (!isNaN(e.target.value)) {
setValidatorCount(Number(e.target.value))
}
}
return ( return (
<YStack space={'$4'}> <YStack space={'$4'}>
<Text size={19} weight={'semibold'}> <Text size={19} weight={'semibold'}>
@ -17,7 +30,12 @@ const SetupRow = ({ title }: SetupRowProps) => {
<Text size={15} weight="regular" color={'#647084'}> <Text size={15} weight="regular" color={'#647084'}>
How many Validators would you like to run? How many Validators would you like to run?
</Text> </Text>
<StatusInput icon={<AddIcon size={16} />} /> <StatusInput
icon={<AddIcon size={16} style={{ cursor: 'pointer' }} onClick={addValidatorHandler} />}
value={validatorCount.toString()}
onChange={changeValidatorCountHandler}
style={{ fontWeight: 'bold' }}
/>
</Stack> </Stack>
<YStack space={'$2'}> <YStack space={'$2'}>
<Text size={15} weight={'semibold'} color="#09101C"> <Text size={15} weight={'semibold'} color="#09101C">

View File

@ -1,12 +1,23 @@
import { Stack, YStack } from 'tamagui' import { Stack, YStack } from 'tamagui'
import { InformationBox, Input as StatusInput, Text } from '@status-im/components' import { InformationBox, Input as StatusInput, Text } from '@status-im/components'
import { ClearIcon, CloseCircleIcon } from '@status-im/icons' import { ClearIcon, CloseCircleIcon } from '@status-im/icons'
import { useState } from 'react'
type WithdrawalAddressProps = { type WithdrawalAddressProps = {
title: string title: string
} }
const WithdrawalAddress = ({ title }: WithdrawalAddressProps) => { const WithdrawalAddress = ({ title }: WithdrawalAddressProps) => {
const [withdrawalAddress, setWithdrawalAddress] = useState('')
const changeWithdrawalAddressHandler = (e: any) => {
setWithdrawalAddress(e.target.value)
}
const removeWithdrawalAddressHandler = () => {
setWithdrawalAddress('')
}
return ( return (
<YStack space={'$4'}> <YStack space={'$4'}>
<Text size={19} weight={'semibold'}> <Text size={19} weight={'semibold'}>
@ -20,7 +31,15 @@ const WithdrawalAddress = ({ title }: WithdrawalAddressProps) => {
<StatusInput <StatusInput
placeholder={'******************'} placeholder={'******************'}
width={'100%'} width={'100%'}
icon={<ClearIcon size={16} />} icon={
<ClearIcon
size={16}
style={{ cursor: 'pointer' }}
onClick={removeWithdrawalAddressHandler}
/>
}
value={withdrawalAddress}
onChange={changeWithdrawalAddressHandler}
/> />
</Stack> </Stack>
<InformationBox <InformationBox

View File

@ -8,13 +8,21 @@ import { RootState } from '../../redux/store'
type ContinueButton = { type ContinueButton = {
continueHandler: () => void continueHandler: () => void
activeStep: number activeStep: number
isConfirmPhraseStage: boolean
} }
const ContinueButton = ({ continueHandler, activeStep }: ContinueButton) => { const ContinueButton = ({ continueHandler, activeStep, isConfirmPhraseStage }: ContinueButton) => {
const isCopyPastedPhrase = useSelector( const { isCopyPastedPhrase, isRightPhrase } = useSelector(
(state: RootState) => state.keyGeneration.isCopyPastedPhrase, (state: RootState) => state.keyGeneration,
) )
const isDisabled = () => {
if (isConfirmPhraseStage && !isRightPhrase) {
return true
}
return false
}
return ( return (
<XStack style={{ width: '100%', marginTop: '16px', zIndex: 999, alignItems: 'center' }}> <XStack style={{ width: '100%', marginTop: '16px', zIndex: 999, alignItems: 'center' }}>
<Stack style={{ width: '100%' }}> <Stack style={{ width: '100%' }}>
@ -35,7 +43,7 @@ const ContinueButton = ({ continueHandler, activeStep }: ContinueButton) => {
marginTop: isCopyPastedPhrase ? '0px' : '40px', marginTop: isCopyPastedPhrase ? '0px' : '40px',
}} }}
> >
<Button onPress={continueHandler} size={40}> <Button onPress={continueHandler} size={40} disabled={isDisabled()}>
{activeStep < 5 ? 'Continue' : 'Continue to Dashboard'} {activeStep < 5 ? 'Continue' : 'Continue to Dashboard'}
</Button> </Button>
</Stack> </Stack>

View File

@ -18,6 +18,7 @@ import ContinueButton from './ContinueButton'
import { setIsCopyPastedPhrase } from '../../redux/ValidatorOnboarding/KeyGeneration/slice' import { setIsCopyPastedPhrase } from '../../redux/ValidatorOnboarding/KeyGeneration/slice'
import { RootState } from '../../redux/store' import { RootState } from '../../redux/store'
import './layoutGradient.css' import './layoutGradient.css'
import ActivationValidatorSetup from './ValidatorSetup/ActivationValidatorSetup'
const ValidatorOnboarding = () => { const ValidatorOnboarding = () => {
const [activeStep, setActiveStep] = useState(0) const [activeStep, setActiveStep] = useState(0)
@ -37,7 +38,7 @@ const ValidatorOnboarding = () => {
const continueHandler = () => { const continueHandler = () => {
if (activeStep === 4 && isConfirmPhraseStage === false) { if (activeStep === 4 && isConfirmPhraseStage === false) {
setIsConfirmPhraseStage(true) setIsConfirmPhraseStage(true)
} else if (activeStep === 3 && subStepValidatorSetup < 2) { } else if (activeStep === 3 && subStepValidatorSetup < 3) {
setSubStepValidatorSetup(subStepValidatorSetup + 1) setSubStepValidatorSetup(subStepValidatorSetup + 1)
} else if (activeStep < 5) { } else if (activeStep < 5) {
setActiveStep(activeStep + 1) setActiveStep(activeStep + 1)
@ -81,11 +82,16 @@ const ValidatorOnboarding = () => {
{activeStep === 3 && subStepValidatorSetup === 0 && <ValidatorSetup />} {activeStep === 3 && subStepValidatorSetup === 0 && <ValidatorSetup />}
{activeStep === 3 && subStepValidatorSetup === 1 && <ValidatorSetupInstall />} {activeStep === 3 && subStepValidatorSetup === 1 && <ValidatorSetupInstall />}
{activeStep === 3 && subStepValidatorSetup === 2 && <ConsensusSelection />} {activeStep === 3 && subStepValidatorSetup === 2 && <ConsensusSelection />}
{activeStep === 3 && subStepValidatorSetup === 3 && <ActivationValidatorSetup />}
{activeStep === 4 && <KeyGeneration isConfirmPhraseStage={isConfirmPhraseStage} />} {activeStep === 4 && <KeyGeneration isConfirmPhraseStage={isConfirmPhraseStage} />}
{activeStep === 5 && <Activation />} {activeStep === 5 && <Activation />}
</ValidatorBoxWrapper> </ValidatorBoxWrapper>
<ContinueButton activeStep={activeStep} continueHandler={continueHandler} /> <ContinueButton
activeStep={activeStep}
continueHandler={continueHandler}
isConfirmPhraseStage={isConfirmPhraseStage}
/>
</YStack> </YStack>
</div> </div>
) )

View File

@ -0,0 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react'
import ActivationValidatorSetup from './ActivationValidatorSetup'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'ValidatorOnboarding/ActivationValidatorSetup',
component: ActivationValidatorSetup,
tags: ['autodocs'],
decorators: [withRouter()],
} satisfies Meta<typeof ActivationValidatorSetup>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {},
}

View File

@ -0,0 +1,87 @@
import { useState, useEffect } from 'react'
import { XStack, Stack, YStack } from 'tamagui'
import { Text } from '@status-im/components'
import Confetti from 'react-confetti'
import LinkWithArrow from '../../../components/General/LinkWithArrow'
import ActivationCard from '../Activation/ActivationCard'
const styles = {
confettiContainer: {
position: 'relative' as const,
width: '100%',
height: '100%',
justifyContent: 'fit-content'
},
confettiCanvas: {
position: 'absolute' as const,
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: 0,
},
}
const ActivationValidatorSetup = () => {
const [showConfetti, setShowConfetti] = useState(true)
useEffect(() => {
const timer = setTimeout(() => {
setShowConfetti(false)
}, 10000)
return () => {
clearTimeout(timer)
}
}, [])
return (
<Stack style={styles.confettiContainer} width={'100%'} >
{showConfetti && <Confetti style={styles.confettiCanvas} />}
<YStack style={{ padding: '16px 32px' }}>
<YStack space={'$5'}>
<Text size={27} weight={'semibold'}>
Activation
</Text>
<Stack >
<Text size={27}>
Congratulations! You have successfully setup your Execution and Consensus clients and are currently syncing your nodes. You need to be sufficiently synced prior to setting up your validators and making a deposit.
</Text>
</Stack>
<YStack space={'$3'} marginTop={'10px'} width={'33%'} >
<XStack width={'151%'} space={'$3'} >
<ActivationCard
text="Execution Sync Status"
isGaugeIncluded={true}
gaugeColor={'#2a4af5'}
gaugeSynced={123.524}
gaugeTotal={172.503}
/>
<ActivationCard
text="Execution Sync Status"
isGaugeIncluded={true}
gaugeColor={'#EB5757'}
gaugeSynced={123.524}
gaugeTotal={172.503}
/>
</XStack>
<XStack space={'$3'}>
<ActivationCard text="Validator Queue" value="92603" />
<ActivationCard text="Estimated Activation Time" value="32 Days" />
<ActivationCard text="Current APR" value="4.40%" />
</XStack>
</YStack>
</YStack>
<LinkWithArrow
text="Skip to Dashboard"
to="/"
arrowLeft={true}
style={{ marginTop: '44px', marginBottom: '88px' }}
/>
</YStack>
</Stack>
)
}
export default ActivationValidatorSetup

View File

@ -0,0 +1,19 @@
import type { Meta, StoryObj } from '@storybook/react'
import ConsensusClientCard from './ConsensusClientCard'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'ValidatorOnboarding/ConsensusClientCard',
component: ConsensusClientCard,
tags: ['autodocs'],
decorators: [withRouter()],
} satisfies Meta<typeof ConsensusClientCard>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: { name: 'Erigon', icon: '/icons/erigon-circle.png' },
}

View File

@ -0,0 +1,23 @@
import type { Meta, StoryObj } from '@storybook/react'
import ConsensusGaugeCard from './ConsensusGaugeCard'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'ValidatorOnboarding/ConsensusGaugeCard',
component: ConsensusGaugeCard,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter()],
} satisfies Meta<typeof ConsensusGaugeCard>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
color:'orange', synced:140000, total:200000, title: 'Synced Files'
},
}

View File

@ -10,7 +10,7 @@ const meta = {
layout: 'centered', layout: 'centered',
}, },
tags: ['autodocs'], tags: ['autodocs'],
decorators: [withRouter()], decorators: [withRouter],
} }
export default meta export default meta
type Story = StoryObj<typeof meta> type Story = StoryObj<typeof meta>

View File

@ -6,9 +6,8 @@ import { withRouter } from 'storybook-addon-react-router-v6'
const meta = { const meta = {
title: 'ValidatorOnboarding/ExecClientCard', title: 'ValidatorOnboarding/ExecClientCard',
component: ExecClientCard, component: ExecClientCard,
tags: ['autodocs'], tags: ['autodocs'],
decorators: [withRouter()], decorators: [withRouter],
} satisfies Meta<typeof ExecClientCard> } satisfies Meta<typeof ExecClientCard>
export default meta export default meta

View File

@ -10,7 +10,7 @@ const meta = {
layout: 'centered', layout: 'centered',
}, },
tags: ['autodocs'], tags: ['autodocs'],
decorators: [withRouter()], decorators: [withRouter],
} satisfies Meta<typeof PairedDeviceCard> } satisfies Meta<typeof PairedDeviceCard>
export default meta export default meta

View File

@ -0,0 +1,21 @@
import type { Meta, StoryObj } from '@storybook/react'
import SyntaxHighlighter from './SyntaxHighlighter'
import { withRouter } from 'storybook-addon-react-router-v6'
const meta = {
title: 'ValidatorOnboarding/SyntaxHighlighter',
component: SyntaxHighlighter,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
decorators: [withRouter()],
} satisfies Meta<typeof SyntaxHighlighter>
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: { rows: ['yarn', 'yarn build', 'yarn dev', 'house'] },
}

View File

@ -3,6 +3,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'
type KeyGenerationState = { type KeyGenerationState = {
words: string[] words: string[]
isCopyPastedPhrase: boolean isCopyPastedPhrase: boolean
isRightPhrase: boolean
} }
type wordProps = { type wordProps = {
@ -13,6 +14,7 @@ type wordProps = {
const initialState: KeyGenerationState = { const initialState: KeyGenerationState = {
words: Array(24).fill(''), words: Array(24).fill(''),
isCopyPastedPhrase: false, isCopyPastedPhrase: false,
isRightPhrase: false,
} }
const keyGenerationSlice = createSlice({ const keyGenerationSlice = createSlice({
@ -30,13 +32,13 @@ const keyGenerationSlice = createSlice({
setIsCopyPastedPhrase: (state, action: PayloadAction<boolean>) => { setIsCopyPastedPhrase: (state, action: PayloadAction<boolean>) => {
state.isCopyPastedPhrase = action.payload state.isCopyPastedPhrase = action.payload
}, },
setIsRightPhrase: (state, action: PayloadAction<boolean>) => {
state.isRightPhrase = action.payload
},
}, },
}) })
export const { export const { setWord, setMnemonic, setIsCopyPastedPhrase, setIsRightPhrase } =
setWord, keyGenerationSlice.actions
setMnemonic,
setIsCopyPastedPhrase,
} = keyGenerationSlice.actions
export default keyGenerationSlice.reducer export default keyGenerationSlice.reducer