refactor: improve form validation

This commit is contained in:
kyranjamie
2023-06-08 11:15:58 +02:00
committed by kyranjamie
parent d5720b9c90
commit 51f305d726
5 changed files with 28 additions and 17 deletions

View File

@@ -0,0 +1,14 @@
import { useField, useFormikContext } from 'formik';
function useIsFieldDirty(name: string) {
const [field, meta] = useField(name);
return field.value !== meta.initialValue;
}
export function useShowFieldError(name: string) {
const form = useFormikContext();
const [_, meta] = useField(name);
const isDirty = useIsFieldDirty(name);
return (form.submitCount > 0 && meta.error) || (meta.touched && isDirty && meta.error);
}

View File

@@ -7,6 +7,7 @@ import { useField } from 'formik';
import { STX_DECIMALS } from '@shared/constants';
import { Money } from '@shared/models/money.model';
import { useShowFieldError } from '@app/common/form-utils';
import { figmaTheme } from '@app/common/utils/figma-theme';
import { ErrorLabel } from '@app/components/error-label';
@@ -51,6 +52,7 @@ export function AmountField({
tokenSymbol,
}: AmountFieldProps) {
const [field, meta, helpers] = useField('amount');
const showError = useShowFieldError('amount');
const [fontSize, setFontSize] = useState(maxFontSize);
const [previousTextLength, setPreviousTextLength] = useState(1);
@@ -106,7 +108,7 @@ export function AmountField({
<Stack
alignItems="center"
px="extra-loose"
spacing={['base', meta.error && meta.touched ? 'base' : '48px']}
spacing={['base', showError ? 'base' : '48px']}
width="100%"
>
<Flex alignItems="center" flexDirection="column" onClick={onClickFocusInput}>
@@ -137,13 +139,6 @@ export function AmountField({
fontWeight={500}
autoComplete={autoComplete}
{...field}
// Custom `onBlur` logic. If value is empty, let's not validate to
// avoid unwanted blur interactions such as when interacting with
// send max button
onBlur={e => {
if (!field.value || field.value === '0') return;
return field.onBlur(e);
}}
/>
<Text fontSize={fontSize + 'px'} pl="tight">
{symbol.toUpperCase()}
@@ -151,7 +146,7 @@ export function AmountField({
</Flex>
<Box mt="12px">{switchableAmount && switchableAmount}</Box>
</Flex>
{meta.error && meta.touched && (
{showError && (
<ErrorLabel data-testid={SendCryptoAssetSelectors.AmountFieldInputErrorLabel}>
{meta.error}
</ErrorLabel>

View File

@@ -5,17 +5,17 @@ import { Box, Flex } from '@stacks/ui';
import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import { useField } from 'formik';
import { useShowFieldError } from '@app/common/form-utils';
import { ErrorLabel } from '@app/components/error-label';
const closedHeight = 0;
const openHeight = 24;
export function FieldError(props: { name: string }) {
export function TextInputFieldError(props: { name: string }) {
const { name } = props;
const [, meta] = useField(name);
const [showHide, setShowHide] = useState(closedHeight);
const showError = meta.touched && meta.error;
const showError = useShowFieldError(name);
useEffect(() => {
if (meta.touched && meta.error) {

View File

@@ -3,10 +3,11 @@ import { Box, Flex, FlexProps, Input, Text, color } from '@stacks/ui';
import { SendCryptoAssetSelectors } from '@tests/selectors/send.selectors';
import { useField } from 'formik';
import { useShowFieldError } from '@app/common/form-utils';
import { capitalize } from '@app/common/utils';
import { SpaceBetween } from '@app/components/layout/space-between';
import { FieldError } from './field-error';
import { TextInputFieldError } from './field-error';
interface TextInputFieldProps extends FlexProps {
dataTestId?: string;
@@ -31,9 +32,9 @@ export function TextInputField({
topInputOverlay,
...props
}: TextInputFieldProps) {
const [field, meta] = useField(name);
const [field] = useField(name);
const showError = meta.error && meta.touched;
const showError = useShowFieldError(name);
return (
<>
@@ -120,7 +121,7 @@ export function TextInputField({
}}
/>
</Flex>
<FieldError name={name} />
<TextInputFieldError name={name} />
</>
);
}

View File

@@ -70,7 +70,8 @@ export function useBtcSendForm() {
.string()
.concat(btcAddressValidator())
.concat(btcAddressNetworkValidator(currentNetwork.chain.bitcoin.network))
.concat(notCurrentAddressValidator(currentAccountBtcAddress || '')),
.concat(notCurrentAddressValidator(currentAccountBtcAddress || ''))
.required('Enter a bitcoin address'),
}),
async chooseTransactionFee(