Skip to content

O3-1409: Support for users changing passwords#43

Open
jnsereko wants to merge 9 commits intoopenmrs:mainfrom
jnsereko:O3-1409
Open

O3-1409: Support for users changing passwords#43
jnsereko wants to merge 9 commits intoopenmrs:mainfrom
jnsereko:O3-1409

Conversation

@jnsereko
Copy link

@jnsereko jnsereko commented Feb 1, 2024

Requirements

  • This PR has a title that briefly describes the work done, including the ticket number if there is a ticket.
  • My work conforms to the OpenMRS 3.0 Styleguide.
  • I checked for feature overlap with existing widgets.

Summary

O3 screen to allow users to change their password as a follow-up for openmrs/openmrs-esm-core#902
cc @ibacher @michaelbontyes @vasharma05 @denniskigen

Screenshots

change-password.mov

None.

Issue

https://openmrs.atlassian.net/browse/O3-1409

None.

Other

None.

@jnsereko jnsereko changed the title O3 1409 O3-1409: Support for users changing passwords Feb 1, 2024
Copy link
Member

@ibacher ibacher left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jnsereko! Getting much closer. A bunch of nit-picking remarks.

if (passwordInput.confirmPassword !== '') {
handleValidation(passwordInput.confirmPassword, 'confirmPassword');
}
}, [passwordInput]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

handleValidation is also a dependency here.

Comment on lines +45 to +52
const handlePasswordChange = (event) => {
const passwordInputValue = event.target.value.trim();
const passwordInputFieldName = event.target.name;
const NewPasswordInput = { ...passwordInput, [passwordInputFieldName]: passwordInputValue };
setPasswordInput(NewPasswordInput);
};

const handleValidation = (passwordInputValue, passwordInputFieldName) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would probably wrap both of these in useCallback()

Comment on lines +106 to +120
try {
setIsSavingPassword(true);
await performPasswordChange(passwordInput.oldPassword, passwordInput.confirmPassword).then(() => {
close();
navigate({ to: `\${openmrsSpaBase}/logout` });
showToast({
title: t('userPassword', 'User password'),
description: t('userPasswordUpdated', 'User password updated successfully'),
kind: 'success',
});
});
} catch (error) {
setIsSavingPassword(false);
setErrorMessage(`${t('invalidPasswordCredentials', 'Invalid password provided')}: ${error.message}`);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This construction is weird...

performPasswordChange(passwordInput.oldPassword, passwordInput.confirmPassword).then(() => {
  close();
   navigate({ to: `\${openmrsSpaBase}/logout` });
  showToast({
    title: t('userPassword', 'User password'),
    description: t('userPasswordUpdated', 'User password updated successfully'),
    kind: 'success',
  });
}).catch((err) => {
  setIsSavingPassword(false);
  setErrorMessage(`${t('invalidPasswordCredentials', 'Invalid password provided')}: ${error.message}`);
});

Reads better to me. (Basically either use await and no then() or else just use it as a promise).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The success message should be a snackbar, not a toast. Also, we should probably show a notification when it submits but fails at the backend.

Comment on lines +103 to +104
evt.preventDefault();
evt.stopPropagation();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

setErrorMessage(`${t('invalidPasswordCredentials', 'Invalid password provided')}: ${error.message}`);
}

return false;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also why are we returning false?

onClick={handleSubmit}
disabled={isSavingPassword || isNewPasswordInvalid || isConfirmPasswordInvalid || isOldPasswordInvalid}
>
{t('apply', 'Apply')}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{t('apply', 'Apply')}
{t('updatePassword', 'Update Password')}

}

.errorMessage {
position: absolute;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolute positioning for an error message feels wrong.

options,
);

export const ChangePasswordModal = getAsyncLifecycle(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const ChangePasswordModal = getAsyncLifecycle(
export const changePasswordModal = getAsyncLifecycle(

},
{
"name": "change-password-modal",
"component": "ChangePasswordModal",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"component": "ChangePasswordModal",
"component": "changePasswordModal",

<Tile>
<form onSubmit={handleSubmit} ref={formRef}>
<div className={styles['input-group']}>
<PasswordInput
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's likely we need a Carbon Layer component in here.

<>
<ModalHeader closeModal={close} title={t('changePassword', 'Change Password')} />
<ModalBody>
<Tile>
Copy link
Member

@denniskigen denniskigen Feb 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for Tile here. It adds unnecessary margin to the modal body.

Comment on lines +6 to +8
:global(.cds--text-input) {
background-color: white;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Layer instead of this override.

import userEvent from '@testing-library/user-event';

describe(`Change Password Modal`, () => {
it('should change user locale', async () => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be something about changing the password, not the locale?

onChange={handlePasswordChange}
ref={newPasswordInputRef}
required
showPasswordLabel="Show new password"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider providing detailed helper text below the fields listing any requirements related to the data format, such as types of characters allowed per the password input usage guidelines.

Comment on lines +83 to +93
useEffect(() => {
if (passwordInput.oldPassword !== '') {
handleValidation(passwordInput.oldPassword, 'oldPassword');
}
if (passwordInput.newPassword !== '') {
handleValidation(passwordInput.newPassword, 'newPassword');
}
if (passwordInput.confirmPassword !== '') {
handleValidation(passwordInput.confirmPassword, 'confirmPassword');
}
}, [handleValidation, passwordInput]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the best client-side validation experience, we should probably use RHF and Zod here similar to how we're validating the Vitals and Biometrics form (and various other vanilla React forms in O3).

jnsereko and others added 6 commits February 6, 2024 13:51
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <kigen.work@gmail.com>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <kigen.work@gmail.com>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <kigen.work@gmail.com>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <kigen.work@gmail.com>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <kigen.work@gmail.com>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <kigen.work@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants