Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

O3-1409: Support for users changing passwords #43

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

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 <[email protected]>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <[email protected]>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <[email protected]>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <[email protected]>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <[email protected]>
…-password-modal.component.tsx

Co-authored-by: Dennis Kigen <[email protected]>
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