mirror of
https://github.com/status-im/nimbus-gui.git
synced 2025-02-22 16:18:31 +00:00
feat: add live autocomplete validation
This commit is contained in:
parent
1c52097350
commit
042b0fd0cb
@ -12,17 +12,20 @@ import styles from './AutocompleteInput.module.css'
|
||||
|
||||
type AutocompleteInputProps = {
|
||||
index: number
|
||||
isValid: boolean
|
||||
changeIsValid: (isValid: boolean, index: number) => void
|
||||
}
|
||||
|
||||
const AutocompleteInput = ({ index }: AutocompleteInputProps) => {
|
||||
const AutocompleteInput = ({ index, isValid, changeIsValid }: AutocompleteInputProps) => {
|
||||
const [suggestions, setSuggestions] = useState<string[]>([])
|
||||
const [isFocused, setIsFocused] = useState(false)
|
||||
const word = useSelector((state: RootState) => state.keyGeneration.words[index])
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
setSuggestions(wordlist.filter(w => w.startsWith(word.toLowerCase())))
|
||||
}, [word])
|
||||
const newSuggestions = getNewSuggestions(word)
|
||||
setSuggestions(newSuggestions)
|
||||
}, [])
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (!isFocused) {
|
||||
@ -35,6 +38,11 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => {
|
||||
|
||||
if (mnemonicLength === 1) {
|
||||
dispatch(setWord({ index, word: value }))
|
||||
|
||||
const newSuggestions = getNewSuggestions(value)
|
||||
setSuggestions(newSuggestions)
|
||||
|
||||
changeIsValid(isWordValidTyping(value, newSuggestions), index)
|
||||
} else if (mnemonicLength === 24) {
|
||||
dispatch(setMnemonic(mnemonic))
|
||||
dispatch(setIsCopyPastedPhrase(true))
|
||||
@ -51,6 +59,8 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => {
|
||||
|
||||
setIsFocused(false)
|
||||
dispatch(setWord({ index, word: suggestion }))
|
||||
|
||||
changeIsValid(isWordValidBlur(suggestion), index)
|
||||
}
|
||||
|
||||
const handleInputFocus = () => {
|
||||
@ -59,6 +69,19 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => {
|
||||
|
||||
const handleInputBlur = () => {
|
||||
setIsFocused(false)
|
||||
changeIsValid(isWordValidBlur(word), index)
|
||||
}
|
||||
|
||||
const getNewSuggestions = (value: string) => {
|
||||
return wordlist.filter(w => w.startsWith(value.toLowerCase()))
|
||||
}
|
||||
|
||||
const isWordValidTyping = (value: string, newSuggestions: string[]) => {
|
||||
return wordlist.includes(value) || newSuggestions.length > 0 || value === ''
|
||||
}
|
||||
|
||||
const isWordValidBlur = (value: string) => {
|
||||
return wordlist.includes(value)
|
||||
}
|
||||
|
||||
return (
|
||||
@ -71,7 +94,7 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => {
|
||||
onChange={handleInputChange}
|
||||
onFocus={handleInputFocus}
|
||||
onBlur={handleInputBlur}
|
||||
style={inputStyle(index, isFocused)}
|
||||
style={inputStyle(index, isFocused, isValid)}
|
||||
/>
|
||||
</div>
|
||||
<div className={isFocused ? styles['suggestion-list'] : ''}>
|
||||
@ -92,16 +115,17 @@ const AutocompleteInput = ({ index }: AutocompleteInputProps) => {
|
||||
|
||||
export default AutocompleteInput
|
||||
|
||||
const inputStyle = (index: number, isFocused: boolean) => {
|
||||
const inputStyle = (index: number, isFocused: boolean, isValid: boolean) => {
|
||||
const style = {
|
||||
outline: 'none',
|
||||
padding: `12px 16px 12px ${index + 1 < 10 ? '35px' : '45px'}`,
|
||||
border: isValid ? 'none' : '2px solid #E53E3E',
|
||||
}
|
||||
|
||||
if (isFocused) {
|
||||
return {
|
||||
...style,
|
||||
border: '2px solid #4360DF',
|
||||
border: isValid ? '2px solid #4360DF' : '2px solid #E53E3E',
|
||||
backgroundColor: '#f1f2f4',
|
||||
}
|
||||
} else {
|
||||
|
@ -3,8 +3,33 @@ import { Text } from '@status-im/components'
|
||||
|
||||
import AutocompleteInput from './AutocompleteInput'
|
||||
import KeyGenerationTitle from '../KeyGenerationTitle'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { setIsRightPhrase } from '../../../../redux/ValidatorOnboarding/KeyGeneration/slice'
|
||||
import { RootState } from '../../../../redux/store'
|
||||
|
||||
const ConfirmRecoveryPhrase = () => {
|
||||
const [validWords, setValidWords] = useState<boolean[]>([])
|
||||
const { words } = useSelector((state: RootState) => state.keyGeneration)
|
||||
const dispatch = useDispatch()
|
||||
|
||||
useEffect(() => {
|
||||
const newValidWords = Array.from({ length: 24 }).map(() => true)
|
||||
setValidWords(newValidWords)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const isValidWords = validWords.every(isValid => isValid)
|
||||
const isFilledWords = words.every(word => word !== '')
|
||||
dispatch(setIsRightPhrase(isValidWords && isFilledWords))
|
||||
}, [validWords])
|
||||
|
||||
const changeIsValid = (isValid: boolean, index: number) => {
|
||||
const newValidWords = [...validWords]
|
||||
newValidWords[index] = isValid
|
||||
setValidWords(newValidWords)
|
||||
}
|
||||
|
||||
return (
|
||||
<YStack space={'$4'} style={{ width: '100%', marginTop: '20px' }}>
|
||||
<KeyGenerationTitle />
|
||||
@ -19,7 +44,12 @@ const ConfirmRecoveryPhrase = () => {
|
||||
}}
|
||||
>
|
||||
{Array.from({ length: 24 }).map((_, index) => (
|
||||
<AutocompleteInput key={index} index={index} />
|
||||
<AutocompleteInput
|
||||
key={index}
|
||||
index={index}
|
||||
isValid={validWords[index]}
|
||||
changeIsValid={changeIsValid}
|
||||
/>
|
||||
))}
|
||||
</Stack>
|
||||
</YStack>
|
||||
|
Loading…
x
Reference in New Issue
Block a user