Merge pull request #41 from nimbus-gui/hn.fix-validator-onboarding
Hn.fix validator onboarding
This commit is contained in:
commit
9d28bf19c1
41
src/App.tsx
41
src/App.tsx
|
@ -21,6 +21,18 @@ import LogsPage from './pages/LogsPage/LogsPage'
|
||||||
import { ethereumRopsten, wcV2InitOptions, apiKey } from './constants'
|
import { ethereumRopsten, wcV2InitOptions, apiKey } from './constants'
|
||||||
import './App.css'
|
import './App.css'
|
||||||
|
|
||||||
|
//ValidatorOnboarding sub-routes
|
||||||
|
import Overview from './pages/ValidatorOnboarding/Overview/Overview'
|
||||||
|
import Advisories from './pages/ValidatorOnboarding/Advisories/Advisories'
|
||||||
|
import ValidatorSetup from './pages/ValidatorOnboarding/ValidatorSetup/ValidatorSetup/ValidatorSetup'
|
||||||
|
import ValidatorSetupInstall from './pages/ValidatorOnboarding/ValidatorSetup/ValidatorInstalling/ValidatorInstall'
|
||||||
|
import ConsensusSelection from './pages/ValidatorOnboarding/ValidatorSetup/ConsensusClient/ConsensusSelection'
|
||||||
|
import ActivationValidatorSetup from './pages/ValidatorOnboarding/ValidatorSetup/ValidatorActivation/ActivationValidatorSetup'
|
||||||
|
import ClientSetup from './pages/ValidatorOnboarding/ClientSetup/ClientSetup'
|
||||||
|
import KeyGeneration from './pages/ValidatorOnboarding/KeyGeneration/KeyGeneration'
|
||||||
|
import Deposit from './pages/ValidatorOnboarding/Deposit/Deposit'
|
||||||
|
import Activation from './pages/ValidatorOnboarding/Activation/Activation'
|
||||||
|
|
||||||
const injected = injectedModule()
|
const injected = injectedModule()
|
||||||
const walletConnect = walletConnectModule(wcV2InitOptions)
|
const walletConnect = walletConnectModule(wcV2InitOptions)
|
||||||
|
|
||||||
|
@ -55,10 +67,35 @@ const router = createBrowserRouter([
|
||||||
element: <PairDevice />,
|
element: <PairDevice />,
|
||||||
},
|
},
|
||||||
{ path: '/create-local-node', element: <CreateLocalNode /> },
|
{ path: '/create-local-node', element: <CreateLocalNode /> },
|
||||||
{ path: '/validator-onboarding', element: <ValidatorOnboarding /> },
|
{
|
||||||
|
path: '/validator-onboarding',
|
||||||
|
children: [
|
||||||
|
{ path: '', element: <Overview /> },
|
||||||
|
{ path: 'advisories', element: <Advisories /> },
|
||||||
|
{ path: 'validator-setup', element: <ValidatorSetup /> },
|
||||||
|
{ path: 'validator-setup-install', element: <ValidatorSetupInstall /> },
|
||||||
|
{ path: 'consensus-selection', element: <ConsensusSelection /> },
|
||||||
|
{
|
||||||
|
path: 'activation-validator-setup',
|
||||||
|
element: <ActivationValidatorSetup />,
|
||||||
|
},
|
||||||
|
{ path: 'client-setup', element: <ClientSetup /> },
|
||||||
|
{ path: 'key-generation', element: <KeyGeneration /> },
|
||||||
|
{ path: 'deposit', element: <Deposit /> },
|
||||||
|
{
|
||||||
|
path: 'activation',
|
||||||
|
element: <Activation />,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
element: <ValidatorOnboarding />,
|
||||||
|
},
|
||||||
{ path: '/dashboard', element: <Dashboard /> },
|
{ path: '/dashboard', element: <Dashboard /> },
|
||||||
{ path: '/logs', element: <LogsPage /> },
|
{ path: '/logs', element: <LogsPage /> },
|
||||||
{ path: '/validator-management', element: <ValidatorManagement /> },
|
{
|
||||||
|
path: '/validator-management',
|
||||||
|
|
||||||
|
element: <ValidatorManagement />,
|
||||||
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import ReactMarkdown from 'react-markdown'
|
import ReactMarkdown from 'react-markdown'
|
||||||
|
import styles from './../../../pages/ValidatorOnboarding/ValidatorSetup/ValidatorInstalling/InstallLayout.module.css'
|
||||||
import MarkdownLink from './MarkdownLink'
|
import MarkdownLink from './MarkdownLink'
|
||||||
|
|
||||||
type MarkdownProps = {
|
type MarkdownProps = {
|
||||||
|
@ -7,7 +7,13 @@ type MarkdownProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Markdown = ({ children }: MarkdownProps) => {
|
const Markdown = ({ children }: MarkdownProps) => {
|
||||||
return <ReactMarkdown children={children} components={{ a: MarkdownLink }} />
|
return (
|
||||||
|
<ReactMarkdown
|
||||||
|
children={children}
|
||||||
|
components={{ a: MarkdownLink }}
|
||||||
|
className={styles['markdown-text']}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Markdown
|
export default Markdown
|
||||||
|
|
|
@ -5,38 +5,11 @@ import Confetti from 'react-confetti'
|
||||||
|
|
||||||
import ActivationCard from './ActivationCard'
|
import ActivationCard from './ActivationCard'
|
||||||
import LinkWithArrow from '../../../components/General/LinkWithArrow'
|
import LinkWithArrow from '../../../components/General/LinkWithArrow'
|
||||||
|
import { useWindowSize } from '../../../hooks/useWindowSize'
|
||||||
|
|
||||||
type ActivationProps = {
|
const Activation = () => {
|
||||||
validatorsValue: string
|
|
||||||
executionSyncStatus1: {
|
|
||||||
text: string
|
|
||||||
isGaugeIncluded: boolean
|
|
||||||
gaugeColor: string
|
|
||||||
gaugeSynced: number
|
|
||||||
gaugeTotal: number
|
|
||||||
}
|
|
||||||
executionSyncStatus2: {
|
|
||||||
text: string
|
|
||||||
isGaugeIncluded: boolean
|
|
||||||
gaugeColor: string
|
|
||||||
gaugeSynced: number
|
|
||||||
gaugeTotal: number
|
|
||||||
}
|
|
||||||
currentAPRValue: string
|
|
||||||
estimatedActivationTimeValue: string
|
|
||||||
validatorQueueValue: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const Activation = ({
|
|
||||||
validatorsValue,
|
|
||||||
executionSyncStatus1,
|
|
||||||
executionSyncStatus2,
|
|
||||||
currentAPRValue,
|
|
||||||
estimatedActivationTimeValue,
|
|
||||||
validatorQueueValue,
|
|
||||||
}: ActivationProps) => {
|
|
||||||
const [showConfetti, setShowConfetti] = useState(true)
|
const [showConfetti, setShowConfetti] = useState(true)
|
||||||
|
const windowSize = useWindowSize()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
setShowConfetti(false)
|
setShowConfetti(false)
|
||||||
|
@ -61,22 +34,36 @@ const Activation = ({
|
||||||
Validators and are currently syncing your nodes.
|
Validators and are currently syncing your nodes.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
<YStack space={'$3'} marginTop={'25px'} width={'33%'}>
|
<YStack marginTop={'25px'}>
|
||||||
<XStack space={'$3'} justifyContent={'space-between'}>
|
<XStack
|
||||||
<ActivationCard text="Validators" value={validatorsValue} />
|
width="100%"
|
||||||
<ActivationCard {...executionSyncStatus1} />
|
flexWrap={windowSize.width < 780 ? 'wrap' : 'nowrap'}
|
||||||
<ActivationCard {...executionSyncStatus2} />
|
>
|
||||||
|
<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>
|
||||||
<XStack space={'$3'}>
|
<XStack
|
||||||
<ActivationCard text="Current APR" value={currentAPRValue} />
|
flexWrap={windowSize.width < 780 ? 'wrap' : 'nowrap'}
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
<ActivationCard text="Validator Queue" value="92603" />
|
||||||
<ActivationCard
|
<ActivationCard
|
||||||
text="Estimated Activation Time"
|
text="Estimated Activation Time"
|
||||||
value={estimatedActivationTimeValue}
|
value="32 Days"
|
||||||
/>
|
|
||||||
<ActivationCard
|
|
||||||
text="Validator Queue"
|
|
||||||
value={validatorQueueValue}
|
|
||||||
/>
|
/>
|
||||||
|
<ActivationCard text="Current APR" value="4.40%" />
|
||||||
</XStack>
|
</XStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|
|
@ -26,7 +26,8 @@ const ActivationCard = ({
|
||||||
border: '1px solid rgba(0, 0, 0, 0.15)',
|
border: '1px solid rgba(0, 0, 0, 0.15)',
|
||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
backgroundColor: '#FFF',
|
backgroundColor: '#FFF',
|
||||||
width: '100%',
|
flex: 1,
|
||||||
|
margin: '8px',
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{!isGaugeIncluded && (
|
{!isGaugeIncluded && (
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { Text } from '@status-im/components'
|
import { Text } from '@status-im/components'
|
||||||
import { Link } from 'react-router-dom'
|
import { Link } from 'react-router-dom'
|
||||||
import { Stack, YStack } from 'tamagui'
|
import { Stack, YStack } from 'tamagui'
|
||||||
|
import { useWindowSize } from '../../../hooks/useWindowSize'
|
||||||
|
|
||||||
type AdvisoriesContentProps = {
|
type AdvisoriesContentProps = {
|
||||||
title: string
|
title: string
|
||||||
|
@ -8,8 +9,9 @@ type AdvisoriesContentProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const AdvisoriesContent = ({ title, content }: AdvisoriesContentProps) => {
|
const AdvisoriesContent = ({ title, content }: AdvisoriesContentProps) => {
|
||||||
|
const windowSize = useWindowSize()
|
||||||
return (
|
return (
|
||||||
<YStack space={'$1'} style={{ width: '70%' }}>
|
<YStack space={'$1'} width={windowSize.width < 780 ? '100%' : '70%'}>
|
||||||
<Stack style={{ marginBottom: '5%' }}>
|
<Stack style={{ marginBottom: '5%' }}>
|
||||||
<Text size={27} weight={400}>
|
<Text size={27} weight={400}>
|
||||||
{title}
|
{title}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
width: auto;
|
|
||||||
}
|
}
|
||||||
.advisories-nav {
|
.advisories-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
|
@ -8,18 +8,17 @@ import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import { RootState } from '../../redux/store'
|
import { RootState } from '../../redux/store'
|
||||||
import LinkWithArrow from '../../components/General/LinkWithArrow'
|
import LinkWithArrow from '../../components/General/LinkWithArrow'
|
||||||
import {
|
import { setActiveStep } from '../../redux/ValidatorOnboarding/slice'
|
||||||
setActiveStep,
|
|
||||||
setSubStepValidatorSetup,
|
|
||||||
} from '../../redux/ValidatorOnboarding/slice'
|
|
||||||
import { KEYSTORE_FILES } from '../../constants'
|
import { KEYSTORE_FILES } from '../../constants'
|
||||||
import {
|
import {
|
||||||
setIsConfirmPhraseStage,
|
setIsConfirmPhraseStage,
|
||||||
setIsCopyPastedPhrase,
|
setIsCopyPastedPhrase,
|
||||||
setValidWords,
|
setValidWords,
|
||||||
} from '../../redux/ValidatorOnboarding/KeyGeneration/slice'
|
} from '../../redux/ValidatorOnboarding/KeyGeneration/slice'
|
||||||
|
import { useWindowSize } from '../../hooks/useWindowSize'
|
||||||
|
|
||||||
const ContinueButton = () => {
|
const ContinueButton = () => {
|
||||||
|
const windowSize = useWindowSize()
|
||||||
const [isDisabled, setIsDisabled] = useState(false)
|
const [isDisabled, setIsDisabled] = useState(false)
|
||||||
const {
|
const {
|
||||||
isCopyPastedPhrase,
|
isCopyPastedPhrase,
|
||||||
|
@ -33,24 +32,44 @@ const ContinueButton = () => {
|
||||||
const { activeStep, subStepValidatorSetup } = useSelector(
|
const { activeStep, subStepValidatorSetup } = useSelector(
|
||||||
(state: RootState) => state.validatorOnboarding,
|
(state: RootState) => state.validatorOnboarding,
|
||||||
)
|
)
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const pathToStepMap = {
|
||||||
|
'/validator-onboarding/': 0,
|
||||||
|
'/validator-onboarding/advisories': 1,
|
||||||
|
'/validator-onboarding/validator-setup': 2,
|
||||||
|
'/validator-onboarding/validator-setup-install': 3,
|
||||||
|
'/validator-onboarding/consensus-selection': 4,
|
||||||
|
'/validator-onboarding/activation-validator-setup': 5,
|
||||||
|
'/validator-onboarding/client-setup': 6,
|
||||||
|
'/validator-onboarding/key-generation': 7,
|
||||||
|
'/validator-onboarding/deposit': 8,
|
||||||
|
'/validator-onboarding/activation': 9,
|
||||||
|
}
|
||||||
|
dispatch(
|
||||||
|
setActiveStep(
|
||||||
|
pathToStepMap[location.pathname as keyof typeof pathToStepMap] || 0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
const { isValidatorSet } = useSelector(
|
const { isValidatorSet } = useSelector(
|
||||||
(state: RootState) => state.validatorSetup,
|
(state: RootState) => state.validatorSetup,
|
||||||
)
|
)
|
||||||
|
|
||||||
const dispatch = useDispatch()
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const isActivationValScreen = activeStep === 3 && subStepValidatorSetup === 3
|
|
||||||
|
const isActivationValScreen = activeStep === 5
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const getDisabledButton = () => {
|
const getDisabledButton = () => {
|
||||||
if (activeStep === 4 && isConfirmPhraseStage) {
|
if (activeStep === 7 && isConfirmPhraseStage) {
|
||||||
if (
|
if (
|
||||||
validWords.some(w => w === false) ||
|
validWords.some(w => w === false) ||
|
||||||
generatedMnemonic.some((w, i) => w !== mnemonic[i])
|
generatedMnemonic.some((w, i) => w !== mnemonic[i])
|
||||||
) {
|
) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
} else if (activeStep === 3 && !isValidatorSet) {
|
} else if (activeStep === 6 && !isValidatorSet) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
@ -66,22 +85,10 @@ const ContinueButton = () => {
|
||||||
isValidatorSet,
|
isValidatorSet,
|
||||||
])
|
])
|
||||||
|
|
||||||
const handleStep1 = () => {
|
const handleRecoveryMechanism = () => {
|
||||||
dispatch(setActiveStep(activeStep + 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleStep2 = () => {
|
|
||||||
if (subStepValidatorSetup === 3) {
|
|
||||||
return dispatch(setActiveStep(activeStep + 1))
|
|
||||||
}
|
|
||||||
dispatch(setSubStepValidatorSetup(subStepValidatorSetup + 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleStep4 = () => {
|
|
||||||
if (!isConfirmPhraseStage && recoveryMechanism === KEYSTORE_FILES) {
|
if (!isConfirmPhraseStage && recoveryMechanism === KEYSTORE_FILES) {
|
||||||
return dispatch(setActiveStep(activeStep + 1))
|
return dispatch(setActiveStep(activeStep + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isConfirmPhraseStage) {
|
if (!isConfirmPhraseStage) {
|
||||||
return dispatch(setIsConfirmPhraseStage(true))
|
return dispatch(setIsConfirmPhraseStage(true))
|
||||||
}
|
}
|
||||||
|
@ -102,26 +109,43 @@ const ContinueButton = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const continueHandler = () => {
|
const continueHandler = () => {
|
||||||
if (activeStep === 1) {
|
let nextPath
|
||||||
handleStep1()
|
if (activeStep === 0) nextPath = '/validator-onboarding/advisories'
|
||||||
} else if (activeStep === 2) {
|
else if (activeStep === 1)
|
||||||
handleStep2()
|
nextPath = '/validator-onboarding/validator-setup'
|
||||||
} else if (activeStep === 4) {
|
else if (activeStep === 2)
|
||||||
handleStep4()
|
nextPath = '/validator-onboarding/validator-setup-install'
|
||||||
} else {
|
else if (activeStep === 3)
|
||||||
if (activeStep < 6) {
|
nextPath = '/validator-onboarding/consensus-selection'
|
||||||
dispatch(setActiveStep(activeStep + 1))
|
else if (activeStep === 4)
|
||||||
|
nextPath = '/validator-onboarding/activation-validator-setup'
|
||||||
|
else if (activeStep === 5) {
|
||||||
|
nextPath = '/validator-onboarding/client-setup'
|
||||||
|
} else if (activeStep === 6) {
|
||||||
|
nextPath = '/validator-onboarding/key-generation'
|
||||||
|
} else if (activeStep === 7) {
|
||||||
|
if (isConfirmPhraseStage) {
|
||||||
|
nextPath = '/validator-onboarding/deposit'
|
||||||
} else {
|
} else {
|
||||||
navigate('/dashboard')
|
nextPath = '/validator-onboarding/key-generation'
|
||||||
}
|
}
|
||||||
}
|
handleRecoveryMechanism()
|
||||||
|
} else if (activeStep === 8) nextPath = '/validator-onboarding/activation'
|
||||||
|
else if (activeStep === 9) nextPath = '/dashboard'
|
||||||
|
else nextPath = '/validator-onboarding/'
|
||||||
|
|
||||||
|
navigate(nextPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<XStack
|
<XStack
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
justifyContent: isActivationValScreen ? 'space-between' : 'end',
|
justifyContent: isActivationValScreen
|
||||||
|
? 'space-between'
|
||||||
|
: windowSize.width < 560
|
||||||
|
? 'start'
|
||||||
|
: 'end',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
zIndex: 1000,
|
zIndex: 1000,
|
||||||
marginTop: '21px',
|
marginTop: '21px',
|
||||||
|
@ -145,7 +169,7 @@ const ContinueButton = () => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Button onPress={continueHandler} size={40} disabled={isDisabled}>
|
<Button onPress={continueHandler} size={40} disabled={isDisabled}>
|
||||||
{activeStep < 6 ? 'Continue' : 'Continue to Dashboard'}
|
{activeStep < 9 ? 'Continue' : 'Continue to Dashboard'}
|
||||||
</Button>
|
</Button>
|
||||||
</XStack>
|
</XStack>
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
import type { Meta, StoryObj } from '@storybook/react'
|
|
||||||
|
|
||||||
import FormStepper from './FormStepper'
|
|
||||||
|
|
||||||
const meta = {
|
|
||||||
title: 'ValidatorOnboarding/FormStepper',
|
|
||||||
component: FormStepper,
|
|
||||||
parameters: {
|
|
||||||
layout: 'centered',
|
|
||||||
},
|
|
||||||
tags: ['autodocs'],
|
|
||||||
argTypes: {
|
|
||||||
activeStep: {
|
|
||||||
options: [0, 1, 2, 3, 4, 5],
|
|
||||||
control: { type: 'radio' },
|
|
||||||
defaultValue: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} satisfies Meta<typeof FormStepper>
|
|
||||||
|
|
||||||
export default meta
|
|
||||||
type Story = StoryObj<typeof meta>
|
|
||||||
|
|
||||||
export const OverviewActive: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const AdvisoriesActive: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: 1,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ClientSetupActive: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: 2,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ValidatorSetupActive: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: 3,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const KeyGenerationActive: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: 4,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ActivationActive: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: 5,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const NoActiveStep: Story = {
|
|
||||||
args: {
|
|
||||||
activeStep: -1,
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -1,7 +1,5 @@
|
||||||
import { Stepper, Step } from 'react-form-stepper'
|
import { Stepper, Step } from 'react-form-stepper'
|
||||||
import { useDispatch } from 'react-redux'
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
|
||||||
import { setActiveStep } from '../../../redux/ValidatorOnboarding/slice'
|
|
||||||
import { FORM_STEPS } from '../../../constants'
|
import { FORM_STEPS } from '../../../constants'
|
||||||
import { useWindowSize } from '../../../hooks/useWindowSize'
|
import { useWindowSize } from '../../../hooks/useWindowSize'
|
||||||
import './FormStepper.css'
|
import './FormStepper.css'
|
||||||
|
@ -11,9 +9,22 @@ type FormStepperProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const FormStepper = ({ activeStep }: FormStepperProps) => {
|
const FormStepper = ({ activeStep }: FormStepperProps) => {
|
||||||
const dispatch = useDispatch()
|
const navigate = useNavigate()
|
||||||
const windowSize = useWindowSize()
|
const windowSize = useWindowSize()
|
||||||
|
|
||||||
|
const stepToUrlMap = [
|
||||||
|
'/validator-onboarding/',
|
||||||
|
'/validator-onboarding/advisories',
|
||||||
|
'/validator-onboarding/validator-setup',
|
||||||
|
'/validator-onboarding/validator-setup-install',
|
||||||
|
'/validator-onboarding/consensus-selection',
|
||||||
|
'/validator-onboarding/activation-validator-setup',
|
||||||
|
'/validator-onboarding/client-setup',
|
||||||
|
'/validator-onboarding/key-generation',
|
||||||
|
'/validator-onboarding/deposit',
|
||||||
|
'/validator-onboarding/activation',
|
||||||
|
]
|
||||||
|
|
||||||
const getIsStepVisible = (
|
const getIsStepVisible = (
|
||||||
index: number,
|
index: number,
|
||||||
stepsBefore: number,
|
stepsBefore: number,
|
||||||
|
@ -23,7 +34,6 @@ const FormStepper = ({ activeStep }: FormStepperProps) => {
|
||||||
let start = activeStep - stepsBefore
|
let start = activeStep - stepsBefore
|
||||||
let end = activeStep + stepsAfter
|
let end = activeStep + stepsAfter
|
||||||
|
|
||||||
// active step is near the start or end
|
|
||||||
if (start < 0) {
|
if (start < 0) {
|
||||||
end -= start
|
end -= start
|
||||||
start = 0
|
start = 0
|
||||||
|
@ -41,23 +51,27 @@ const FormStepper = ({ activeStep }: FormStepperProps) => {
|
||||||
|
|
||||||
const isStepVisible = (index: number) => {
|
const isStepVisible = (index: number) => {
|
||||||
if (windowSize.width < 774) {
|
if (windowSize.width < 774) {
|
||||||
return getIsStepVisible(index, 1, 1) // 3 steps (1 before, 1 after)
|
return getIsStepVisible(index, 1, 1)
|
||||||
} else if (windowSize.width < 963) {
|
} else if (windowSize.width < 963) {
|
||||||
return getIsStepVisible(index, 1, 2) // 4 steps
|
return getIsStepVisible(index, 1, 2)
|
||||||
} else if (windowSize.width < 1183) {
|
} else if (windowSize.width < 1183) {
|
||||||
return getIsStepVisible(index, 1, 3) // 5 steps
|
return getIsStepVisible(index, 1, 3)
|
||||||
} else if (windowSize.width < 1300) {
|
} else if (windowSize.width < 1300) {
|
||||||
return getIsStepVisible(index, 2, 3) // 6 steps
|
return getIsStepVisible(index, 2, 3)
|
||||||
} else {
|
} else {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeStepOnClickHandler = (index: number) => {
|
const changeStepOnClickHandler = (index: number) => {
|
||||||
if (activeStep > index) {
|
const path = stepToUrlMap[index]
|
||||||
dispatch(setActiveStep(index))
|
if (path && index < activeStep) {
|
||||||
|
navigate(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (activeStep > 1) {
|
||||||
|
activeStep = activeStep < 6 ? 2 : activeStep - 3
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stepper
|
<Stepper
|
||||||
|
@ -85,12 +99,18 @@ const FormStepper = ({ activeStep }: FormStepperProps) => {
|
||||||
completed={activeStep > originalIndex - 1}
|
completed={activeStep > originalIndex - 1}
|
||||||
data-subtitle={step.subtitle}
|
data-subtitle={step.subtitle}
|
||||||
data-step={step.label}
|
data-step={step.label}
|
||||||
|
style={
|
||||||
|
originalIndex === activeStep
|
||||||
|
? { backgroundColor: stepStyle.currentBgColor }
|
||||||
|
: {}
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Stepper>
|
</Stepper>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const stepStyle = {
|
const stepStyle = {
|
||||||
// For default dots:
|
// For default dots:
|
||||||
inactiveBgColor: '#FFFFFF',
|
inactiveBgColor: '#FFFFFF',
|
||||||
|
@ -107,9 +127,10 @@ const stepStyle = {
|
||||||
inactiveTextColor: '#000000',
|
inactiveTextColor: '#000000',
|
||||||
size: '28px',
|
size: '28px',
|
||||||
circleFontSize: '0px',
|
circleFontSize: '0px',
|
||||||
labelFontSize: '14px',
|
labelFontSize: '13px',
|
||||||
borderRadius: '50%',
|
borderRadius: '50%',
|
||||||
fontWeight: 700,
|
fontWeight: 700,
|
||||||
|
currentBgColor: '#808080',
|
||||||
}
|
}
|
||||||
|
|
||||||
const customConnectorStyle = {
|
const customConnectorStyle = {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { YStack } from 'tamagui'
|
import { YStack, Stack } from 'tamagui'
|
||||||
import { Text } from '@status-im/components'
|
import { Text } from '@status-im/components'
|
||||||
|
|
||||||
import OverviewCard from './OverviewCard'
|
import OverviewCard from './OverviewCard'
|
||||||
|
@ -12,10 +12,17 @@ const Overview = () => {
|
||||||
imgHeight="250%"
|
imgHeight="250%"
|
||||||
rightImageSrc="./background-images/sync-status-background.png"
|
rightImageSrc="./background-images/sync-status-background.png"
|
||||||
>
|
>
|
||||||
<YStack space={'$5'} marginTop={'2rem'} width="100%">
|
<YStack
|
||||||
<Text size={27} weight={'semibold'}>
|
space={'$5'}
|
||||||
Overview
|
marginTop={'2rem'}
|
||||||
</Text>
|
marginBottom={'2rem'}
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
|
<Stack marginBottom={'$2'}>
|
||||||
|
<Text size={27} weight={'semibold'}>
|
||||||
|
Overview
|
||||||
|
</Text>
|
||||||
|
</Stack>
|
||||||
<Text size={19}>
|
<Text size={19}>
|
||||||
Becoming a validator is a big responsibility with important
|
Becoming a validator is a big responsibility with important
|
||||||
preparation steps. Only start the deposit process when you're ready.
|
preparation steps. Only start the deposit process when you're ready.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
width: 250%;
|
width: 250%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overviewCard {
|
.overviewCard {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
|
@ -19,6 +20,5 @@
|
||||||
}
|
}
|
||||||
.overviewCard {
|
.overviewCard {
|
||||||
width: 35%;
|
width: 35%;
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,23 +4,15 @@ import { useSelector } from 'react-redux'
|
||||||
import { RootState } from '../../redux/store'
|
import { RootState } from '../../redux/store'
|
||||||
import FormStepper from './FormStepper/FormStepper'
|
import FormStepper from './FormStepper/FormStepper'
|
||||||
import Titles from '../../components/General/Titles'
|
import Titles from '../../components/General/Titles'
|
||||||
import Overview from './Overview/Overview'
|
|
||||||
import KeyGeneration from './KeyGeneration/KeyGeneration'
|
|
||||||
import Activation from './Activation/Activation'
|
|
||||||
import ValidatorBoxWrapper from './ValidatorBoxWrapper/ValidatorBoxWrapper'
|
import ValidatorBoxWrapper from './ValidatorBoxWrapper/ValidatorBoxWrapper'
|
||||||
import ClientSetup from './ClientSetup/ClientSetup'
|
|
||||||
import ConsensusSelection from './ValidatorSetup/ConsensusClient/ConsensusSelection'
|
|
||||||
import Advisories from './Advisories/Advisories'
|
|
||||||
import ValidatorSetup from './ValidatorSetup/ValidatorSetup/ValidatorSetup'
|
|
||||||
import ValidatorSetupInstall from './ValidatorSetup/ValidatorInstalling/ValidatorInstall'
|
|
||||||
import ContinueButton from './ContinueButton'
|
import ContinueButton from './ContinueButton'
|
||||||
import ActivationValidatorSetup from './ValidatorSetup/ValidatorActivation/ActivationValidatorSetup'
|
|
||||||
import Deposit from './Deposit/Deposit'
|
|
||||||
import { useWindowSize } from '../../hooks/useWindowSize'
|
import { useWindowSize } from '../../hooks/useWindowSize'
|
||||||
import styles from './layoutGradient.module.css'
|
import styles from './layoutGradient.module.css'
|
||||||
|
import { Outlet } from 'react-router-dom'
|
||||||
|
|
||||||
const ValidatorOnboarding = () => {
|
const ValidatorOnboarding = () => {
|
||||||
const { activeStep, subStepValidatorSetup } = useSelector(
|
const { activeStep } = useSelector(
|
||||||
(state: RootState) => state.validatorOnboarding,
|
(state: RootState) => state.validatorOnboarding,
|
||||||
)
|
)
|
||||||
const windowSize = useWindowSize()
|
const windowSize = useWindowSize()
|
||||||
|
@ -42,45 +34,7 @@ const ValidatorOnboarding = () => {
|
||||||
/>
|
/>
|
||||||
<FormStepper activeStep={activeStep} />
|
<FormStepper activeStep={activeStep} />
|
||||||
<ValidatorBoxWrapper>
|
<ValidatorBoxWrapper>
|
||||||
{activeStep === 0 && <Overview />}
|
<Outlet />
|
||||||
{activeStep === 1 && <Advisories />}
|
|
||||||
{activeStep === 2 && subStepValidatorSetup === 0 && (
|
|
||||||
<ValidatorSetup />
|
|
||||||
)}
|
|
||||||
{activeStep === 2 && subStepValidatorSetup === 1 && (
|
|
||||||
<ValidatorSetupInstall />
|
|
||||||
)}
|
|
||||||
{activeStep === 2 && subStepValidatorSetup === 2 && (
|
|
||||||
<ConsensusSelection />
|
|
||||||
)}
|
|
||||||
{activeStep === 2 && subStepValidatorSetup === 3 && (
|
|
||||||
<ActivationValidatorSetup />
|
|
||||||
)}
|
|
||||||
{activeStep === 3 && <ClientSetup />}
|
|
||||||
{activeStep === 4 && <KeyGeneration />}
|
|
||||||
{activeStep === 5 && <Deposit />}
|
|
||||||
{activeStep === 6 && (
|
|
||||||
<Activation
|
|
||||||
validatorsValue="4"
|
|
||||||
executionSyncStatus1={{
|
|
||||||
text: 'Execution Sync Status',
|
|
||||||
isGaugeIncluded: true,
|
|
||||||
gaugeColor: '$blue',
|
|
||||||
gaugeSynced: 123.524,
|
|
||||||
gaugeTotal: 172.503,
|
|
||||||
}}
|
|
||||||
executionSyncStatus2={{
|
|
||||||
text: 'Execution Sync Status',
|
|
||||||
isGaugeIncluded: true,
|
|
||||||
gaugeColor: '$red',
|
|
||||||
gaugeSynced: 123.524,
|
|
||||||
gaugeTotal: 172.503,
|
|
||||||
}}
|
|
||||||
currentAPRValue="4.40%"
|
|
||||||
estimatedActivationTimeValue="32 Days"
|
|
||||||
validatorQueueValue="92603"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ValidatorBoxWrapper>
|
</ValidatorBoxWrapper>
|
||||||
<ContinueButton />
|
<ContinueButton />
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Stack, YStack } from 'tamagui'
|
||||||
import { Text } from '@status-im/components'
|
import { Text } from '@status-im/components'
|
||||||
|
|
||||||
import Icon from '../../../../components/General/Icon'
|
import Icon from '../../../../components/General/Icon'
|
||||||
|
import { useWindowSize } from '../../../../hooks/useWindowSize'
|
||||||
|
|
||||||
type ConsensusClientCardProps = {
|
type ConsensusClientCardProps = {
|
||||||
name: string
|
name: string
|
||||||
|
@ -9,6 +10,7 @@ type ConsensusClientCardProps = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConsensusClientCard = ({ name, icon }: ConsensusClientCardProps) => {
|
const ConsensusClientCard = ({ name, icon }: ConsensusClientCardProps) => {
|
||||||
|
const windowSize = useWindowSize()
|
||||||
return (
|
return (
|
||||||
<YStack
|
<YStack
|
||||||
style={{
|
style={{
|
||||||
|
@ -16,8 +18,9 @@ const ConsensusClientCard = ({ name, icon }: ConsensusClientCardProps) => {
|
||||||
border: '1px solid #2A4AF5',
|
border: '1px solid #2A4AF5',
|
||||||
borderRadius: '16px',
|
borderRadius: '16px',
|
||||||
padding: '12px 16px',
|
padding: '12px 16px',
|
||||||
width: '29%',
|
|
||||||
cursor: 'pointer',
|
cursor: 'pointer',
|
||||||
|
minWidth: '250px',
|
||||||
|
width: windowSize.width < 780 ? '100%' : 'auto',
|
||||||
}}
|
}}
|
||||||
space={'$8'}
|
space={'$8'}
|
||||||
>
|
>
|
||||||
|
|
|
@ -3,8 +3,8 @@ import { InfoBadgeIcon } from '@status-im/icons'
|
||||||
import { Text } from '@status-im/components'
|
import { Text } from '@status-im/components'
|
||||||
|
|
||||||
import StandardGauge from '../../../../components/Charts/StandardGauge'
|
import StandardGauge from '../../../../components/Charts/StandardGauge'
|
||||||
import BorderBox from '../../../../components/General/BorderBox'
|
|
||||||
import { formatNumbersWithComa } from '../../../../utilities'
|
import { formatNumbersWithComa } from '../../../../utilities'
|
||||||
|
import { useWindowSize } from '../../../../hooks/useWindowSize'
|
||||||
|
|
||||||
type ConsensusGaugeCardProps = {
|
type ConsensusGaugeCardProps = {
|
||||||
synced: number
|
synced: number
|
||||||
|
@ -19,43 +19,56 @@ const ConsensusGaugeCard = ({
|
||||||
title,
|
title,
|
||||||
color,
|
color,
|
||||||
}: ConsensusGaugeCardProps) => {
|
}: ConsensusGaugeCardProps) => {
|
||||||
|
const windowSize = useWindowSize()
|
||||||
return (
|
return (
|
||||||
<BorderBox style={{ borderRadius: '10.1px', borderWidth: '0.5px' }}>
|
<Stack
|
||||||
<XStack space={'$2'} alignItems="center">
|
style={{
|
||||||
<Stack
|
border: '1px solid #DCE0E5',
|
||||||
style={{
|
borderRadius: '10px',
|
||||||
height: '35px',
|
padding: '6px 12px',
|
||||||
width: '35px',
|
borderWidth: '0.5px',
|
||||||
}}
|
width: windowSize.width < 580 ? '100%' : 'auto',
|
||||||
>
|
height: '100%',
|
||||||
<StandardGauge
|
}}
|
||||||
data={[
|
>
|
||||||
{
|
<XStack space={'$2'} alignItems="center" justifyContent="space-between">
|
||||||
id: title,
|
<XStack space={'$3'}>
|
||||||
label: title,
|
<Stack
|
||||||
value: synced,
|
style={{
|
||||||
color: color,
|
height: '35px',
|
||||||
},
|
width: '35px',
|
||||||
{
|
}}
|
||||||
id: 'free',
|
space={'$2'}
|
||||||
label: 'free',
|
>
|
||||||
value: total - synced || 1,
|
<StandardGauge
|
||||||
color: '#E7EAEE',
|
data={[
|
||||||
},
|
{
|
||||||
]}
|
id: title,
|
||||||
/>
|
label: title,
|
||||||
</Stack>
|
value: synced,
|
||||||
<YStack>
|
color: color,
|
||||||
<Text size={11} color="#84888e" weight={'semibold'}>
|
},
|
||||||
{title}
|
{
|
||||||
</Text>
|
id: 'free',
|
||||||
<Text size={15} weight={'semibold'}>
|
label: 'free',
|
||||||
{formatNumbersWithComa(synced)} / {formatNumbersWithComa(total)}
|
value: total - synced || 1,
|
||||||
</Text>
|
color: '#E7EAEE',
|
||||||
</YStack>
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
|
<YStack>
|
||||||
|
<Text size={11} color="#84888e" weight={'semibold'}>
|
||||||
|
{title}
|
||||||
|
</Text>
|
||||||
|
<Text size={15} weight={'semibold'}>
|
||||||
|
{formatNumbersWithComa(synced)} / {formatNumbersWithComa(total)}
|
||||||
|
</Text>
|
||||||
|
</YStack>
|
||||||
|
</XStack>
|
||||||
<InfoBadgeIcon size={20} color="#A1ABBD" />
|
<InfoBadgeIcon size={20} color="#A1ABBD" />
|
||||||
</XStack>
|
</XStack>
|
||||||
</BorderBox>
|
</Stack>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import ConsensusGaugeCard from './ConsensusGaugeCard'
|
||||||
import ConsensusClientCard from './ConsensusClientCard'
|
import ConsensusClientCard from './ConsensusClientCard'
|
||||||
import LinkWithArrow from '../../../../components/General/LinkWithArrow'
|
import LinkWithArrow from '../../../../components/General/LinkWithArrow'
|
||||||
import { RootState } from '../../../../redux/store'
|
import { RootState } from '../../../../redux/store'
|
||||||
|
import { useWindowSize } from '../../../../hooks/useWindowSize'
|
||||||
|
|
||||||
const clientIcons = {
|
const clientIcons = {
|
||||||
Nethermind: '/icons/nethermind-circle.png',
|
Nethermind: '/icons/nethermind-circle.png',
|
||||||
|
@ -17,6 +18,7 @@ const clientIcons = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConsensusSelection = () => {
|
const ConsensusSelection = () => {
|
||||||
|
const windowSize = useWindowSize()
|
||||||
const selectedClient = useSelector(
|
const selectedClient = useSelector(
|
||||||
(state: RootState) => state.execClient.selectedClient,
|
(state: RootState) => state.execClient.selectedClient,
|
||||||
) as 'Nethermind' | 'Besu' | 'Geth' | 'Erigon' | 'Nimbus'
|
) as 'Nethermind' | 'Besu' | 'Geth' | 'Erigon' | 'Nimbus'
|
||||||
|
@ -37,9 +39,14 @@ const ConsensusSelection = () => {
|
||||||
flexWrap="wrap"
|
flexWrap="wrap"
|
||||||
>
|
>
|
||||||
<Text size={27} weight={'semibold'}>
|
<Text size={27} weight={'semibold'}>
|
||||||
Validator Setup
|
Client Setup
|
||||||
</Text>
|
</Text>
|
||||||
<XStack space={'$2'} flexWrap="wrap">
|
<XStack
|
||||||
|
space={'$2'}
|
||||||
|
flexWrap={windowSize.width < 735 ? 'wrap' : 'nowrap'}
|
||||||
|
marginTop={windowSize.width < 735 ? '20px' : 0}
|
||||||
|
width={windowSize.width < 580 ? '100%' : 'auto'}
|
||||||
|
>
|
||||||
<PairedDeviceCard />
|
<PairedDeviceCard />
|
||||||
|
|
||||||
<ConsensusGaugeCard
|
<ConsensusGaugeCard
|
||||||
|
@ -76,7 +83,7 @@ const ConsensusSelection = () => {
|
||||||
|
|
||||||
<XStack space={'$8'} flexWrap="wrap">
|
<XStack space={'$8'} flexWrap="wrap">
|
||||||
<ConsensusClientCard name={clients[0].name} icon={clients[0].icon} />
|
<ConsensusClientCard name={clients[0].name} icon={clients[0].icon} />
|
||||||
<YStack width={'67%'} maxWidth="550px" space={'$4'}>
|
<YStack width={windowSize.width < 780 ? '100%' : '70%'} space={'$4'}>
|
||||||
<Text size={19}>The resource efficient Ethereum Clients.</Text>
|
<Text size={19}>The resource efficient Ethereum Clients.</Text>
|
||||||
<Text size={15}>
|
<Text size={15}>
|
||||||
{selectedClient} is a client implementation for both execution and
|
{selectedClient} is a client implementation for both execution and
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import { XStack, YStack } from 'tamagui'
|
import { XStack, YStack } from 'tamagui'
|
||||||
import { InfoBadgeIcon } from '@status-im/icons'
|
import { InfoBadgeIcon } from '@status-im/icons'
|
||||||
import { Avatar, Text } from '@status-im/components'
|
import { Avatar, Text } from '@status-im/components'
|
||||||
|
import { useWindowSize } from '../../../../hooks/useWindowSize'
|
||||||
|
|
||||||
const PairedDeviceCard = () => {
|
const PairedDeviceCard = () => {
|
||||||
|
const windowSize = useWindowSize()
|
||||||
return (
|
return (
|
||||||
<XStack
|
<XStack
|
||||||
space={'$7'}
|
space={'$7'}
|
||||||
|
@ -10,10 +12,13 @@ const PairedDeviceCard = () => {
|
||||||
padding: '6px 12px',
|
padding: '6px 12px',
|
||||||
border: '1px solid #DCE0E5',
|
border: '1px solid #DCE0E5',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
|
marginBottom: '20px',
|
||||||
|
width: windowSize.width < 580 ? '100%' : 'auto',
|
||||||
}}
|
}}
|
||||||
|
justifyContent="space-between"
|
||||||
alignItems={'center'}
|
alignItems={'center'}
|
||||||
>
|
>
|
||||||
<XStack space={'$3'} alignItems={'center'}>
|
<XStack space={'$3'}>
|
||||||
<Avatar
|
<Avatar
|
||||||
backgroundColor="pink"
|
backgroundColor="pink"
|
||||||
type="icon"
|
type="icon"
|
||||||
|
|
|
@ -4,10 +4,11 @@ import { Text } from '@status-im/components'
|
||||||
import Confetti from 'react-confetti'
|
import Confetti from 'react-confetti'
|
||||||
|
|
||||||
import ActivationCard from '../../Activation/ActivationCard'
|
import ActivationCard from '../../Activation/ActivationCard'
|
||||||
|
import { useWindowSize } from '../../../../hooks/useWindowSize'
|
||||||
|
|
||||||
const ActivationValidatorSetup = () => {
|
const ActivationValidatorSetup = () => {
|
||||||
const [showConfetti, setShowConfetti] = useState(true)
|
const [showConfetti, setShowConfetti] = useState(true)
|
||||||
|
const windowSize = useWindowSize()
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
setShowConfetti(false)
|
setShowConfetti(false)
|
||||||
|
@ -19,7 +20,7 @@ const ActivationValidatorSetup = () => {
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack style={styles.confettiContainer} width={'100%'} minHeight={'65vh'}>
|
<Stack style={styles.confettiContainer} minHeight={'65vh'}>
|
||||||
{showConfetti && <Confetti style={styles.confettiCanvas} />}
|
{showConfetti && <Confetti style={styles.confettiCanvas} />}
|
||||||
<YStack style={{ padding: '26px 32px' }}>
|
<YStack style={{ padding: '26px 32px' }}>
|
||||||
<YStack space={'$5'}>
|
<YStack space={'$5'}>
|
||||||
|
@ -34,8 +35,11 @@ const ActivationValidatorSetup = () => {
|
||||||
making a deposit.
|
making a deposit.
|
||||||
</Text>
|
</Text>
|
||||||
</Stack>
|
</Stack>
|
||||||
<YStack space={'$3'} marginTop={'25px'} width={'33%'}>
|
<YStack marginTop={'25px'}>
|
||||||
<XStack width={'151%'} space={'$3'}>
|
<XStack
|
||||||
|
width="100%"
|
||||||
|
flexWrap={windowSize.width < 780 ? 'wrap' : 'nowrap'}
|
||||||
|
>
|
||||||
<ActivationCard
|
<ActivationCard
|
||||||
text="Execution Sync Status"
|
text="Execution Sync Status"
|
||||||
isGaugeIncluded={true}
|
isGaugeIncluded={true}
|
||||||
|
@ -51,7 +55,10 @@ const ActivationValidatorSetup = () => {
|
||||||
gaugeTotal={172.503}
|
gaugeTotal={172.503}
|
||||||
/>
|
/>
|
||||||
</XStack>
|
</XStack>
|
||||||
<XStack space={'$3'}>
|
<XStack
|
||||||
|
flexWrap={windowSize.width < 780 ? 'wrap' : 'nowrap'}
|
||||||
|
width="100%"
|
||||||
|
>
|
||||||
<ActivationCard text="Validator Queue" value="92603" />
|
<ActivationCard text="Validator Queue" value="92603" />
|
||||||
<ActivationCard
|
<ActivationCard
|
||||||
text="Estimated Activation Time"
|
text="Estimated Activation Time"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
.osCardsContainer {
|
.os-cards-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
display: grid;
|
display: grid;
|
||||||
|
@ -7,36 +7,45 @@
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
}
|
}
|
||||||
|
|
||||||
.osCard {
|
.os-card {
|
||||||
border: 1px solid rgba(0, 0, 0, 0.15);
|
border: 1px solid rgba(0, 0, 0, 0.15);
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
padding: 12px 16px;
|
padding: 12px 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
.markdown-text {
|
||||||
.osCardSelected {
|
overflow-x: auto;
|
||||||
|
width: 100%;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.os-card-selected {
|
||||||
background-color: #2a4af50d;
|
background-color: #2a4af50d;
|
||||||
border: 1px solid #2a4af566;
|
border: 1px solid #2a4af566;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
.osCardsContainer {
|
.os-cards-container {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
.osCard:nth-child(3) {
|
.os-card:nth-child(3) {
|
||||||
width: 205%;
|
width: 205%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 750px) {
|
@media (max-width: 850px) {
|
||||||
.osCardsContainer {
|
.os-cards-container {
|
||||||
grid-template-columns: repeat(1, 1fr);
|
grid-template-columns: repeat(1, 1fr);
|
||||||
}
|
}
|
||||||
.osCard {
|
.os-card {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.osCard:nth-child(3) {
|
.os-card:nth-child(3) {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,13 +14,15 @@ type OSCardsProps = {
|
||||||
}
|
}
|
||||||
const OSCards = ({ selectedOS, handleOSCardClick }: OSCardsProps) => {
|
const OSCards = ({ selectedOS, handleOSCardClick }: OSCardsProps) => {
|
||||||
return (
|
return (
|
||||||
<div className={styles.osCardsContainer}>
|
<div className={styles['os-cards-container']}>
|
||||||
{cards.map(card => (
|
{cards.map(card => (
|
||||||
<div
|
<div
|
||||||
key={card.name}
|
key={card.name}
|
||||||
className={`${styles.osCard} ${
|
className={
|
||||||
selectedOS === card.name ? styles.osCardSelected : ''
|
selectedOS === card.name
|
||||||
}`}
|
? styles['os-card-selected']
|
||||||
|
: styles['os-card']
|
||||||
|
}
|
||||||
onClick={() => handleOSCardClick(card.name)}
|
onClick={() => handleOSCardClick(card.name)}
|
||||||
>
|
>
|
||||||
<OSCard key={card.name} icon={card.icon} name={card.name} />
|
<OSCard key={card.name} icon={card.icon} name={card.name} />
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { Stack, YStack } from 'tamagui'
|
import { Stack, YStack } from 'tamagui'
|
||||||
import { Text } from '@status-im/components'
|
import { Text } from '@status-im/components'
|
||||||
import { useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
|
||||||
import { RootState } from '../../../../redux/store'
|
import { RootState } from '../../../../redux/store'
|
||||||
|
@ -8,21 +8,56 @@ import { DOCUMENTATIONS } from './documentations'
|
||||||
import { MAC } from '../../../../constants'
|
import { MAC } from '../../../../constants'
|
||||||
import OSCards from './OSCards'
|
import OSCards from './OSCards'
|
||||||
import Markdown from '../../../../components/General/Markdown/Markdown'
|
import Markdown from '../../../../components/General/Markdown/Markdown'
|
||||||
|
import { setPinnedMessage } from '../../../../redux/PinnedMessage/slice'
|
||||||
|
|
||||||
|
function extractBashCommands(documentation: any) {
|
||||||
|
const bashCommandRegex = /```bash\n([\s\S]*?)\n```/g
|
||||||
|
const matches = []
|
||||||
|
let match
|
||||||
|
|
||||||
|
while ((match = bashCommandRegex.exec(documentation)) !== null) {
|
||||||
|
matches.push(match[1])
|
||||||
|
}
|
||||||
|
return matches.join('\n\n')
|
||||||
|
}
|
||||||
|
|
||||||
const ValidatorSetupInstall = () => {
|
const ValidatorSetupInstall = () => {
|
||||||
|
const dispatch = useDispatch()
|
||||||
const [selectedOS, setSelectedOS] = useState(MAC)
|
const [selectedOS, setSelectedOS] = useState(MAC)
|
||||||
const selectedClient = useSelector(
|
const selectedClient = useSelector(
|
||||||
(state: RootState) => state.execClient.selectedClient,
|
(state: RootState) => state.execClient.selectedClient,
|
||||||
)
|
)
|
||||||
|
const docText = DOCUMENTATIONS[selectedClient].documentation[selectedOS]
|
||||||
|
const bashCommands = extractBashCommands(docText)
|
||||||
|
|
||||||
const handleOSCardClick = (os: string) => {
|
const handleOSCardClick = (os: string) => {
|
||||||
setSelectedOS(os)
|
setSelectedOS(os)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const copyCommands = () => {
|
||||||
|
navigator.clipboard.writeText(bashCommands)
|
||||||
|
dispatch(
|
||||||
|
setPinnedMessage({
|
||||||
|
id: '123',
|
||||||
|
text: 'You have successfully copied the commands to your clipboard.',
|
||||||
|
pinned: true,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
setTimeout(() => {
|
||||||
|
dispatch(
|
||||||
|
setPinnedMessage({
|
||||||
|
id: '123',
|
||||||
|
text: 'You have successfully copied the commands to your clipboard.',
|
||||||
|
pinned: false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<YStack style={{ padding: '26px 32px', width: 'fit-content' }}>
|
<YStack style={{ padding: '26px 32px', width: '100%' }}>
|
||||||
<Text size={27} weight={'semibold'}>
|
<Text size={27} weight={'semibold'}>
|
||||||
Validator Setup
|
Client Setup
|
||||||
</Text>
|
</Text>
|
||||||
<YStack
|
<YStack
|
||||||
style={{
|
style={{
|
||||||
|
@ -43,9 +78,13 @@ const ValidatorSetupInstall = () => {
|
||||||
selectedOS={selectedOS}
|
selectedOS={selectedOS}
|
||||||
handleOSCardClick={handleOSCardClick}
|
handleOSCardClick={handleOSCardClick}
|
||||||
/>
|
/>
|
||||||
<Markdown
|
<Stack onPress={() => copyCommands()}>
|
||||||
children={DOCUMENTATIONS[selectedClient].documentation[selectedOS]}
|
<Markdown
|
||||||
/>
|
children={
|
||||||
|
DOCUMENTATIONS[selectedClient].documentation[selectedOS]
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
</YStack>
|
</YStack>
|
||||||
</YStack>
|
</YStack>
|
||||||
|
|
|
@ -19,7 +19,7 @@ const ValidatorSetup = () => {
|
||||||
space={'$8'}
|
space={'$8'}
|
||||||
>
|
>
|
||||||
<Text size={27} weight={'semibold'}>
|
<Text size={27} weight={'semibold'}>
|
||||||
Validator Setup
|
Client Setup
|
||||||
</Text>
|
</Text>
|
||||||
<PairedDeviceCard />
|
<PairedDeviceCard />
|
||||||
</XStack>
|
</XStack>
|
||||||
|
|
Loading…
Reference in New Issue