From f9ed1466e995002a0bbe905d7a33cb44119aaa55 Mon Sep 17 00:00:00 2001 From: kleyberthsantos Date: Sun, 25 Aug 2024 02:51:51 -0400 Subject: [PATCH] feat: Add validation for federation name and dynamic warning message in setup forms --- .../setConfiguration/BasicSettingsForm.tsx | 22 ++++++++++++-- .../FederationSettingsForm.tsx | 29 ++++++++++++++++++- .../setConfiguration/SetConfiguration.tsx | 11 ++++++- apps/guardian-ui/src/languages/en.json | 1 + 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/apps/guardian-ui/src/components/setup/screens/setConfiguration/BasicSettingsForm.tsx b/apps/guardian-ui/src/components/setup/screens/setConfiguration/BasicSettingsForm.tsx index 848476096..e02128fe0 100644 --- a/apps/guardian-ui/src/components/setup/screens/setConfiguration/BasicSettingsForm.tsx +++ b/apps/guardian-ui/src/components/setup/screens/setConfiguration/BasicSettingsForm.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { FormControl, FormLabel, @@ -22,6 +22,7 @@ interface BasicSettingsFormProps { setMyName: (name: string) => void; password: string | null; setPassword: (password: string) => void; + isNextDisabled: (disabled: boolean) => void; } export const BasicSettingsForm: React.FC = ({ @@ -29,11 +30,24 @@ export const BasicSettingsForm: React.FC = ({ setMyName, password, setPassword, + isNextDisabled, }) => { const { t } = useTranslation(); const theme = useTheme(); const [showPassword, setShowPassword] = useState(false); + const validateName = useCallback( + (name: string) => { + const isValid = name.trim() !== '' && /^[a-zA-Z0-9]/.test(name); + isNextDisabled(!isValid); + }, + [isNextDisabled] + ); + + useEffect(() => { + validateName(myName); + }, [myName, validateName]); + return ( = ({ value={myName} onChange={(ev) => setMyName(ev.currentTarget.value)} /> - {t('set-config.guardian-name-help')} + + {myName.trim() === '' + ? t('set-config.give-federation-name') + : t('set-config.guardian-name-help')} + {t('set-config.admin-password')} diff --git a/apps/guardian-ui/src/components/setup/screens/setConfiguration/FederationSettingsForm.tsx b/apps/guardian-ui/src/components/setup/screens/setConfiguration/FederationSettingsForm.tsx index fa44aedc5..788076dda 100644 --- a/apps/guardian-ui/src/components/setup/screens/setConfiguration/FederationSettingsForm.tsx +++ b/apps/guardian-ui/src/components/setup/screens/setConfiguration/FederationSettingsForm.tsx @@ -1,10 +1,12 @@ -import React from 'react'; +import React, { useState, useEffect, useCallback } from 'react'; import { FormControl, FormHelperText, + Text, FormLabel, Input, Select, + useTheme, } from '@chakra-ui/react'; import { useTranslation } from '@fedimint/utils'; import { FormGroup } from '@fedimint/ui'; @@ -36,6 +38,23 @@ export const FederationSettingsForm: React.FC = ({ setNumPeers, }) => { const { t } = useTranslation(); + const theme = useTheme(); + const [nameHelpText, setNameHelpText] = useState(null); + + const validateFederationName = useCallback( + (name: string) => { + if (name.trim() === '') { + setNameHelpText(t('set-config.give-federation-name')); + } else { + setNameHelpText(null); + } + }, + [t] + ); + + useEffect(() => { + validateFederationName(federationName); + }, [federationName, validateFederationName]); return ( = ({ validateFederationName(federationName)} /> + {nameHelpText && ( + + + {nameHelpText || t('set-config.guardian-name-help')} + + + )} {isHost && ( diff --git a/apps/guardian-ui/src/components/setup/screens/setConfiguration/SetConfiguration.tsx b/apps/guardian-ui/src/components/setup/screens/setConfiguration/SetConfiguration.tsx index 2eb4cd753..99e76cf2f 100644 --- a/apps/guardian-ui/src/components/setup/screens/setConfiguration/SetConfiguration.tsx +++ b/apps/guardian-ui/src/components/setup/screens/setConfiguration/SetConfiguration.tsx @@ -70,6 +70,7 @@ export const SetConfiguration: React.FC = ({ next }: Props) => { stateNumPeers ? stateNumPeers.toString() : isSolo ? '1' : MIN_BFT_NUM_PEERS ); + const [isNextDisabled, setIsNextDisabled] = useState(true); const { isOpen, onOpen, onClose } = useDisclosure(); useEffect(() => { @@ -117,6 +118,12 @@ export const SetConfiguration: React.FC = ({ next }: Props) => { setPassword(statePassword); }, [statePassword]); + // Validate if the name of the Federation is valid + const validateFederationName = (name: string) => { + const isValid = name.trim() !== '' && /^[a-zA-Z0-9]/.test(name); + setIsNextDisabled(!isValid); + }; + const hostCriteria = [ myName, password, @@ -149,6 +156,7 @@ export const SetConfiguration: React.FC = ({ next }: Props) => { ) => { const newName = ev.currentTarget.value; setFederationName(newName); + validateFederationName(newName); setMetaFields((prev) => prev.map(([key, val]) => key === 'federation_name' ? [key, newName] : [key, val] @@ -253,9 +261,10 @@ export const SetConfiguration: React.FC = ({ next }: Props) => { setMyName={setMyName} password={password} setPassword={setPassword} + isNextDisabled={setIsNextDisabled} />