Skip to content

Commit

Permalink
fix: Required custom field consider blank space as valid input (#29635)
Browse files Browse the repository at this point in the history
  • Loading branch information
aleksandernsilva committed Jul 1, 2023
1 parent ee75fc2 commit baaa38f
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/olive-pears-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/ui-client': patch
---

Fixed required custom fields considering blank spaces as valid.
46 changes: 28 additions & 18 deletions packages/ui-client/src/components/CustomFieldsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import type { SelectOption } from '@rocket.chat/fuselage';
import { Field, Select, TextInput } from '@rocket.chat/fuselage';
import type { TranslationKey } from '@rocket.chat/ui-contexts';
import { useTranslation } from '@rocket.chat/ui-contexts';
import { useCallback, useMemo } from 'react';
import type { Control, FieldValues } from 'react-hook-form';
import { Controller } from 'react-hook-form';
import { Controller, useFormState, get } from 'react-hook-form';

type CustomFieldFormProps<T extends FieldValues> = {
metadata: CustomFieldMetadata[];
Expand Down Expand Up @@ -33,42 +34,51 @@ const CustomField = <T extends FieldValues>({
...props
}: CustomFieldProps<T>) => {
const t = useTranslation();
const { getFieldState } = control;
const { errors } = useFormState({ control });

const Component = FIELD_TYPES[type] ?? null;

const selectOptions =
options.length > 0 && options[0] instanceof Array ? options : options.map((option) => [option, option, defaultValue === option]);
const selectOptions = useMemo(
() =>
options.length > 0 && options[0] instanceof Array ? options : options.map((option) => [option, option, defaultValue === option]),
[defaultValue, options],
);

const validateRequired = useCallback((value) => (required ? typeof value === 'string' && !!value.trim() : true), [required]);

const getErrorMessage = (error: any) => {
switch (error?.type) {
case 'required':
return t('The_field_is_required', label || name);
case 'minLength':
return t('Min_length_is', props?.minLength);
case 'maxLength':
return t('Max_length_is', props?.maxLength);
}
};
const getErrorMessage = useCallback(
(error: any) => {
switch (error?.type) {
case 'required':
return t('The_field_is_required', label || name);
case 'minLength':
return t('Min_length_is', props?.minLength);
case 'maxLength':
return t('Max_length_is', props?.maxLength);
}
},
[label, name, props?.maxLength, props?.minLength, t],
);

const error = getErrorMessage(getFieldState(name as any).error);
const error = get(errors, name);
const errorMessage = useMemo(() => getErrorMessage(error), [error, getErrorMessage]);

return (
<Controller<T, any>
name={name}
control={control}
defaultValue={defaultValue ?? ''}
rules={{ required, minLength: props.minLength, maxLength: props.maxLength }}
rules={{ minLength: props.minLength, maxLength: props.maxLength, validate: { required: validateRequired } }}
render={({ field }) => (
<Field rcx-field-group__item>
<Field.Label>
{label || t(name as TranslationKey)}
{required && '*'}
</Field.Label>
<Field.Row>
<Component {...props} {...field} error={error} options={selectOptions as SelectOption[]} flexGrow={1} />
<Component {...props} {...field} error={errorMessage} options={selectOptions as SelectOption[]} flexGrow={1} />
</Field.Row>
<Field.Error>{error}</Field.Error>
<Field.Error>{errorMessage}</Field.Error>
</Field>
)}
/>
Expand Down

0 comments on commit baaa38f

Please sign in to comment.