From f296becfc87b2bfc4f57eb045a928535e718b8f9 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Wed, 4 Oct 2023 23:47:18 +0300 Subject: [PATCH 01/40] feat: generate mnemonic and set it to state --- .../KeyGeneration/RecoveryPhrase.tsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx index 10e0a84f..508f3f89 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx @@ -1,7 +1,9 @@ import { Stack, XStack, YStack } from 'tamagui' import { Button, InformationBox, Text } from '@status-im/components' import { CloseCircleIcon } from '@status-im/icons' -import { useState } from 'react' +import { useEffect, useState } from 'react' +import { generateMnemonic } from 'web-bip39' +import wordlist from 'web-bip39/wordlists/english' type RecoveryPhraseProps = { isKeystoreFiles: boolean @@ -9,6 +11,15 @@ type RecoveryPhraseProps = { const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { const [isReveal, setIsReveal] = useState(false) + const [generatedMnemonic, setGeneratedMnemonic] = useState('') + + useEffect(() => { + const getMnemonic = async () => { + const mnemonic = await generateMnemonic(wordlist, 256) + setGeneratedMnemonic(mnemonic) + } + getMnemonic() + }, []) const revealHandler = () => { setIsReveal(state => !state) From f2ef848b2fe672d061e1acf76d3ba841e76224ca Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Thu, 5 Oct 2023 00:01:02 +0300 Subject: [PATCH 02/40] feat: visualize generated mnemonic --- .../KeyGeneration/RecoveryPhrase.tsx | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx index 508f3f89..771e09cd 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx @@ -14,13 +14,14 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { const [generatedMnemonic, setGeneratedMnemonic] = useState('') useEffect(() => { - const getMnemonic = async () => { - const mnemonic = await generateMnemonic(wordlist, 256) - setGeneratedMnemonic(mnemonic) - } getMnemonic() }, []) + const getMnemonic = async () => { + const mnemonic = await generateMnemonic(wordlist, 256) + setGeneratedMnemonic(mnemonic) + } + const revealHandler = () => { setIsReveal(state => !state) } @@ -38,21 +39,12 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { }} > - - - this is your secret recovery phrase for the validator - - - this is your secret recovery phrase for the validator - - - - - this is your secret recovery phrase for the validator - - - this is your secret recovery phrase for the validator - + + {generatedMnemonic.split(' ').map((word, index) => ( + + {word} + + ))} From 6f558968a8f0ecd0e6c134ee9e27d4652a93bdc4 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Thu, 5 Oct 2023 00:16:52 +0300 Subject: [PATCH 03/40] feat: structure mnemonic into grid --- .../ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx index 771e09cd..8a309a6c 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx @@ -35,11 +35,16 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { padding: '28px 18px', backgroundColor: '#f4f6fe', width: '100%', - height: '176px', }} > - + {generatedMnemonic.split(' ').map((word, index) => ( {word} From 220b13eafcc42b32e5992b75ae7e5a59bb7136cd Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sat, 7 Oct 2023 19:52:55 +0300 Subject: [PATCH 04/40] fix: imports order --- src/App.tsx | 5 +++-- .../ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx | 2 +- src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index f433fcc2..e526d90f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,19 +1,20 @@ import { TamaguiProvider, Theme } from 'tamagui' import { createBrowserRouter, RouterProvider } from 'react-router-dom' import { Provider as StatusProvider } from '@status-im/components' -import './App.css' +import { useSelector } from 'react-redux' + import config from '../tamagui.config' import LandingPage from './pages/LandingPage/LandingPage' import DeviceHealthCheck from './pages/DeviceHealthCheck/DeviceHealthCheck' import ConnectDevicePage from './pages/ConnectDevicePage/ConnectDevicePage' import DeviceSyncStatus from './pages/DeviceSyncStatus/DeviceSyncStatus' import PairDevice from './pages/PairDevice/PairDevice' -import { useSelector } from 'react-redux' import PinnedNotification from './components/General/PinnedNottification' import { RootState } from './redux/store' import CreateLocalNodePage from './pages/CreateLocalNodePage/CreateLocalNodePage' import ValidatorOnboarding from './pages/ValidatorOnboarding/ValidatorOnboarding' import ConnectExistingInstance from './pages/ConnectExistingInstance/ConnectExistingInstance' +import './App.css' const router = createBrowserRouter([ { diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx index 8c672ccf..8e09f8de 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx @@ -6,8 +6,8 @@ import KeyGenerationHeader from './KeyGenerationHeader/KeyGenerationHeader' import RecoveryMechanism from './RecoveryMechanism/RecoveryMechanism' import KeystoreFiles from './KeystoreFiles' import RecoveryPhrase from './RecoveryPhrase' -import { BOTH_KEY_AND_RECOVERY, KEYSTORE_FILES, RECOVERY_PHRASE } from '../../../constants' import ConfirmRecoveryPhrase from './ConfirmRecoveryPhrase/ConfirmRecoveryPhrase' +import { BOTH_KEY_AND_RECOVERY, KEYSTORE_FILES, RECOVERY_PHRASE } from '../../../constants' type KeyGenerationProps = { isConfirmPhraseStage: boolean diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index e8cb282d..c107208b 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -2,6 +2,7 @@ import { YStack } from 'tamagui' import { useNavigate } from 'react-router-dom' import { useState } from 'react' import { useDispatch, useSelector } from 'react-redux' +import wordlist from 'web-bip39/wordlists/english' import FormStepper from './FormStepper/FormStepper' import Titles from '../../components/General/Titles' @@ -20,9 +21,8 @@ import { setValidWords, } from '../../redux/ValidatorOnboarding/KeyGeneration/slice' import { RootState } from '../../redux/store' -import './layoutGradient.css' import ActivationValidatorSetup from './ValidatorSetup/ValidatorActivation/ActivationValidatorSetup' -import wordlist from 'web-bip39/wordlists/english' +import './layoutGradient.css' const ValidatorOnboarding = () => { const [activeStep, setActiveStep] = useState(0) From ac167376d9e6987195665ce76a32c123b58b51ff Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 10:22:38 +0300 Subject: [PATCH 05/40] feat: add text to hide recovery phrase --- .../ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx index 8a309a6c..ab5dbda4 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx @@ -54,7 +54,9 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { - + Date: Sun, 8 Oct 2023 10:45:57 +0300 Subject: [PATCH 06/40] fix: execution of small functions --- src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index c107208b..2674ebca 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -34,8 +34,6 @@ const ValidatorOnboarding = () => { const changeActiveStep = (step: number) => { setActiveStep(step) - removeCopyPastePhraseInfoBox() - removeConfirmPhraseStage() } const continueHandler = () => { @@ -47,6 +45,8 @@ const ValidatorOnboarding = () => { if (newValidWords.every(w => w === true)) { setActiveStep(activeStep + 1) + removeCopyPastePhraseInfoBox() + removeConfirmPhraseStage() } else { return } @@ -60,9 +60,6 @@ const ValidatorOnboarding = () => { } else { navigate('/') } - - removeCopyPastePhraseInfoBox() - removeConfirmPhraseStage() } const removeCopyPastePhraseInfoBox = () => { From 232cc13547ca43db5473562e7dd6c9cfd483da8a Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 10:54:39 +0300 Subject: [PATCH 07/40] feat: add generated mnemonic to redux --- .../ValidatorOnboarding/KeyGeneration/slice.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index a4eef6d7..fada9de8 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -5,6 +5,7 @@ type KeyGenerationState = { isCopyPastedPhrase: boolean isRightPhrase: boolean validWords: boolean[] + generatedMnemonic: string[] } type wordProps = { @@ -17,6 +18,7 @@ const initialState: KeyGenerationState = { isCopyPastedPhrase: false, isRightPhrase: false, validWords: Array(24).fill(true), + generatedMnemonic: Array(24).fill(''), } const keyGenerationSlice = createSlice({ @@ -40,10 +42,19 @@ const keyGenerationSlice = createSlice({ setValidWords: (state, action: PayloadAction) => { state.validWords = action.payload }, + setGeneratedMnemonic: (state, action: PayloadAction) => { + state.generatedMnemonic = action.payload + }, }, }) -export const { setWord, setMnemonic, setIsCopyPastedPhrase, setIsRightPhrase, setValidWords } = - keyGenerationSlice.actions +export const { + setWord, + setMnemonic, + setIsCopyPastedPhrase, + setIsRightPhrase, + setValidWords, + setGeneratedMnemonic, +} = keyGenerationSlice.actions export default keyGenerationSlice.reducer From 62b8bd8a5f04300e347c24c313f4bd9825f8b80d Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 10:59:04 +0300 Subject: [PATCH 08/40] feat: remove generated mnemonic state --- .../KeyGeneration/RecoveryPhrase.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx index ab5dbda4..a253a059 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx @@ -4,6 +4,10 @@ import { CloseCircleIcon } from '@status-im/icons' import { useEffect, useState } from 'react' import { generateMnemonic } from 'web-bip39' import wordlist from 'web-bip39/wordlists/english' +import { useDispatch, useSelector } from 'react-redux' + +import { RootState } from '../../../redux/store' +import { setGeneratedMnemonic } from '../../../redux/ValidatorOnboarding/KeyGeneration/slice' type RecoveryPhraseProps = { isKeystoreFiles: boolean @@ -11,7 +15,8 @@ type RecoveryPhraseProps = { const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { const [isReveal, setIsReveal] = useState(false) - const [generatedMnemonic, setGeneratedMnemonic] = useState('') + const { generatedMnemonic } = useSelector((state: RootState) => state.keyGeneration) + const dispatch = useDispatch() useEffect(() => { getMnemonic() @@ -19,7 +24,7 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { const getMnemonic = async () => { const mnemonic = await generateMnemonic(wordlist, 256) - setGeneratedMnemonic(mnemonic) + dispatch(setGeneratedMnemonic(mnemonic.split(' '))) } const revealHandler = () => { @@ -45,7 +50,7 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { gap: '5px 0px', }} > - {generatedMnemonic.split(' ').map((word, index) => ( + {generatedMnemonic.map((word, index) => ( {word} From 8358f8593c7e0f3d604ef0554e16b9b2be15c2af Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 11:02:56 +0300 Subject: [PATCH 09/40] feat: add state and reducer for is confirm phrase stage --- src/redux/ValidatorOnboarding/KeyGeneration/slice.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index fada9de8..94281b2c 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -6,6 +6,7 @@ type KeyGenerationState = { isRightPhrase: boolean validWords: boolean[] generatedMnemonic: string[] + isConfirmPhraseStage: boolean } type wordProps = { @@ -19,6 +20,7 @@ const initialState: KeyGenerationState = { isRightPhrase: false, validWords: Array(24).fill(true), generatedMnemonic: Array(24).fill(''), + isConfirmPhraseStage: false, } const keyGenerationSlice = createSlice({ @@ -45,6 +47,9 @@ const keyGenerationSlice = createSlice({ setGeneratedMnemonic: (state, action: PayloadAction) => { state.generatedMnemonic = action.payload }, + setIsConfirmPhraseStage: (state, action: PayloadAction) => { + state.isConfirmPhraseStage = action.payload + }, }, }) @@ -55,6 +60,7 @@ export const { setIsRightPhrase, setValidWords, setGeneratedMnemonic, + setIsConfirmPhraseStage, } = keyGenerationSlice.actions export default keyGenerationSlice.reducer From d124e64f66230b53595aed9c0e593deb607efaee Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 11:59:24 +0300 Subject: [PATCH 10/40] feat: use is confirm phrase from redux --- .../ContinueButton.stories.ts | 2 -- .../ValidatorOnboarding/ContinueButton.tsx | 13 +++---------- .../ValidatorOnboarding/ValidatorOnboarding.tsx | 17 ++++++----------- 3 files changed, 9 insertions(+), 23 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.stories.ts b/src/pages/ValidatorOnboarding/ContinueButton.stories.ts index 549e8c04..bd2f02f5 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.stories.ts +++ b/src/pages/ValidatorOnboarding/ContinueButton.stories.ts @@ -20,7 +20,6 @@ export const Default: Story = { args: { continueHandler: () => {}, activeStep: 0, - isConfirmPhraseStage: false, subStepValidatorSetup: 0, }, } @@ -29,7 +28,6 @@ export const Disabled: Story = { args: { continueHandler: () => {}, activeStep: 0, - isConfirmPhraseStage: true, subStepValidatorSetup: 0, }, } diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index e5bc8193..a28dd5e4 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -11,19 +11,12 @@ import LinkWithArrow from '../../components/General/LinkWithArrow' type ContinueButton = { continueHandler: () => void activeStep: number - isConfirmPhraseStage: boolean subStepValidatorSetup: number } -const ContinueButton = ({ - continueHandler, - activeStep, - isConfirmPhraseStage, - subStepValidatorSetup, -}: ContinueButton) => { - const { isCopyPastedPhrase, isRightPhrase, words, validWords } = useSelector( - (state: RootState) => state.keyGeneration, - ) +const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: ContinueButton) => { + const { isCopyPastedPhrase, isRightPhrase, words, validWords, isConfirmPhraseStage } = + useSelector((state: RootState) => state.keyGeneration) const dispatch = useDispatch() useEffect(() => { diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index 2674ebca..6de65ef8 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -17,6 +17,7 @@ import ValidatorSetup from './ValidatorSetup/ValidatorSetup/ValidatorSetup' import ValidatorSetupInstall from './ValidatorSetup/ValidatorInstalling/ValidatorInstall' import ContinueButton from './ContinueButton' import { + setIsConfirmPhraseStage, setIsCopyPastedPhrase, setValidWords, } from '../../redux/ValidatorOnboarding/KeyGeneration/slice' @@ -26,9 +27,10 @@ import './layoutGradient.css' const ValidatorOnboarding = () => { const [activeStep, setActiveStep] = useState(0) - const [isConfirmPhraseStage, setIsConfirmPhraseStage] = useState(false) const [subStepValidatorSetup, setSubStepValidatorSetup] = useState(0) - const { isCopyPastedPhrase, words } = useSelector((state: RootState) => state.keyGeneration) + const { isCopyPastedPhrase, words, isConfirmPhraseStage } = useSelector( + (state: RootState) => state.keyGeneration, + ) const navigate = useNavigate() const dispatch = useDispatch() @@ -38,7 +40,7 @@ const ValidatorOnboarding = () => { const continueHandler = () => { if (activeStep === 4 && isConfirmPhraseStage === false) { - return setIsConfirmPhraseStage(true) + return dispatch(setIsConfirmPhraseStage(true)) } else if (activeStep === 4 && isConfirmPhraseStage === true) { const newValidWords = words.map(w => wordlist.includes(w)) dispatch(setValidWords(newValidWords)) @@ -46,7 +48,7 @@ const ValidatorOnboarding = () => { if (newValidWords.every(w => w === true)) { setActiveStep(activeStep + 1) removeCopyPastePhraseInfoBox() - removeConfirmPhraseStage() + dispatch(setIsConfirmPhraseStage(false)) } else { return } @@ -68,12 +70,6 @@ const ValidatorOnboarding = () => { } } - const removeConfirmPhraseStage = () => { - if (isConfirmPhraseStage) { - setIsConfirmPhraseStage(false) - } - } - return (
{ From 550761a485a5aef468b5147fc900483c8b787391 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 12:50:55 +0300 Subject: [PATCH 11/40] feat: validate mnemonic with generated in order --- .../ValidatorOnboarding/ValidatorOnboarding.tsx | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index 6de65ef8..8d684a8f 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -2,7 +2,6 @@ import { YStack } from 'tamagui' import { useNavigate } from 'react-router-dom' import { useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import wordlist from 'web-bip39/wordlists/english' import FormStepper from './FormStepper/FormStepper' import Titles from '../../components/General/Titles' @@ -28,7 +27,7 @@ import './layoutGradient.css' const ValidatorOnboarding = () => { const [activeStep, setActiveStep] = useState(0) const [subStepValidatorSetup, setSubStepValidatorSetup] = useState(0) - const { isCopyPastedPhrase, words, isConfirmPhraseStage } = useSelector( + const { isCopyPastedPhrase, words, isConfirmPhraseStage, generatedMnemonic } = useSelector( (state: RootState) => state.keyGeneration, ) const navigate = useNavigate() @@ -38,20 +37,20 @@ const ValidatorOnboarding = () => { setActiveStep(step) } - const continueHandler = () => { + const continueHandler = async () => { if (activeStep === 4 && isConfirmPhraseStage === false) { return dispatch(setIsConfirmPhraseStage(true)) } else if (activeStep === 4 && isConfirmPhraseStage === true) { - const newValidWords = words.map(w => wordlist.includes(w)) + const newValidWords = words.map((w, index) => generatedMnemonic[index] === w) dispatch(setValidWords(newValidWords)) - if (newValidWords.every(w => w === true)) { - setActiveStep(activeStep + 1) - removeCopyPastePhraseInfoBox() - dispatch(setIsConfirmPhraseStage(false)) - } else { + if (newValidWords.some(w => w === false)) { return } + + setActiveStep(activeStep + 1) + removeCopyPastePhraseInfoBox() + dispatch(setIsConfirmPhraseStage(false)) } else if (activeStep === 3 && subStepValidatorSetup < 3) { setSubStepValidatorSetup(subStepValidatorSetup + 1) } else if (activeStep < 5) { From d22838d945a5bce38bff21745129c9bf91c4e2ba Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 13:24:47 +0300 Subject: [PATCH 12/40] feat: change words to mnemonic --- src/pages/ValidatorOnboarding/ContinueButton.tsx | 6 +++--- .../ConfirmRecoveryPhrase/AutocompleteInput.tsx | 2 +- .../ValidatorOnboarding/ValidatorOnboarding.tsx | 4 ++-- src/redux/ValidatorOnboarding/KeyGeneration/slice.ts | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index a28dd5e4..b5dcddc3 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -15,13 +15,13 @@ type ContinueButton = { } const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: ContinueButton) => { - const { isCopyPastedPhrase, isRightPhrase, words, validWords, isConfirmPhraseStage } = + const { isCopyPastedPhrase, isRightPhrase, mnemonic, validWords, isConfirmPhraseStage } = useSelector((state: RootState) => state.keyGeneration) const dispatch = useDispatch() useEffect(() => { - dispatch(setIsRightPhrase(words.every(word => word !== ''))) - }, [words]) + dispatch(setIsRightPhrase(mnemonic.every(word => word !== ''))) + }, [mnemonic]) const isDisabled = () => { if ( diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx index d655b6dc..16bc1cb8 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx @@ -18,7 +18,7 @@ type AutocompleteInputProps = { const AutocompleteInput = ({ index }: AutocompleteInputProps) => { const [suggestions, setSuggestions] = useState([]) const [isFocused, setIsFocused] = useState(false) - const word = useSelector((state: RootState) => state.keyGeneration.words[index]) + const word = useSelector((state: RootState) => state.keyGeneration.mnemonic[index]) const isValidWord = useSelector((state: RootState) => state.keyGeneration.validWords[index]) const validWords = useSelector((state: RootState) => state.keyGeneration.validWords) const dispatch = useDispatch() diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index 8d684a8f..fcdb19a3 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -27,7 +27,7 @@ import './layoutGradient.css' const ValidatorOnboarding = () => { const [activeStep, setActiveStep] = useState(0) const [subStepValidatorSetup, setSubStepValidatorSetup] = useState(0) - const { isCopyPastedPhrase, words, isConfirmPhraseStage, generatedMnemonic } = useSelector( + const { isCopyPastedPhrase, mnemonic, isConfirmPhraseStage, generatedMnemonic } = useSelector( (state: RootState) => state.keyGeneration, ) const navigate = useNavigate() @@ -41,7 +41,7 @@ const ValidatorOnboarding = () => { if (activeStep === 4 && isConfirmPhraseStage === false) { return dispatch(setIsConfirmPhraseStage(true)) } else if (activeStep === 4 && isConfirmPhraseStage === true) { - const newValidWords = words.map((w, index) => generatedMnemonic[index] === w) + const newValidWords = mnemonic.map((w, index) => generatedMnemonic[index] === w) dispatch(setValidWords(newValidWords)) if (newValidWords.some(w => w === false)) { diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index 94281b2c..9b224405 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -1,7 +1,7 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' type KeyGenerationState = { - words: string[] + mnemonic: string[] isCopyPastedPhrase: boolean isRightPhrase: boolean validWords: boolean[] @@ -15,7 +15,7 @@ type wordProps = { } const initialState: KeyGenerationState = { - words: Array(24).fill(''), + mnemonic: Array(24).fill(''), isCopyPastedPhrase: false, isRightPhrase: false, validWords: Array(24).fill(true), @@ -28,12 +28,12 @@ const keyGenerationSlice = createSlice({ initialState, reducers: { setWord: (state, action: PayloadAction) => { - const newWords = [...state.words] - newWords[action.payload.index] = action.payload.word - return { ...state, words: newWords } + const newMnemonic = [...state.mnemonic] + newMnemonic[action.payload.index] = action.payload.word + return { ...state, mnemonic: newMnemonic } }, setMnemonic: (state, action: PayloadAction) => { - state.words = action.payload + state.mnemonic = action.payload }, setIsCopyPastedPhrase: (state, action: PayloadAction) => { state.isCopyPastedPhrase = action.payload From d715e222b10e82fe4873daef5cff56fc13560c1c Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 13:26:26 +0300 Subject: [PATCH 13/40] fix: change set word reducer return --- src/redux/ValidatorOnboarding/KeyGeneration/slice.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index 9b224405..e453ed6b 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -30,7 +30,7 @@ const keyGenerationSlice = createSlice({ setWord: (state, action: PayloadAction) => { const newMnemonic = [...state.mnemonic] newMnemonic[action.payload.index] = action.payload.word - return { ...state, mnemonic: newMnemonic } + state.mnemonic = newMnemonic }, setMnemonic: (state, action: PayloadAction) => { state.mnemonic = action.payload From 49129c6a82da868e3a16ac30c91d015acd3b8624 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 14:20:29 +0300 Subject: [PATCH 14/40] feat: copy recovery phrase functionallity --- .../KeyGeneration/RecoveryPhrase.tsx | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx index a253a059..a80b74da 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryPhrase.tsx @@ -31,6 +31,15 @@ const RecoveryPhrase = ({ isKeystoreFiles }: RecoveryPhraseProps) => { setIsReveal(state => !state) } + const copyRecoveryPhraseHandler = () => { + if (isKeystoreFiles) { + return + } + + const text = generatedMnemonic.join(' ') + navigator.clipboard.writeText(text) + } + return ( { width: '100%', }} > - + Date: Sun, 8 Oct 2023 15:04:24 +0300 Subject: [PATCH 15/40] feat: download empty txt file for keystore files --- .../ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx index b9be5222..e86eec36 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx @@ -25,7 +25,14 @@ const KeystoreFiles = () => { setConfirmEncryptedPassword('') } - const downloadKeyFilesHandler = () => {} + const downloadKeyFilesHandler = () => { + const element = document.createElement('a') + const file = new Blob([''], { type: 'text/plain' }) + element.href = URL.createObjectURL(file) + element.download = 'keystore_files.txt' + document.body.appendChild(element) + element.click() + } return ( From 691bc01c42e2d92225d64c714c619b7b29a3384e Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 15:32:19 +0300 Subject: [PATCH 16/40] feat: create state for open key generation sync card --- .../KeyGenerationSyncCard.tsx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationSyncCard.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationSyncCard.tsx index 32151617..424169d8 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationSyncCard.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationSyncCard.tsx @@ -1,6 +1,7 @@ import { Stack, XStack, YStack } from 'tamagui' import { ClearIcon } from '@status-im/icons' import { Text } from '@status-im/components' +import { useState } from 'react' import StandardGauge from '../../../../components/Charts/StandardGauge' import BorderBox from '../../../../components/General/BorderBox' @@ -14,6 +15,16 @@ type KeyGenerationSyncCardProps = { } const KeyGenerationSyncCard = ({ synced, total, title, color }: KeyGenerationSyncCardProps) => { + const [isOpen, setIsOpen] = useState(true) + + const closeCardHanlder = () => { + setIsOpen(false) + } + + if (isOpen === false) { + return + } + return ( @@ -48,7 +59,12 @@ const KeyGenerationSyncCard = ({ synced, total, title, color }: KeyGenerationSyn {formatNumberForGauge(synced)} / {formatNumberForGauge(total)} - + ) From 919612fb1c42dbdd1cb06a88dac5c32a6986995f Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 15:35:02 +0300 Subject: [PATCH 17/40] fix: align sync cards and title --- .../KeyGeneration/KeyGenerationHeader/KeyGenerationHeader.tsx | 2 +- .../KeyGeneration/KeyGenerationHeader/KeyGenerationSyncCard.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationHeader.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationHeader.tsx index da062939..9d10ad84 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationHeader.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGenerationHeader/KeyGenerationHeader.tsx @@ -5,7 +5,7 @@ import KeyGenerationTitle from '../KeyGenerationTitle' const KeyGenerationHeader = () => { return ( - + Date: Sun, 8 Oct 2023 16:21:13 +0300 Subject: [PATCH 18/40] feat: live checking mnemonic with generated one --- .../ConfirmRecoveryPhrase/AutocompleteInput.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx index 16bc1cb8..d5186552 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx @@ -20,7 +20,7 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { const [isFocused, setIsFocused] = useState(false) const word = useSelector((state: RootState) => state.keyGeneration.mnemonic[index]) const isValidWord = useSelector((state: RootState) => state.keyGeneration.validWords[index]) - const validWords = useSelector((state: RootState) => state.keyGeneration.validWords) + const { validWords, generatedMnemonic } = useSelector((state: RootState) => state.keyGeneration) const dispatch = useDispatch() useEffect(() => { @@ -43,20 +43,20 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { if (mnemonicLength === 1) { dispatch(setWord({ index, word: value })) - - newValidWords[index] = wordlist.includes(value) || getNewSuggestions(value).length > 0 + newValidWords[index] = + generatedMnemonic[index] === value || generatedMnemonic[index].startsWith(value) } else if (mnemonicLength === 24) { dispatch(setMnemonic(mnemonic)) dispatch(setIsCopyPastedPhrase(true)) mnemonic.forEach((m, i) => { - newValidWords[i] = wordlist.includes(m) + newValidWords[i] = generatedMnemonic[i] === m }) } else { for (let i = index; i < mnemonicLength + index; i++) { const mnemonicWord = mnemonic.shift() || '' dispatch(setWord({ index: i, word: mnemonicWord })) - newValidWords[i] = wordlist.includes(mnemonicWord) + newValidWords[i] = generatedMnemonic[i] === mnemonicWord } dispatch(setIsCopyPastedPhrase(true)) @@ -72,7 +72,7 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { dispatch(setWord({ index, word: suggestion })) let newValidWords = [...validWords] - newValidWords[index] = wordlist.includes(suggestion) + newValidWords[index] = generatedMnemonic[index] === suggestion dispatch(setValidWords(newValidWords)) } @@ -84,7 +84,7 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { setIsFocused(false) let newValidWords = [...validWords] - newValidWords[index] = wordlist.includes(word) + newValidWords[index] = generatedMnemonic[index] === word dispatch(setValidWords(newValidWords)) } From 522717cb1cb1e27d8000474074047a896838e9f3 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 16:33:33 +0300 Subject: [PATCH 19/40] feat: remove is right phrase state and reducer --- src/pages/ValidatorOnboarding/ContinueButton.tsx | 16 +++++----------- .../ValidatorOnboarding/KeyGeneration/slice.ts | 6 ------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index b5dcddc3..5b1b0d2b 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -1,11 +1,9 @@ import { Stack, YStack } from 'tamagui' import { Button, InformationBox } from '@status-im/components' import { CloseCircleIcon } from '@status-im/icons' -import { useDispatch, useSelector } from 'react-redux' -import { useEffect } from 'react' +import { useSelector } from 'react-redux' import { RootState } from '../../redux/store' -import { setIsRightPhrase } from '../../redux/ValidatorOnboarding/KeyGeneration/slice' import LinkWithArrow from '../../components/General/LinkWithArrow' type ContinueButton = { @@ -15,17 +13,13 @@ type ContinueButton = { } const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: ContinueButton) => { - const { isCopyPastedPhrase, isRightPhrase, mnemonic, validWords, isConfirmPhraseStage } = - useSelector((state: RootState) => state.keyGeneration) - const dispatch = useDispatch() - - useEffect(() => { - dispatch(setIsRightPhrase(mnemonic.every(word => word !== ''))) - }, [mnemonic]) + const { isCopyPastedPhrase, mnemonic, validWords, isConfirmPhraseStage } = useSelector( + (state: RootState) => state.keyGeneration, + ) const isDisabled = () => { if ( - (isConfirmPhraseStage && !isRightPhrase) || + (isConfirmPhraseStage && mnemonic.some(word => word === '')) || (isConfirmPhraseStage && validWords.some(w => w === false)) ) { return true diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index e453ed6b..895025b2 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -3,7 +3,6 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' type KeyGenerationState = { mnemonic: string[] isCopyPastedPhrase: boolean - isRightPhrase: boolean validWords: boolean[] generatedMnemonic: string[] isConfirmPhraseStage: boolean @@ -17,7 +16,6 @@ type wordProps = { const initialState: KeyGenerationState = { mnemonic: Array(24).fill(''), isCopyPastedPhrase: false, - isRightPhrase: false, validWords: Array(24).fill(true), generatedMnemonic: Array(24).fill(''), isConfirmPhraseStage: false, @@ -38,9 +36,6 @@ const keyGenerationSlice = createSlice({ setIsCopyPastedPhrase: (state, action: PayloadAction) => { state.isCopyPastedPhrase = action.payload }, - setIsRightPhrase: (state, action: PayloadAction) => { - state.isRightPhrase = action.payload - }, setValidWords: (state, action: PayloadAction) => { state.validWords = action.payload }, @@ -57,7 +52,6 @@ export const { setWord, setMnemonic, setIsCopyPastedPhrase, - setIsRightPhrase, setValidWords, setGeneratedMnemonic, setIsConfirmPhraseStage, From 8c766a152be52f8affd149f3331ccfe4b2fd4723 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 17:16:17 +0300 Subject: [PATCH 20/40] feat: change structure for continue btn and info box --- .../ValidatorOnboarding/ContinueButton.tsx | 55 +++++++++---------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index 5b1b0d2b..b13a3f4c 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -1,4 +1,4 @@ -import { Stack, YStack } from 'tamagui' +import { Stack, XStack } from 'tamagui' import { Button, InformationBox } from '@status-im/components' import { CloseCircleIcon } from '@status-im/icons' import { useSelector } from 'react-redux' @@ -16,6 +16,7 @@ const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: const { isCopyPastedPhrase, mnemonic, validWords, isConfirmPhraseStage } = useSelector( (state: RootState) => state.keyGeneration, ) + const isActivationValScreen = activeStep === 3 && subStepValidatorSetup === 3 const isDisabled = () => { if ( @@ -27,39 +28,37 @@ const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: return false } - const isActivationValScreen = activeStep === 3 && subStepValidatorSetup === 3 - return ( - - - {isCopyPastedPhrase && ( + + {isCopyPastedPhrase && ( + } /> - )} - {isActivationValScreen && ( - - )} - - - - - + + )} + {isActivationValScreen && ( + + )} + + ) } From fc5492072a880d29e50b9bb6d1f6c7fa31eb339f Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 17:16:53 +0300 Subject: [PATCH 21/40] feat: add url to dashboard --- src/pages/ValidatorOnboarding/ContinueButton.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index b13a3f4c..7a06c5b6 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -50,7 +50,7 @@ const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: {isActivationValScreen && ( From 74c8312589938877643d1affaa3e8951678504b1 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 18:29:38 +0300 Subject: [PATCH 22/40] feat: add error for not matching passwords --- .../KeyGeneration/KeystoreFiles.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx index e86eec36..7548d7b7 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx @@ -6,8 +6,23 @@ import { useState } from 'react' const KeystoreFiles = () => { const [encryptedPassword, setEncryptedPassword] = useState('') const [confirmEncryptedPassword, setConfirmEncryptedPassword] = useState('') + const [encryptedPasswordError, setEncryptedPasswordError] = useState(false) + const [confirmEncryptedPasswordError, setConfirmEncryptedPasswordError] = useState(false) - const generateKeystoreFilesHandler = () => {} + const generateKeystoreFilesHandler = () => { + if ( + encryptedPassword !== confirmEncryptedPassword || + encryptedPassword === '' || + confirmEncryptedPassword === '' + ) { + setEncryptedPasswordError(true) + setConfirmEncryptedPasswordError(true) + return + } + + setEncryptedPasswordError(false) + setConfirmEncryptedPasswordError(false) + } const changeEncryptedPasswordHandler = (e: any) => { setEncryptedPassword(e.target.value) @@ -52,6 +67,7 @@ const KeystoreFiles = () => { onClick={clearEncryptedPasswordHandler} /> } + error={encryptedPasswordError} value={encryptedPassword} onChange={changeEncryptedPasswordHandler} /> @@ -70,6 +86,7 @@ const KeystoreFiles = () => { onClick={clearConfirmEncryptedPasswordHandler} /> } + error={confirmEncryptedPasswordError} value={confirmEncryptedPassword} onChange={changeConfirmEncryptedPasswordHandler} /> From 9b58e13bac2d3625b4f870fc976a03ff3d100b08 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 18:52:20 +0300 Subject: [PATCH 23/40] feat: hide passwords while typing --- .../KeyGeneration/KeystoreFiles.tsx | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx index 7548d7b7..ae64c732 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx @@ -8,6 +8,8 @@ const KeystoreFiles = () => { const [confirmEncryptedPassword, setConfirmEncryptedPassword] = useState('') const [encryptedPasswordError, setEncryptedPasswordError] = useState(false) const [confirmEncryptedPasswordError, setConfirmEncryptedPasswordError] = useState(false) + const [displayEncryptedPassword, setDisplayEncryptedPassword] = useState('') + const [displayConfirmEncryptedPassword, setDisplayConfirmEncryptedPassword] = useState('') const generateKeystoreFilesHandler = () => { if ( @@ -25,11 +27,15 @@ const KeystoreFiles = () => { } const changeEncryptedPasswordHandler = (e: any) => { - setEncryptedPassword(e.target.value) + const password = e.target.value + setEncryptedPassword(password) + setDisplayEncryptedPassword(getHidedPassword(password.length)) } const changeConfirmEncryptedPasswordHandler = (e: any) => { - setConfirmEncryptedPassword(e.target.value) + const password = e.target.value + setConfirmEncryptedPassword(password) + setDisplayConfirmEncryptedPassword(getHidedPassword(password.length)) } const clearEncryptedPasswordHandler = () => { @@ -49,6 +55,10 @@ const KeystoreFiles = () => { element.click() } + const getHidedPassword = (passwordLength: number) => { + return '*'.repeat(passwordLength) + } + return ( @@ -68,7 +78,7 @@ const KeystoreFiles = () => { /> } error={encryptedPasswordError} - value={encryptedPassword} + value={displayEncryptedPassword} onChange={changeEncryptedPasswordHandler} /> @@ -87,7 +97,7 @@ const KeystoreFiles = () => { /> } error={confirmEncryptedPasswordError} - value={confirmEncryptedPassword} + value={displayConfirmEncryptedPassword} onChange={changeConfirmEncryptedPasswordHandler} /> From a53fabc7c83e3f6767a803ca7546438d3d295f2d Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 19:49:15 +0300 Subject: [PATCH 24/40] fix: disabled continue button --- .../ValidatorOnboarding/ContinueButton.tsx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index 7a06c5b6..65ea67d0 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -5,6 +5,7 @@ import { useSelector } from 'react-redux' import { RootState } from '../../redux/store' import LinkWithArrow from '../../components/General/LinkWithArrow' +import { useEffect, useState } from 'react' type ContinueButton = { continueHandler: () => void @@ -13,20 +14,25 @@ type ContinueButton = { } const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: ContinueButton) => { + const [isDisabled, setIsDisabled] = useState(false) const { isCopyPastedPhrase, mnemonic, validWords, isConfirmPhraseStage } = useSelector( (state: RootState) => state.keyGeneration, ) const isActivationValScreen = activeStep === 3 && subStepValidatorSetup === 3 - const isDisabled = () => { - if ( - (isConfirmPhraseStage && mnemonic.some(word => word === '')) || - (isConfirmPhraseStage && validWords.some(w => w === false)) - ) { - return true + useEffect(() => { + const getDisabledButton = () => { + if (activeStep === 4 && isConfirmPhraseStage) { + if (mnemonic.some(word => word === '') || validWords.some(w => w === false)) { + return false + } + } + + return false } - return false - } + + setIsDisabled(getDisabledButton()) + }, [activeStep, subStepValidatorSetup, isConfirmPhraseStage, mnemonic, validWords]) return ( )} - From 7ee2c047ee5bb9394cf4aa329dc50059e43f058f Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 20:04:11 +0300 Subject: [PATCH 25/40] feat: add recovery mechanism to redux --- src/redux/ValidatorOnboarding/KeyGeneration/slice.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index 895025b2..de320f6c 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -1,4 +1,5 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' +import { KEYSTORE_FILES } from '../../../constants' type KeyGenerationState = { mnemonic: string[] @@ -6,6 +7,7 @@ type KeyGenerationState = { validWords: boolean[] generatedMnemonic: string[] isConfirmPhraseStage: boolean + recoveryMechanism: string } type wordProps = { @@ -19,6 +21,7 @@ const initialState: KeyGenerationState = { validWords: Array(24).fill(true), generatedMnemonic: Array(24).fill(''), isConfirmPhraseStage: false, + recoveryMechanism: KEYSTORE_FILES, } const keyGenerationSlice = createSlice({ @@ -45,6 +48,9 @@ const keyGenerationSlice = createSlice({ setIsConfirmPhraseStage: (state, action: PayloadAction) => { state.isConfirmPhraseStage = action.payload }, + setRecoveryMechanism: (state, action: PayloadAction) => { + state.recoveryMechanism = action.payload + }, }, }) @@ -55,6 +61,7 @@ export const { setValidWords, setGeneratedMnemonic, setIsConfirmPhraseStage, + setRecoveryMechanism, } = keyGenerationSlice.actions export default keyGenerationSlice.reducer From fe02c14efd24e338742784b67759b0c057547905 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 22:01:24 +0300 Subject: [PATCH 26/40] feat: use recovery mechanism from redux --- .../ValidatorOnboarding/ContinueButton.tsx | 2 +- .../KeyGeneration/KeyGeneration.tsx | 14 ++++---------- .../RecoveryMechanism.stories.ts | 4 ---- .../RecoveryMechanism/RecoveryMechanism.tsx | 13 ++----------- .../RecoveryMechanismCard.stories.ts | 3 --- .../RecoveryMechanismCard.tsx | 18 +++++++++++------- 6 files changed, 18 insertions(+), 36 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index 65ea67d0..c5646e00 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -2,10 +2,10 @@ import { Stack, XStack } from 'tamagui' import { Button, InformationBox } from '@status-im/components' import { CloseCircleIcon } from '@status-im/icons' import { useSelector } from 'react-redux' +import { useEffect, useState } from 'react' import { RootState } from '../../redux/store' import LinkWithArrow from '../../components/General/LinkWithArrow' -import { useEffect, useState } from 'react' type ContinueButton = { continueHandler: () => void diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx index 8e09f8de..fe7e0776 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeyGeneration.tsx @@ -1,6 +1,6 @@ import { Stack, YStack } from 'tamagui' import { Text } from '@status-im/components' -import { useState } from 'react' +import { useSelector } from 'react-redux' import KeyGenerationHeader from './KeyGenerationHeader/KeyGenerationHeader' import RecoveryMechanism from './RecoveryMechanism/RecoveryMechanism' @@ -8,13 +8,14 @@ import KeystoreFiles from './KeystoreFiles' import RecoveryPhrase from './RecoveryPhrase' import ConfirmRecoveryPhrase from './ConfirmRecoveryPhrase/ConfirmRecoveryPhrase' import { BOTH_KEY_AND_RECOVERY, KEYSTORE_FILES, RECOVERY_PHRASE } from '../../../constants' +import { RootState } from '../../../redux/store' type KeyGenerationProps = { isConfirmPhraseStage: boolean } const KeyGeneration = ({ isConfirmPhraseStage }: KeyGenerationProps) => { - const [recoveryMechanism, setRecoveryMechanism] = useState(KEYSTORE_FILES) + const { recoveryMechanism } = useSelector((state: RootState) => state.keyGeneration) const isKeystoreFiles = recoveryMechanism === KEYSTORE_FILES || recoveryMechanism === BOTH_KEY_AND_RECOVERY @@ -22,20 +23,13 @@ const KeyGeneration = ({ isConfirmPhraseStage }: KeyGenerationProps) => { const isRecoveryPhrase = recoveryMechanism === RECOVERY_PHRASE || recoveryMechanism === BOTH_KEY_AND_RECOVERY - const handleRecMechanismChange = (value: string) => { - setRecoveryMechanism(value) - } - return ( {isConfirmPhraseStage && } {isConfirmPhraseStage === false && ( <> - + 4 Validators diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts index 5b2fbb60..203d2805 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts @@ -18,27 +18,23 @@ type Story = StoryObj export const KeystoreFiles: Story = { args: { recoveryMechanism: KEYSTORE_FILES, - handleRecMechanismChange: () => {}, }, } export const RecoveryPhrase: Story = { args: { recoveryMechanism: RECOVERY_PHRASE, - handleRecMechanismChange: () => {}, }, } export const BothKeystoreAndRecovery: Story = { args: { recoveryMechanism: BOTH_KEY_AND_RECOVERY, - handleRecMechanismChange: () => {}, }, } export const WithoutRecMechanism: Story = { args: { recoveryMechanism: '', - handleRecMechanismChange: () => {}, }, } diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.tsx index fd768bb4..84a49253 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.tsx @@ -6,15 +6,11 @@ import { BOTH_KEY_AND_RECOVERY, KEYSTORE_FILES, RECOVERY_PHRASE } from '../../.. type RecoveryMechanismProps = { recoveryMechanism: string - handleRecMechanismChange: (value: string) => void } const cards = [RECOVERY_PHRASE, KEYSTORE_FILES, BOTH_KEY_AND_RECOVERY] -const RecoveryMechanism = ({ - recoveryMechanism, - handleRecMechanismChange, -}: RecoveryMechanismProps) => { +const RecoveryMechanism = ({ recoveryMechanism }: RecoveryMechanismProps) => { return ( @@ -22,12 +18,7 @@ const RecoveryMechanism = ({ {cards.map(value => ( - + ))} diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts index 06f87741..e5f4009c 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts @@ -19,7 +19,6 @@ export const Selected: Story = { args: { value: KEYSTORE_FILES, recoveryMechanism: KEYSTORE_FILES, - handleRecMechanismChange: () => {}, }, } @@ -27,7 +26,6 @@ export const NotSelected: Story = { args: { value: KEYSTORE_FILES, recoveryMechanism: '', - handleRecMechanismChange: () => {}, }, } @@ -35,6 +33,5 @@ export const WithoutValue: Story = { args: { value: '', recoveryMechanism: KEYSTORE_FILES, - handleRecMechanismChange: () => {}, }, } diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.tsx index 4b5098bd..62235436 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.tsx @@ -1,16 +1,20 @@ import { Text } from '@status-im/components' +import { useDispatch } from 'react-redux' + +import { setRecoveryMechanism } from '../../../../redux/ValidatorOnboarding/KeyGeneration/slice' type RecoveryMechanismProps = { value: string recoveryMechanism: string - handleRecMechanismChange: (value: string) => void } -const RecoveryMechanismCard = ({ - value, - recoveryMechanism, - handleRecMechanismChange, -}: RecoveryMechanismProps) => { +const RecoveryMechanismCard = ({ value, recoveryMechanism }: RecoveryMechanismProps) => { + const dispatch = useDispatch() + + const handleRecMechanismChange = () => { + dispatch(setRecoveryMechanism(value)) + } + return (
handleRecMechanismChange(value)} + onClick={handleRecMechanismChange} > {value} From f6c51a5f9d744e737c3204224a62c0c765ad7faf Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 22:04:08 +0300 Subject: [PATCH 27/40] feat: skip rec phrase for keystore rec mechanism --- .../ValidatorOnboarding.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index fcdb19a3..cdff4e12 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -23,13 +23,18 @@ import { import { RootState } from '../../redux/store' import ActivationValidatorSetup from './ValidatorSetup/ValidatorActivation/ActivationValidatorSetup' import './layoutGradient.css' +import { KEYSTORE_FILES } from '../../constants' const ValidatorOnboarding = () => { const [activeStep, setActiveStep] = useState(0) const [subStepValidatorSetup, setSubStepValidatorSetup] = useState(0) - const { isCopyPastedPhrase, mnemonic, isConfirmPhraseStage, generatedMnemonic } = useSelector( - (state: RootState) => state.keyGeneration, - ) + const { + isCopyPastedPhrase, + mnemonic, + isConfirmPhraseStage, + generatedMnemonic, + recoveryMechanism, + } = useSelector((state: RootState) => state.keyGeneration) const navigate = useNavigate() const dispatch = useDispatch() @@ -38,7 +43,13 @@ const ValidatorOnboarding = () => { } const continueHandler = async () => { - if (activeStep === 4 && isConfirmPhraseStage === false) { + if ( + activeStep === 4 && + isConfirmPhraseStage === false && + recoveryMechanism === KEYSTORE_FILES + ) { + setActiveStep(activeStep + 1) + } else if (activeStep === 4 && isConfirmPhraseStage === false) { return dispatch(setIsConfirmPhraseStage(true)) } else if (activeStep === 4 && isConfirmPhraseStage === true) { const newValidWords = mnemonic.map((w, index) => generatedMnemonic[index] === w) From d5b6e6034a269ecb24b40cd6a096bbf3862a3ffc Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 22:11:36 +0300 Subject: [PATCH 28/40] feat: separate continue function into pieces --- .../ValidatorOnboarding.tsx | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index cdff4e12..36bd3e90 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -42,35 +42,44 @@ const ValidatorOnboarding = () => { setActiveStep(step) } - const continueHandler = async () => { - if ( - activeStep === 4 && - isConfirmPhraseStage === false && - recoveryMechanism === KEYSTORE_FILES - ) { - setActiveStep(activeStep + 1) - } else if (activeStep === 4 && isConfirmPhraseStage === false) { + const handleStep3 = () => { + subStepValidatorSetup < 3 + ? setSubStepValidatorSetup(subStepValidatorSetup + 1) + : setSubStepValidatorSetup(0) + } + + const handleStep4 = () => { + if (!isConfirmPhraseStage && recoveryMechanism === KEYSTORE_FILES) { + return setActiveStep(activeStep + 1) + } + + if (!isConfirmPhraseStage) { return dispatch(setIsConfirmPhraseStage(true)) - } else if (activeStep === 4 && isConfirmPhraseStage === true) { + } + + if (isConfirmPhraseStage) { const newValidWords = mnemonic.map((w, index) => generatedMnemonic[index] === w) dispatch(setValidWords(newValidWords)) - if (newValidWords.some(w => w === false)) { - return + if (!newValidWords.includes(false)) { + setActiveStep(activeStep + 1) + removeCopyPastePhraseInfoBox() + dispatch(setIsConfirmPhraseStage(false)) } + } + } - setActiveStep(activeStep + 1) - removeCopyPastePhraseInfoBox() - dispatch(setIsConfirmPhraseStage(false)) - } else if (activeStep === 3 && subStepValidatorSetup < 3) { - setSubStepValidatorSetup(subStepValidatorSetup + 1) - } else if (activeStep < 5) { - setActiveStep(activeStep + 1) - if (activeStep === 3 && subStepValidatorSetup === 2) { - setSubStepValidatorSetup(0) - } + const continueHandler = () => { + if (activeStep === 3) { + handleStep3() + } else if (activeStep === 4) { + handleStep4() } else { - navigate('/') + if (activeStep < 5) { + setActiveStep(activeStep + 1) + } else { + navigate('/') + } } } From c9b3ef3fca2156a6e68c326b37f075c4d7e12110 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 22:25:35 +0300 Subject: [PATCH 29/40] fix: optimize checking for disable button --- src/pages/ValidatorOnboarding/ContinueButton.tsx | 3 +-- src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index c5646e00..278f7523 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -23,11 +23,10 @@ const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: useEffect(() => { const getDisabledButton = () => { if (activeStep === 4 && isConfirmPhraseStage) { - if (mnemonic.some(word => word === '') || validWords.some(w => w === false)) { + if (validWords.some(w => w === false)) { return false } } - return false } diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index 36bd3e90..0d17f1ea 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -22,8 +22,8 @@ import { } from '../../redux/ValidatorOnboarding/KeyGeneration/slice' import { RootState } from '../../redux/store' import ActivationValidatorSetup from './ValidatorSetup/ValidatorActivation/ActivationValidatorSetup' -import './layoutGradient.css' import { KEYSTORE_FILES } from '../../constants' +import './layoutGradient.css' const ValidatorOnboarding = () => { const [activeStep, setActiveStep] = useState(0) From 83c633cc189f057358454e2cdd1f002879578f71 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Sun, 8 Oct 2023 22:44:02 +0300 Subject: [PATCH 30/40] feat: add examples for rec mechanism card story --- .../RecoveryMechanismCard.stories.ts | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts index e5f4009c..85c512c5 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanismCard.stories.ts @@ -1,7 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react' import RecoveryMechanismCard from './RecoveryMechanismCard' -import { KEYSTORE_FILES } from '../../../../constants' +import { BOTH_KEY_AND_RECOVERY, KEYSTORE_FILES, RECOVERY_PHRASE } from '../../../../constants' const meta = { title: 'ValidatorOnboarding/RecoveryMechanismCard', @@ -15,13 +15,27 @@ const meta = { export default meta type Story = StoryObj -export const Selected: Story = { +export const KeystoreFiles: Story = { args: { value: KEYSTORE_FILES, recoveryMechanism: KEYSTORE_FILES, }, } +export const RecoveryPhrase: Story = { + args: { + value: RECOVERY_PHRASE, + recoveryMechanism: RECOVERY_PHRASE, + }, +} + +export const BothKeyAndRecovery: Story = { + args: { + value: BOTH_KEY_AND_RECOVERY, + recoveryMechanism: BOTH_KEY_AND_RECOVERY, + }, +} + export const NotSelected: Story = { args: { value: KEYSTORE_FILES, From 63cfed09069769527a7152c4fd6450a77a013c28 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 15:48:39 +0300 Subject: [PATCH 31/40] feat: add control to change story --- ...yMechanism.stories.ts => RecoveryMechanism.stories.tsx} | 7 +++++++ 1 file changed, 7 insertions(+) rename src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/{RecoveryMechanism.stories.ts => RecoveryMechanism.stories.tsx} (81%) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.tsx similarity index 81% rename from src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts rename to src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.tsx index 203d2805..faf7173d 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.ts +++ b/src/pages/ValidatorOnboarding/KeyGeneration/RecoveryMechanism/RecoveryMechanism.stories.tsx @@ -10,6 +10,13 @@ const meta = { layout: 'centered', }, tags: ['autodocs'], + argTypes: { + recoveryMechanism: { + options: [RECOVERY_PHRASE, KEYSTORE_FILES, BOTH_KEY_AND_RECOVERY], + control: { type: 'radio' }, + defaultValue: KEYSTORE_FILES, + }, + }, } satisfies Meta export default meta From d1fed2c5801141647b59bc3725816b72e14d3319 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 16:16:18 +0300 Subject: [PATCH 32/40] feat: reduce code from keystore files --- .../KeyGeneration/KeystoreFiles.tsx | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx index ae64c732..1fb44a9d 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/KeystoreFiles.tsx @@ -18,8 +18,7 @@ const KeystoreFiles = () => { confirmEncryptedPassword === '' ) { setEncryptedPasswordError(true) - setConfirmEncryptedPasswordError(true) - return + return setConfirmEncryptedPasswordError(true) } setEncryptedPasswordError(false) @@ -38,14 +37,6 @@ const KeystoreFiles = () => { setDisplayConfirmEncryptedPassword(getHidedPassword(password.length)) } - const clearEncryptedPasswordHandler = () => { - setEncryptedPassword('') - } - - const clearConfirmEncryptedPasswordHandler = () => { - setConfirmEncryptedPassword('') - } - const downloadKeyFilesHandler = () => { const element = document.createElement('a') const file = new Blob([''], { type: 'text/plain' }) @@ -74,7 +65,7 @@ const KeystoreFiles = () => { size={16} color="#A1ABBD" style={{ cursor: 'pointer' }} - onClick={clearEncryptedPasswordHandler} + onClick={() => setEncryptedPassword('')} /> } error={encryptedPasswordError} @@ -93,7 +84,7 @@ const KeystoreFiles = () => { size={16} color="#A1ABBD" style={{ cursor: 'pointer' }} - onClick={clearConfirmEncryptedPasswordHandler} + onClick={() => setConfirmEncryptedPassword('')} /> } error={confirmEncryptedPasswordError} From cb39622ab67b3f29dcf5b118da43abcf495c980a Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 16:28:02 +0300 Subject: [PATCH 33/40] fix: change mnemonic var name to new --- .../ConfirmRecoveryPhrase/AutocompleteInput.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx index d5186552..4253254a 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx @@ -37,8 +37,8 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { } const value = e.target.value - const mnemonic = value.trim().split(' ').slice(0, 24) - const mnemonicLength = mnemonic.length + const newMnemonic = value.trim().split(' ').slice(0, 24) + const mnemonicLength = newMnemonic.length let newValidWords = [...validWords] if (mnemonicLength === 1) { @@ -46,15 +46,15 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { newValidWords[index] = generatedMnemonic[index] === value || generatedMnemonic[index].startsWith(value) } else if (mnemonicLength === 24) { - dispatch(setMnemonic(mnemonic)) + dispatch(setMnemonic(newMnemonic)) dispatch(setIsCopyPastedPhrase(true)) - mnemonic.forEach((m, i) => { + newMnemonic.forEach((m, i) => { newValidWords[i] = generatedMnemonic[i] === m }) } else { for (let i = index; i < mnemonicLength + index; i++) { - const mnemonicWord = mnemonic.shift() || '' + const mnemonicWord = newMnemonic.shift() || '' dispatch(setWord({ index: i, word: mnemonicWord })) newValidWords[i] = generatedMnemonic[i] === mnemonicWord } From 6567d76b8f569863808503ebf36422b0093dc810 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 16:35:36 +0300 Subject: [PATCH 34/40] feat: create slice for validator on boarding --- src/redux/ValidatorOnboarding/slice.ts | 15 +++++++++++++++ src/redux/store.ts | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 src/redux/ValidatorOnboarding/slice.ts diff --git a/src/redux/ValidatorOnboarding/slice.ts b/src/redux/ValidatorOnboarding/slice.ts new file mode 100644 index 00000000..642d2e0a --- /dev/null +++ b/src/redux/ValidatorOnboarding/slice.ts @@ -0,0 +1,15 @@ +import { createSlice } from '@reduxjs/toolkit' + +type ValidatorOnboardingState = {} + +const initialState: ValidatorOnboardingState = {} + +const validatorOnboardingSlice = createSlice({ + name: 'validatorOnboarding', + initialState, + reducers: {}, +}) + +export const {} = validatorOnboardingSlice.actions + +export default validatorOnboardingSlice.reducer diff --git a/src/redux/store.ts b/src/redux/store.ts index 592f40af..253fc58d 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -4,6 +4,7 @@ import pinnedMessageReducer from './PinnedMessage/slice' import execClientReducer from './ValidatorOnboarding/ValidatorSetup/slice' import themeReducer from './theme/slice' import keyGenerationReducer from './ValidatorOnboarding/KeyGeneration/slice' +import validatorOnboardingReducer from './ValidatorOnboarding/slice' const store = configureStore({ reducer: { @@ -12,6 +13,7 @@ const store = configureStore({ execClient: execClientReducer, theme: themeReducer, keyGeneration: keyGenerationReducer, + validatorOnboarding: validatorOnboardingReducer, }, }) From ddf94893d44bdc910d676513992cf6b359ee53ea Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 17:03:11 +0300 Subject: [PATCH 35/40] feat: add states and reducers for steps --- src/redux/ValidatorOnboarding/slice.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/redux/ValidatorOnboarding/slice.ts b/src/redux/ValidatorOnboarding/slice.ts index 642d2e0a..fd2d0b52 100644 --- a/src/redux/ValidatorOnboarding/slice.ts +++ b/src/redux/ValidatorOnboarding/slice.ts @@ -1,15 +1,28 @@ -import { createSlice } from '@reduxjs/toolkit' +import { createSlice, PayloadAction } from '@reduxjs/toolkit' -type ValidatorOnboardingState = {} +type ValidatorOnboardingState = { + activeStep: number + subStepValidatorSetup: number +} -const initialState: ValidatorOnboardingState = {} +const initialState: ValidatorOnboardingState = { + activeStep: 0, + subStepValidatorSetup: 0, +} const validatorOnboardingSlice = createSlice({ name: 'validatorOnboarding', initialState, - reducers: {}, + reducers: { + setActiveStep(state, action: PayloadAction) { + state.activeStep = action.payload + }, + setSubStepValidatorSetup(state, action: PayloadAction) { + state.subStepValidatorSetup = action.payload + }, + }, }) -export const {} = validatorOnboardingSlice.actions +export const { setActiveStep, setSubStepValidatorSetup } = validatorOnboardingSlice.actions export default validatorOnboardingSlice.reducer From c119e1ba2766f2249570b1e20a3498abe8c67720 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 17:28:57 +0300 Subject: [PATCH 36/40] feat: use steps with redux and remove states --- .../ContinueButton.stories.ts | 14 +--- .../ValidatorOnboarding/ContinueButton.tsx | 75 ++++++++++++++--- .../FormStepper/FormStepper.stories.ts | 7 -- .../FormStepper/FormStepper.tsx | 18 ++-- .../ValidatorOnboarding.tsx | 84 ++----------------- 5 files changed, 84 insertions(+), 114 deletions(-) diff --git a/src/pages/ValidatorOnboarding/ContinueButton.stories.ts b/src/pages/ValidatorOnboarding/ContinueButton.stories.ts index bd2f02f5..d809d2c9 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.stories.ts +++ b/src/pages/ValidatorOnboarding/ContinueButton.stories.ts @@ -17,17 +17,5 @@ export default meta type Story = StoryObj export const Default: Story = { - args: { - continueHandler: () => {}, - activeStep: 0, - subStepValidatorSetup: 0, - }, -} - -export const Disabled: Story = { - args: { - continueHandler: () => {}, - activeStep: 0, - subStepValidatorSetup: 0, - }, + args: {}, } diff --git a/src/pages/ValidatorOnboarding/ContinueButton.tsx b/src/pages/ValidatorOnboarding/ContinueButton.tsx index 278f7523..5218bd93 100644 --- a/src/pages/ValidatorOnboarding/ContinueButton.tsx +++ b/src/pages/ValidatorOnboarding/ContinueButton.tsx @@ -1,23 +1,35 @@ import { Stack, XStack } from 'tamagui' import { Button, InformationBox } from '@status-im/components' import { CloseCircleIcon } from '@status-im/icons' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useEffect, useState } from 'react' +import { useNavigate } from 'react-router-dom' import { RootState } from '../../redux/store' import LinkWithArrow from '../../components/General/LinkWithArrow' +import { setActiveStep, setSubStepValidatorSetup } from '../../redux/ValidatorOnboarding/slice' +import { KEYSTORE_FILES } from '../../constants' +import { + setIsConfirmPhraseStage, + setIsCopyPastedPhrase, + setValidWords, +} from '../../redux/ValidatorOnboarding/KeyGeneration/slice' -type ContinueButton = { - continueHandler: () => void - activeStep: number - subStepValidatorSetup: number -} - -const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: ContinueButton) => { +const ContinueButton = () => { const [isDisabled, setIsDisabled] = useState(false) - const { isCopyPastedPhrase, mnemonic, validWords, isConfirmPhraseStage } = useSelector( - (state: RootState) => state.keyGeneration, + const { + isCopyPastedPhrase, + mnemonic, + validWords, + isConfirmPhraseStage, + recoveryMechanism, + generatedMnemonic, + } = useSelector((state: RootState) => state.keyGeneration) + const { activeStep, subStepValidatorSetup } = useSelector( + (state: RootState) => state.validatorOnboarding, ) + const dispatch = useDispatch() + const navigate = useNavigate() const isActivationValScreen = activeStep === 3 && subStepValidatorSetup === 3 useEffect(() => { @@ -33,6 +45,49 @@ const ContinueButton = ({ continueHandler, activeStep, subStepValidatorSetup }: setIsDisabled(getDisabledButton()) }, [activeStep, subStepValidatorSetup, isConfirmPhraseStage, mnemonic, validWords]) + const handleStep3 = () => { + subStepValidatorSetup < 3 + ? dispatch(setSubStepValidatorSetup(subStepValidatorSetup + 1)) + : dispatch(setSubStepValidatorSetup(0)) + } + + const handleStep4 = () => { + if (!isConfirmPhraseStage && recoveryMechanism === KEYSTORE_FILES) { + return dispatch(setActiveStep(activeStep + 1)) + } + + if (!isConfirmPhraseStage) { + return dispatch(setIsConfirmPhraseStage(true)) + } + + if (isConfirmPhraseStage) { + const newValidWords = mnemonic.map((w, index) => generatedMnemonic[index] === w) + dispatch(setValidWords(newValidWords)) + + if (!newValidWords.includes(false)) { + setActiveStep(activeStep + 1) + dispatch(setIsConfirmPhraseStage(false)) + if (isCopyPastedPhrase) { + dispatch(setIsCopyPastedPhrase(false)) + } + } + } + } + + const continueHandler = () => { + if (activeStep === 3) { + handleStep3() + } else if (activeStep === 4) { + handleStep4() + } else { + if (activeStep < 5) { + setActiveStep(activeStep + 1) + } else { + navigate('/') + } + } + } + return ( export const OverviewActive: Story = { args: { activeStep: 0, - changeActiveStep: () => {}, }, } export const AdvisoriesActive: Story = { args: { activeStep: 1, - changeActiveStep: () => {}, }, } export const ClientSetupActive: Story = { args: { activeStep: 2, - changeActiveStep: () => {}, }, } export const ValidatorSetupActive: Story = { args: { activeStep: 3, - changeActiveStep: () => {}, }, } export const KeyGenerationActive: Story = { args: { activeStep: 4, - changeActiveStep: () => {}, }, } export const ActivationActive: Story = { args: { activeStep: 5, - changeActiveStep: () => {}, }, } export const NoActiveStep: Story = { args: { activeStep: -1, - changeActiveStep: () => {}, }, } diff --git a/src/pages/ValidatorOnboarding/FormStepper/FormStepper.tsx b/src/pages/ValidatorOnboarding/FormStepper/FormStepper.tsx index c82c721a..f2aa183b 100644 --- a/src/pages/ValidatorOnboarding/FormStepper/FormStepper.tsx +++ b/src/pages/ValidatorOnboarding/FormStepper/FormStepper.tsx @@ -1,10 +1,8 @@ import { Stepper, Step } from 'react-form-stepper' -import './FormStepper.css' +import { useDispatch } from 'react-redux' -type FormStepperProps = { - activeStep: number - changeActiveStep: (step: number) => void -} +import { setActiveStep } from '../../../redux/ValidatorOnboarding/slice' +import './FormStepper.css' const steps = [ { label: 'Overview', subtitle: 'Get Started' }, @@ -15,7 +13,13 @@ const steps = [ { label: 'Activation', subtitle: 'Complete Setup' }, ] -const FormStepper = ({ activeStep, changeActiveStep }: FormStepperProps) => { +type FormStepperProps = { + activeStep: number +} + +const FormStepper = ({ activeStep }: FormStepperProps) => { + const dispatch = useDispatch() + return ( { key={index} label={step.label} className="custom-step" - onClick={() => changeActiveStep(index)} + onClick={() => dispatch(setActiveStep(index))} completed={activeStep > index - 1} data-subtitle={step.subtitle} data-step={step.label} diff --git a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx index 0d17f1ea..3eab4877 100644 --- a/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx +++ b/src/pages/ValidatorOnboarding/ValidatorOnboarding.tsx @@ -1,7 +1,5 @@ import { YStack } from 'tamagui' -import { useNavigate } from 'react-router-dom' -import { useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import FormStepper from './FormStepper/FormStepper' import Titles from '../../components/General/Titles' @@ -15,79 +13,15 @@ import Advisories from './Advisories/Advisories' import ValidatorSetup from './ValidatorSetup/ValidatorSetup/ValidatorSetup' import ValidatorSetupInstall from './ValidatorSetup/ValidatorInstalling/ValidatorInstall' import ContinueButton from './ContinueButton' -import { - setIsConfirmPhraseStage, - setIsCopyPastedPhrase, - setValidWords, -} from '../../redux/ValidatorOnboarding/KeyGeneration/slice' import { RootState } from '../../redux/store' import ActivationValidatorSetup from './ValidatorSetup/ValidatorActivation/ActivationValidatorSetup' -import { KEYSTORE_FILES } from '../../constants' import './layoutGradient.css' const ValidatorOnboarding = () => { - const [activeStep, setActiveStep] = useState(0) - const [subStepValidatorSetup, setSubStepValidatorSetup] = useState(0) - const { - isCopyPastedPhrase, - mnemonic, - isConfirmPhraseStage, - generatedMnemonic, - recoveryMechanism, - } = useSelector((state: RootState) => state.keyGeneration) - const navigate = useNavigate() - const dispatch = useDispatch() - - const changeActiveStep = (step: number) => { - setActiveStep(step) - } - - const handleStep3 = () => { - subStepValidatorSetup < 3 - ? setSubStepValidatorSetup(subStepValidatorSetup + 1) - : setSubStepValidatorSetup(0) - } - - const handleStep4 = () => { - if (!isConfirmPhraseStage && recoveryMechanism === KEYSTORE_FILES) { - return setActiveStep(activeStep + 1) - } - - if (!isConfirmPhraseStage) { - return dispatch(setIsConfirmPhraseStage(true)) - } - - if (isConfirmPhraseStage) { - const newValidWords = mnemonic.map((w, index) => generatedMnemonic[index] === w) - dispatch(setValidWords(newValidWords)) - - if (!newValidWords.includes(false)) { - setActiveStep(activeStep + 1) - removeCopyPastePhraseInfoBox() - dispatch(setIsConfirmPhraseStage(false)) - } - } - } - - const continueHandler = () => { - if (activeStep === 3) { - handleStep3() - } else if (activeStep === 4) { - handleStep4() - } else { - if (activeStep < 5) { - setActiveStep(activeStep + 1) - } else { - navigate('/') - } - } - } - - const removeCopyPastePhraseInfoBox = () => { - if (isCopyPastedPhrase) { - dispatch(setIsCopyPastedPhrase(false)) - } - } + const { activeStep, subStepValidatorSetup } = useSelector( + (state: RootState) => state.validatorOnboarding, + ) + const { isConfirmPhraseStage } = useSelector((state: RootState) => state.keyGeneration) return (
@@ -105,7 +39,7 @@ const ValidatorOnboarding = () => { titleSize={19} subtitle="Earn Rewards for securing the Ethereum Network" /> - + {activeStep === 0 && } {activeStep === 1 && } @@ -140,11 +74,7 @@ const ValidatorOnboarding = () => { /> )} - +
) From f462ab08d91a51e7192d31912e7642aa1007b7af Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 17:35:59 +0300 Subject: [PATCH 37/40] feat: add control to form stepper story --- .../ValidatorOnboarding/FormStepper/FormStepper.stories.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pages/ValidatorOnboarding/FormStepper/FormStepper.stories.ts b/src/pages/ValidatorOnboarding/FormStepper/FormStepper.stories.ts index bb49cb51..a096e8b5 100644 --- a/src/pages/ValidatorOnboarding/FormStepper/FormStepper.stories.ts +++ b/src/pages/ValidatorOnboarding/FormStepper/FormStepper.stories.ts @@ -9,6 +9,13 @@ const meta = { layout: 'centered', }, tags: ['autodocs'], + argTypes: { + activeStep: { + options: [0, 1, 2, 3, 4, 5], + control: { type: 'radio' }, + defaultValue: 0, + }, + }, } satisfies Meta export default meta From e150786725ee4fb79a03acba36ca26154a5aa1fd Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 17:55:31 +0300 Subject: [PATCH 38/40] fix: bug with creating new inputs --- .../KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx index 4253254a..7c00af71 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx @@ -53,7 +53,9 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { newValidWords[i] = generatedMnemonic[i] === m }) } else { - for (let i = index; i < mnemonicLength + index; i++) { + const endIndex = mnemonicLength + index > 24 ? 24 : mnemonicLength + index + + for (let i = index; i < endIndex; i++) { const mnemonicWord = newMnemonic.shift() || '' dispatch(setWord({ index: i, word: mnemonicWord })) newValidWords[i] = generatedMnemonic[i] === mnemonicWord From fa003b3f54a3505ea70ba7107af6b11d6ea0e4ef Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 18:22:08 +0300 Subject: [PATCH 39/40] feat: update code of autocomplete --- .../AutocompleteInput.tsx | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx index 7c00af71..35bca1aa 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx @@ -32,41 +32,47 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { } const handleInputChange = (e: React.ChangeEvent) => { + const { value } = e.target + const newMnemonic = value.trim().split(' ') + const newMnemonicLength = newMnemonic.length + let newValidWords = [...validWords] + if (!isFocused) { handleInputFocus() } - const value = e.target.value - const newMnemonic = value.trim().split(' ').slice(0, 24) - const mnemonicLength = newMnemonic.length - let newValidWords = [...validWords] - - if (mnemonicLength === 1) { - dispatch(setWord({ index, word: value })) - newValidWords[index] = - generatedMnemonic[index] === value || generatedMnemonic[index].startsWith(value) - } else if (mnemonicLength === 24) { - dispatch(setMnemonic(newMnemonic)) - dispatch(setIsCopyPastedPhrase(true)) - - newMnemonic.forEach((m, i) => { - newValidWords[i] = generatedMnemonic[i] === m - }) - } else { - const endIndex = mnemonicLength + index > 24 ? 24 : mnemonicLength + index - - for (let i = index; i < endIndex; i++) { - const mnemonicWord = newMnemonic.shift() || '' - dispatch(setWord({ index: i, word: mnemonicWord })) - newValidWords[i] = generatedMnemonic[i] === mnemonicWord - } - - dispatch(setIsCopyPastedPhrase(true)) + switch (newMnemonicLength) { + case 1: + updateWord(index, value, newValidWords) + break + case 24: + dispatch(setMnemonic(newMnemonic)) + dispatch(setIsCopyPastedPhrase(true)) + break + default: + const endIndex = Math.min(newMnemonicLength + index, 24) + const partialMnemonic = newMnemonic.slice(0, endIndex - index) + dispatch(setIsCopyPastedPhrase(true)) + updateMultipleWords(partialMnemonic, newValidWords, index) + break } dispatch(setValidWords(newValidWords)) } + const updateWord = (idx: number, word: string, validWords: boolean[]) => { + dispatch(setWord({ index: idx, word })) + validWords[idx] = generatedMnemonic[idx] === word || generatedMnemonic[idx].startsWith(word) + } + + const updateMultipleWords = (words: string[], validWords: boolean[], startIndex: number = 0) => { + words.forEach((word, idx) => { + const actualIdx = startIndex + idx + dispatch(setWord({ index: actualIdx, word })) + validWords[actualIdx] = generatedMnemonic[actualIdx] === word + }) + } + const handleSuggestionClick = (e: React.MouseEvent, suggestion: string) => { e.preventDefault() From ea735cb6b5808350a266a897f1f13f20330c3de3 Mon Sep 17 00:00:00 2001 From: RadoslavDimchev Date: Mon, 9 Oct 2023 18:49:19 +0300 Subject: [PATCH 40/40] fix: remove set mnemonic and use ready func --- .../ConfirmRecoveryPhrase/AutocompleteInput.tsx | 3 +-- src/redux/ValidatorOnboarding/KeyGeneration/slice.ts | 5 +---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx index 35bca1aa..b1595c07 100644 --- a/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx +++ b/src/pages/ValidatorOnboarding/KeyGeneration/ConfirmRecoveryPhrase/AutocompleteInput.tsx @@ -5,7 +5,6 @@ import wordlist from 'web-bip39/wordlists/english' import { RootState } from '../../../../redux/store' import { setIsCopyPastedPhrase, - setMnemonic, setValidWords, setWord, } from '../../../../redux/ValidatorOnboarding/KeyGeneration/slice' @@ -46,8 +45,8 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => { updateWord(index, value, newValidWords) break case 24: - dispatch(setMnemonic(newMnemonic)) dispatch(setIsCopyPastedPhrase(true)) + updateMultipleWords(newMnemonic, newValidWords) break default: const endIndex = Math.min(newMnemonicLength + index, 24) diff --git a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts index de320f6c..94e1c5d3 100644 --- a/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts +++ b/src/redux/ValidatorOnboarding/KeyGeneration/slice.ts @@ -1,4 +1,5 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit' + import { KEYSTORE_FILES } from '../../../constants' type KeyGenerationState = { @@ -33,9 +34,6 @@ const keyGenerationSlice = createSlice({ newMnemonic[action.payload.index] = action.payload.word state.mnemonic = newMnemonic }, - setMnemonic: (state, action: PayloadAction) => { - state.mnemonic = action.payload - }, setIsCopyPastedPhrase: (state, action: PayloadAction) => { state.isCopyPastedPhrase = action.payload }, @@ -56,7 +54,6 @@ const keyGenerationSlice = createSlice({ export const { setWord, - setMnemonic, setIsCopyPastedPhrase, setValidWords, setGeneratedMnemonic,