-
Notifications
You must be signed in to change notification settings - Fork 467
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
UI – Updates to confirm invite flow (#25583)
## For #24486 - Check invite validity before rendering form, error if invalid - Use data returned from validity check to pre-populate form - Remove dependence of flow on URL params other than token - Remove other URL params from link generated in invite confirmation email - Refactor form from JS to TS - Refactor form from class to functional components - Cleanup unused logic - Improve error handling **Invalid invite** ![invalid](https://github.com/user-attachments/assets/c42c47ca-6a0d-4112-89ea-68b77e748d12) **Valid invite** ![valid-login-flow](https://github.com/user-attachments/assets/f2b97306-a1bd-47be-9725-968a3c4ad8a8) - [x] Changes file added for user-visible changes in `changes/` - [x] Updated tests - [ ] A detailed QA plan exists on the associated ticket (if it isn't there, work with the product group's QA engineer to add it) - [x] Manual QA for all new/changed functionality --------- Co-authored-by: Jacob Shandling <[email protected]>
- Loading branch information
1 parent
11319fd
commit 55fd95d
Showing
11 changed files
with
315 additions
and
128 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
- Check the server for validity of any Fleet invites |
70 changes: 0 additions & 70 deletions
70
frontend/components/forms/ConfirmInviteForm/ConfirmInviteForm.jsx
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
149 changes: 149 additions & 0 deletions
149
frontend/components/forms/ConfirmInviteForm/ConfirmInviteForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
import React, { useCallback, useState } from "react"; | ||
|
||
import validateEquality from "components/forms/validators/validate_equality"; | ||
|
||
import Button from "components/buttons/Button"; | ||
// @ts-ignore | ||
import InputField from "components/forms/fields/InputField"; | ||
import { IFormField } from "interfaces/form_field"; | ||
|
||
const baseClass = "confirm-invite-page__form"; | ||
export interface IConfirmInviteFormData { | ||
name: string; | ||
password: string; | ||
password_confirmation: string; | ||
} | ||
interface IConfirmInviteFormProps { | ||
defaultFormData?: Partial<IConfirmInviteFormData>; | ||
handleSubmit: (data: IConfirmInviteFormData) => void; | ||
ancestorError?: string; | ||
} | ||
interface IConfirmInviteFormErrors { | ||
name?: string | null; | ||
password?: string | null; | ||
password_confirmation?: string | null; | ||
} | ||
|
||
const validate = (formData: IConfirmInviteFormData) => { | ||
const errors: IConfirmInviteFormErrors = {}; | ||
const { | ||
name, | ||
password, | ||
password_confirmation: passwordConfirmation, | ||
} = formData; | ||
|
||
if (!name) { | ||
errors.name = "Full name must be present"; | ||
} | ||
|
||
if ( | ||
password && | ||
passwordConfirmation && | ||
!validateEquality(password, passwordConfirmation) | ||
) { | ||
errors.password_confirmation = | ||
"Password confirmation does not match password"; | ||
} | ||
|
||
if (!password) { | ||
errors.password = "Password must be present"; | ||
} | ||
|
||
if (!passwordConfirmation) { | ||
errors.password_confirmation = "Password confirmation must be present"; | ||
} | ||
|
||
return errors; | ||
}; | ||
const ConfirmInviteForm = ({ | ||
defaultFormData, | ||
handleSubmit, | ||
ancestorError, | ||
}: IConfirmInviteFormProps) => { | ||
const [formData, setFormData] = useState<IConfirmInviteFormData>({ | ||
name: defaultFormData?.name || "", | ||
password: defaultFormData?.password || "", | ||
password_confirmation: defaultFormData?.password || "", | ||
}); | ||
const [formErrors, setFormErrors] = useState<IConfirmInviteFormErrors>({}); | ||
|
||
const { name, password, password_confirmation } = formData; | ||
|
||
const onInputChange = ({ name: n, value }: IFormField) => { | ||
const newFormData = { ...formData, [n]: value }; | ||
setFormData(newFormData); | ||
const newErrs = validate(newFormData); | ||
// only set errors that are updates of existing errors | ||
// new errors are only set on submit | ||
const errsToSet: Record<string, string> = {}; | ||
Object.keys(formErrors).forEach((k) => { | ||
// @ts-ignore | ||
if (newErrs[k]) { | ||
// @ts-ignore | ||
errsToSet[k] = newErrs[k]; | ||
} | ||
}); | ||
setFormErrors(errsToSet); | ||
}; | ||
|
||
const onSubmit = useCallback( | ||
(evt: React.FormEvent<HTMLFormElement>) => { | ||
evt.preventDefault(); | ||
|
||
const errs = validate(formData); | ||
if (Object.keys(errs).length > 0) { | ||
setFormErrors(errs); | ||
return; | ||
} | ||
handleSubmit(formData); | ||
}, | ||
[formData, handleSubmit] | ||
); | ||
|
||
return ( | ||
<form onSubmit={onSubmit} className={baseClass} autoComplete="off"> | ||
{ancestorError && <div className="form__base-error">{ancestorError}</div>} | ||
<InputField | ||
label="Full name" | ||
autofocus | ||
onChange={onInputChange} | ||
name="name" | ||
value={name} | ||
error={formErrors.name} | ||
parseTarget | ||
maxLength={80} | ||
/> | ||
<InputField | ||
label="Password" | ||
type="password" | ||
placeholder="Password" | ||
helpText="Must include 12 characters, at least 1 number (e.g. 0 - 9), and at least 1 symbol (e.g. &*#)" | ||
onChange={onInputChange} | ||
name="password" | ||
value={password} | ||
error={formErrors.password} | ||
parseTarget | ||
/> | ||
<InputField | ||
label="Confirm password" | ||
type="password" | ||
placeholder="Confirm password" | ||
onChange={onInputChange} | ||
name="password_confirmation" | ||
value={password_confirmation} | ||
error={formErrors.password_confirmation} | ||
parseTarget | ||
/> | ||
<Button | ||
type="submit" | ||
disabled={Object.keys(formErrors).length > 0} | ||
className="confirm-invite-button" | ||
variant="brand" | ||
> | ||
Submit | ||
</Button> | ||
</form> | ||
); | ||
}; | ||
|
||
export default ConfirmInviteForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { size } from "lodash"; | ||
import validateEquality from "components/forms/validators/validate_equality"; | ||
|
||
const validate = (formData) => { | ||
const errors = {}; | ||
const { | ||
name, | ||
password, | ||
password_confirmation: passwordConfirmation, | ||
} = formData; | ||
|
||
if (!name) { | ||
errors.name = "Full name must be present"; | ||
} | ||
|
||
if ( | ||
password && | ||
passwordConfirmation && | ||
!validateEquality(password, passwordConfirmation) | ||
) { | ||
errors.password_confirmation = | ||
"Password confirmation does not match password"; | ||
} | ||
|
||
if (!password) { | ||
errors.password = "Password must be present"; | ||
} | ||
|
||
if (!passwordConfirmation) { | ||
errors.password_confirmation = "Password confirmation must be present"; | ||
} | ||
|
||
const valid = !size(errors); | ||
|
||
return { valid, errors }; | ||
}; | ||
|
||
export default { validate }; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.