Skip to content

Commit

Permalink
refactor the validatedTextInput functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mgold1234 committed Dec 12, 2024
1 parent 2380207 commit 0b3a569
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 79 deletions.
111 changes: 40 additions & 71 deletions src/Components/CreateImageWizard/ValidatedTextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ interface HookValidatedTextInputWithButtonPropTypes
isEmpty: boolean;
}

const getValidatedState = (
isPristine: boolean,
isEmpty: boolean | undefined,
stepValidation: StepValidation,
fieldName: string
): 'default' | 'error' | 'success' => {
if (isEmpty) return 'default';
if (isPristine) return 'default';
if (stepValidation.errors[fieldName] === 'default') return 'default';
return stepValidation.errors[fieldName] ? 'error' : 'success';
};

export const HookValidatedInput = ({
dataTestId,
ouiaId,
Expand All @@ -67,13 +79,6 @@ export const HookValidatedInput = ({
const [isPristine, setIsPristine] = useState(!value ? true : false);
// Do not surface validation on pristine state components
// Allow step validation to be set on pristine state, when needed
const validated = isPristine
? 'default'
: stepValidation.errors[fieldName] === 'default'
? 'default'
: stepValidation.errors[fieldName]
? 'error'
: 'success';

const handleBlur = () => {
setIsPristine(false);
Expand All @@ -87,13 +92,19 @@ export const HookValidatedInput = ({
ouiaId={ouiaId || ''}
type={type}
onChange={onChange!}
validated={validated}
validated={getValidatedState(
isPristine,
undefined,
stepValidation,
fieldName
)}
aria-label={ariaLabel || ''}
onBlur={handleBlur}
placeholder={placeholder || ''}
isDisabled={isDisabled || false}
/>
{validated === 'error' && (
{getValidatedState(isPristine, undefined, stepValidation, fieldName) ===
'error' && (
<HelperText>
<HelperTextItem variant="error" hasIcon>
{stepValidation.errors[fieldName]}
Expand All @@ -111,60 +122,13 @@ export const HookValidatedInput = ({
);
};

// Lucas I tried to write a wrapper function that reuse as much as I can the exciting code,
// and there is a bug with that code - the error message appears on the right side instead of under the input.
export const HookValidatedInputWithPasswordVisibilityButton1 = (
props: HookValidatedTextInputWithButtonPropTypes
) => {
const { togglePasswordVisibility, isPasswordVisible, ...restProps } = props;
return (
<>
<div
style={{ position: 'relative', display: 'flex', alignItems: 'center' }}
>
<HookValidatedInput {...restProps} style={{ paddingRight: '2rem' }} />
<Button
variant="plain"
onClick={togglePasswordVisibility}
aria-label="Toggle password visibility"
style={{
position: 'absolute',
right: '0.5rem',
}}
>
{isPasswordVisible ? <EyeSlashIcon /> : <EyeIcon />}
</Button>
</div>
{restProps.validated === 'error' && (
<HelperText>
<HelperTextItem variant="error" hasIcon>
{restProps.stepValidation.errors[restProps.fieldName]}
</HelperTextItem>
</HelperText>
)}
</>
);
};

// this function also reuse some of the code and works as it should be -
// error message appears under the input
export const HookValidatedInputWithPasswordVisibilityButton = (
props: HookValidatedTextInputWithButtonPropTypes
) => {
const { togglePasswordVisibility, isPasswordVisible, ...restProps } = props;
const [isPristine, setIsPristine] = useState(!restProps.value ? true : false);
// Do not surface validation on pristine state components
// Allow step validation to be set on pristine state, when needed
const validated = restProps.isEmpty
? 'default'
: isPristine
? 'default'
: restProps.stepValidation.errors[restProps.fieldName] === 'default'
? 'default'
: restProps.stepValidation.errors[restProps.fieldName]
? 'error'
: 'success';

const handleBlur = () => {
setIsPristine(false);
};
Expand All @@ -179,7 +143,12 @@ export const HookValidatedInputWithPasswordVisibilityButton = (
onChange={restProps.onChange!}
ouiaId={restProps.ouiaId || ''}
aria-label={restProps.ariaLabel || ''}
validated={validated}
validated={getValidatedState(
isPristine,
restProps.isEmpty,
restProps.stepValidation,
restProps.fieldName
)}
type={restProps.type || 'text'}
placeholder={restProps.placeholder || ''}
onBlur={handleBlur}
Expand All @@ -197,7 +166,12 @@ export const HookValidatedInputWithPasswordVisibilityButton = (
{isPasswordVisible ? <EyeSlashIcon /> : <EyeIcon />}
</Button>
</div>
{validated === 'error' && (
{getValidatedState(
isPristine,
restProps.isEmpty,
restProps.stepValidation,
restProps.fieldName
) === 'error' && (
<HelperText>
<HelperTextItem variant="error" hasIcon>
{restProps.stepValidation.errors[restProps.fieldName]}
Expand Down Expand Up @@ -271,17 +245,6 @@ export const HookValidatedTextArea = ({
const [isPristine, setIsPristine] = useState(!value ? true : false);
// Do not surface validation on pristine state components
// Allow step validation to be set on pristine state, when needed
const validated = isEmpty
? 'default'
: isDisabled
? 'default'
: isPristine
? 'default'
: stepValidation.errors[fieldName] === 'default'
? 'default'
: stepValidation.errors[fieldName]
? 'error'
: 'success';

const handleBlur = () => {
setIsPristine(false);
Expand All @@ -299,13 +262,19 @@ export const HookValidatedTextArea = ({
data-testid={dataTestId}
type={type}
onChange={handleChange}
validated={validated}
validated={getValidatedState(
isPristine,
isEmpty,
stepValidation,
fieldName
)}
aria-label={ariaLabel || ''}
onBlur={handleBlur}
placeholder={placeholder}
isDisabled={isDisabled}
/>
{validated === 'error' && (
{getValidatedState(isPristine, isEmpty, stepValidation, fieldName) ===
'error' && (
<HelperText>
<HelperTextItem variant="error" hasIcon>
{stepValidation.errors[fieldName]}
Expand Down
18 changes: 10 additions & 8 deletions src/Components/CreateImageWizard/utilities/useValidation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,16 +186,18 @@ export function useUserValidation(): StepValidation {
const sshKeyValid = isSshKeyValid(userSshKey || '');
const isPasswordAndConfirmValid = passwordValid && passwordConfirmMatchValid;
const canProceed =
// Case 1: there is no users
users.length === 0 ||
(userConfirmPassword === '' &&
userSshKey === '' &&
// Case 2: All fields are empty
(userName === '' &&
userPassword === '' &&
userName === '') ||
(userPassword === '' && userConfirmPassword === '' && userName !== '') ||
(userName &&
userNameValid &&
((userSshKey && sshKeyValid) ||
(userPassword && isPasswordAndConfirmValid)));
userConfirmPassword === '' &&
userSshKey === '') ||
// Case 3: Name and password are valid
(userName && userNameValid && userPassword && isPasswordAndConfirmValid) ||
// Case 4: Name and SSH Key are valid
(userName && userNameValid && userSshKey && sshKeyValid);

return {
errors: {
userName: !userNameValid
Expand Down

0 comments on commit 0b3a569

Please sign in to comment.