refactor(SW-360): extract password validation outside main NewPassword component to minimize re-renders.

This commit is contained in:
Chuma McPhoy
2024-11-25 15:25:12 +01:00
parent c8eaae7928
commit c14fe6bc86

View File

@@ -36,21 +36,6 @@ export default function NewPassword({
const intl = useIntl() const intl = useIntl()
const [isPasswordVisible, setIsPasswordVisible] = useState(false) const [isPasswordVisible, setIsPasswordVisible] = useState(false)
function getErrorMessage(key: PasswordValidatorKey) {
switch (key) {
case "length":
return `10 ${intl.formatMessage({ id: "to" })} 40 ${intl.formatMessage({ id: "characters" })}`
case "hasUppercase":
return `1 ${intl.formatMessage({ id: "uppercase letter" })}`
case "hasLowercase":
return `1 ${intl.formatMessage({ id: "lowercase letter" })}`
case "hasNumber":
return `1 ${intl.formatMessage({ id: "number" })}`
case "hasSpecialChar":
return `1 ${intl.formatMessage({ id: "special character" })}`
}
}
return ( return (
<Controller <Controller
disabled={disabled} disabled={disabled}
@@ -59,6 +44,7 @@ export default function NewPassword({
rules={registerOptions} rules={registerOptions}
render={({ field, fieldState, formState }) => { render={({ field, fieldState, formState }) => {
const errors = Object.values(formState.errors[name]?.types ?? []).flat() const errors = Object.values(formState.errors[name]?.types ?? []).flat()
return ( return (
<TextField <TextField
aria-label={ariaLabel} aria-label={ariaLabel}
@@ -100,20 +86,9 @@ export default function NewPassword({
</Button> </Button>
) : null} ) : null}
</div> </div>
{field.value ? (
<div className={styles.errors}> <PasswordValidation value={field.value} errors={errors} />
{Object.entries(passwordValidators).map(
([key, { message }]) => (
<Caption asChild color="black" key={key}>
<Text className={styles.helpText} slot="description">
<Icon errorMessage={message} errors={errors} />
{getErrorMessage(key as PasswordValidatorKey)}
</Text>
</Caption>
)
)}
</div>
) : null}
{!field.value && fieldState.error ? ( {!field.value && fieldState.error ? (
<Caption className={styles.error} fontOnly> <Caption className={styles.error} fontOnly>
<InfoCircleIcon color="red" /> <InfoCircleIcon color="red" />
@@ -134,3 +109,43 @@ function Icon({ errorMessage, errors }: IconProps) {
<CheckIcon color="green" height={20} width={20} /> <CheckIcon color="green" height={20} width={20} />
) )
} }
function PasswordValidation({
value,
errors,
}: {
value: string
errors: string[]
}) {
const intl = useIntl()
if (!value) return null
function getErrorMessage(key: PasswordValidatorKey) {
switch (key) {
case "length":
return `10 ${intl.formatMessage({ id: "to" })} 40 ${intl.formatMessage({ id: "characters" })}`
case "hasUppercase":
return `1 ${intl.formatMessage({ id: "uppercase letter" })}`
case "hasLowercase":
return `1 ${intl.formatMessage({ id: "lowercase letter" })}`
case "hasNumber":
return `1 ${intl.formatMessage({ id: "number" })}`
case "hasSpecialChar":
return `1 ${intl.formatMessage({ id: "special character" })}`
}
}
return (
<div className={styles.errors}>
{Object.entries(passwordValidators).map(([key, { message }]) => (
<Caption asChild color="black" key={key}>
<Text className={styles.helpText} slot="description">
<Icon errorMessage={message} errors={errors} />
{getErrorMessage(key as PasswordValidatorKey)}
</Text>
</Caption>
))}
</div>
)
}