feat: Add `ChangePassword` field to Account/Security (#30306)
Co-authored-by: Douglas Fabris <27704687+dougfabris@users.noreply.github.com>pull/30321/head^2
parent
9bdbc9b086
commit
ee3815fce4
@ -0,0 +1,6 @@ |
||||
--- |
||||
'@rocket.chat/ui-client': minor |
||||
'@rocket.chat/meteor': minor |
||||
--- |
||||
|
||||
feat: add ChangePassword field to Account/Security |
||||
@ -0,0 +1,115 @@ |
||||
import { Box, Field, FieldError, FieldGroup, FieldHint, FieldLabel, FieldRow, Icon, PasswordInput } from '@rocket.chat/fuselage'; |
||||
import { useUniqueId } from '@rocket.chat/fuselage-hooks'; |
||||
import { PasswordVerifier, useValidatePassword } from '@rocket.chat/ui-client'; |
||||
import { useMethod, useToastMessageDispatch, useTranslation } from '@rocket.chat/ui-contexts'; |
||||
import type { AllHTMLAttributes } from 'react'; |
||||
import React from 'react'; |
||||
import { Controller, useFormContext } from 'react-hook-form'; |
||||
|
||||
import { useAllowPasswordChange } from './useAllowPasswordChange'; |
||||
|
||||
type PasswordFieldValues = { password: string; confirmationPassword: string }; |
||||
|
||||
const ChangePassword = (props: AllHTMLAttributes<HTMLFormElement>) => { |
||||
const t = useTranslation(); |
||||
const dispatchToastMessage = useToastMessageDispatch(); |
||||
|
||||
const passwordId = useUniqueId(); |
||||
const confirmPasswordId = useUniqueId(); |
||||
const passwordVerifierId = useUniqueId(); |
||||
|
||||
const { |
||||
watch, |
||||
formState: { errors }, |
||||
handleSubmit, |
||||
reset, |
||||
control, |
||||
} = useFormContext<PasswordFieldValues>(); |
||||
|
||||
const password = watch('password'); |
||||
const passwordIsValid = useValidatePassword(password); |
||||
const { allowPasswordChange } = useAllowPasswordChange(); |
||||
|
||||
// FIXME: replace to endpoint
|
||||
const updatePassword = useMethod('saveUserProfile'); |
||||
|
||||
const handleSave = async ({ password }: { password?: string }) => { |
||||
try { |
||||
await updatePassword({ newPassword: password }, {}); |
||||
dispatchToastMessage({ type: 'success', message: t('Password_changed_successfully') }); |
||||
reset(); |
||||
} catch (error) { |
||||
dispatchToastMessage({ type: 'error', message: error }); |
||||
} |
||||
}; |
||||
|
||||
return ( |
||||
<Box {...props} is='form' autoComplete='off' onSubmit={handleSubmit(handleSave)}> |
||||
<FieldGroup> |
||||
<Field> |
||||
<FieldLabel htmlFor={passwordId}>{t('New_password')}</FieldLabel> |
||||
<FieldRow> |
||||
<Controller |
||||
control={control} |
||||
name='password' |
||||
rules={{ |
||||
validate: () => (password?.length && !passwordIsValid ? t('Password_must_meet_the_complexity_requirements') : true), |
||||
}} |
||||
render={({ field: { onChange, value } }) => ( |
||||
<PasswordInput |
||||
id={passwordId} |
||||
onChange={onChange} |
||||
value={value} |
||||
error={errors.password?.message} |
||||
flexGrow={1} |
||||
addon={<Icon name='key' size='x20' />} |
||||
disabled={!allowPasswordChange} |
||||
aria-describedby={`${passwordVerifierId} ${passwordId}-hint ${passwordId}-error`} |
||||
aria-invalid={errors.password ? 'true' : 'false'} |
||||
/> |
||||
)} |
||||
/> |
||||
</FieldRow> |
||||
{!allowPasswordChange && <FieldHint id={`${passwordId}-hint`}>{t('Password_Change_Disabled')}</FieldHint>} |
||||
{errors?.password && ( |
||||
<FieldError aria-live='assertive' id={`${passwordId}-error`}> |
||||
{errors.password.message} |
||||
</FieldError> |
||||
)} |
||||
{allowPasswordChange && <PasswordVerifier password={password} id={passwordVerifierId} />} |
||||
</Field> |
||||
<Field> |
||||
<FieldLabel htmlFor={confirmPasswordId}>{t('Confirm_password')}</FieldLabel> |
||||
<FieldRow> |
||||
<Controller |
||||
control={control} |
||||
name='confirmationPassword' |
||||
rules={{ validate: (confirmationPassword) => (password !== confirmationPassword ? t('Passwords_do_not_match') : true) }} |
||||
render={({ field: { onChange, value } }) => ( |
||||
<PasswordInput |
||||
id={confirmPasswordId} |
||||
onChange={onChange} |
||||
value={value} |
||||
error={errors.confirmationPassword?.message} |
||||
flexGrow={1} |
||||
addon={<Icon name='key' size='x20' />} |
||||
disabled={!allowPasswordChange || !passwordIsValid} |
||||
aria-required={password !== '' ? 'true' : 'false'} |
||||
aria-invalid={errors.confirmationPassword ? 'true' : 'false'} |
||||
aria-describedby={`${confirmPasswordId}-error`} |
||||
/> |
||||
)} |
||||
/> |
||||
</FieldRow> |
||||
{errors.confirmationPassword && ( |
||||
<FieldError aria-live='assertive' id={`${confirmPasswordId}-error`}> |
||||
{errors.confirmationPassword.message} |
||||
</FieldError> |
||||
)} |
||||
</Field> |
||||
</FieldGroup> |
||||
</Box> |
||||
); |
||||
}; |
||||
|
||||
export default ChangePassword; |
||||
Loading…
Reference in new issue