Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ <h2 class="text-center">{{ 'auth.resetPassword.title' | translate }}</h2>
autocomplete="new-password"
></p-password>

<osf-password-input-hint [isError]="isNewPasswordError" />
<osf-password-input-hint [control]="resetPasswordForm.controls['newPassword']" />
</div>

<div class="flex flex-column">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,17 @@ export class ResetPasswordComponent {

resetPasswordForm: ResetPasswordFormGroupType = this.fb.group(
{
newPassword: ['', [CustomValidators.requiredTrimmed(), Validators.pattern(this.passwordRegex)]],
newPassword: [
'',
[CustomValidators.requiredTrimmed(), Validators.minLength(8), Validators.pattern(this.passwordRegex)],
],
confirmNewPassword: ['', CustomValidators.requiredTrimmed()],
},
{
validators: CustomValidators.passwordMatchValidator('newPassword', 'confirmNewPassword'),
}
);

get isNewPasswordError() {
return this.resetPasswordForm.get('newPassword')?.errors && this.resetPasswordForm.get('newPassword')?.touched;
}

get isMismatchError(): boolean {
return (
this.resetPasswordForm.get('confirmNewPassword')?.dirty &&
Expand Down
2 changes: 1 addition & 1 deletion src/app/features/auth/pages/sign-up/sign-up.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ <h2 class="text-center">{{ 'auth.signUp.title' | translate }}</h2>
autocomplete="new-password"
styleClass="w-full"
></p-password>
<osf-password-input-hint [isError]="isPasswordError" />
<osf-password-input-hint [control]="signUpForm.controls['password']" />
</div>

<div class="flex mt-1">
Expand Down
7 changes: 1 addition & 6 deletions src/app/features/auth/pages/sign-up/sign-up.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,11 @@ export class SignUpComponent implements OnInit {
private readonly environment = inject(ENVIRONMENT);

signUpForm = new FormGroup<SignUpForm>({} as SignUpForm);
passwordRegex: RegExp = PASSWORD_REGEX;
inputLimits = InputLimits;
isFormSubmitted = signal(false);

readonly siteKey = this.environment.recaptchaSiteKey;

get isPasswordError() {
return this.signUpForm.controls['password'].errors && this.signUpForm.get('password')?.touched;
}

ngOnInit(): void {
this.initializeForm();
}
Expand All @@ -76,7 +71,7 @@ export class SignUpComponent implements OnInit {
}),
password: new FormControl('', {
nonNullable: true,
validators: [CustomValidators.requiredTrimmed(), Validators.pattern(this.passwordRegex)],
validators: [CustomValidators.requiredTrimmed(), Validators.minLength(8), Validators.pattern(PASSWORD_REGEX)],
}),
acceptedTermsOfService: new FormControl(false, {
nonNullable: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,30 +47,6 @@ <h2>{{ 'settings.accountSettings.changePassword.title' | translate }}</h2>
"
/>

@if (
FormValidationHelper.hasError(getFormControl(AccountSettingsPasswordFormControls.NewPassword), 'required')
) {
<small class="text-red-500 mt-1">
{{ 'settings.accountSettings.changePassword.validation.newPasswordRequired' | translate }}
</small>
}

@if (
FormValidationHelper.hasError(getFormControl(AccountSettingsPasswordFormControls.NewPassword), 'minlength')
) {
<small class="text-red-500 mt-1">
{{ 'settings.accountSettings.changePassword.validation.newPasswordMinLength' | translate }}
</small>
}

@if (
FormValidationHelper.hasError(getFormControl(AccountSettingsPasswordFormControls.NewPassword), 'pattern')
) {
<small class="text-red-500 mt-1">
{{ 'settings.accountSettings.changePassword.validation.newPasswordPattern' | translate }}
</small>
}

@if (
getFormErrors()['sameAsOldPassword'] &&
FormValidationHelper.isFieldTouched(getFormControl(AccountSettingsPasswordFormControls.NewPassword))
Expand All @@ -80,9 +56,7 @@ <h2>{{ 'settings.accountSettings.changePassword.title' | translate }}</h2>
</small>
}

<small class="password-help mt-1">
{{ 'settings.accountSettings.changePassword.form.passwordRequirements' | translate }}
</small>
<osf-password-input-hint [control]="getFormControl(AccountSettingsPasswordFormControls.NewPassword)" />
</div>

<div class="flex flex-column flex-1">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
.password-help {
color: var(--pr-blue-1);
font-size: 0.75rem;
font-weight: 600;
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,16 @@ import {
} from '@angular/forms';

import { AuthService } from '@osf/core/services';
import { CustomValidators, FormValidationHelper } from '@osf/shared/helpers';
import { PasswordInputHintComponent } from '@osf/shared/components';
import { CustomValidators, FormValidationHelper, PASSWORD_REGEX } from '@osf/shared/helpers';
import { LoaderService, ToastService } from '@osf/shared/services';

import { AccountSettingsPasswordForm, AccountSettingsPasswordFormControls } from '../../models';
import { UpdatePassword } from '../../store';

@Component({
selector: 'osf-change-password',
imports: [Card, ReactiveFormsModule, Password, CommonModule, Button, TranslatePipe],
imports: [Card, ReactiveFormsModule, Password, CommonModule, Button, TranslatePipe, PasswordInputHintComponent],
templateUrl: './change-password.component.html',
styleUrl: './change-password.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
Expand All @@ -47,11 +48,7 @@ export class ChangePasswordComponent implements OnInit {
}),
[AccountSettingsPasswordFormControls.NewPassword]: new FormControl('', {
nonNullable: true,
validators: [
CustomValidators.requiredTrimmed(),
Validators.minLength(8),
Validators.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*[\d!@#$%^&*])[A-Za-z\d!@#$%^&*_]{8,}$/),
],
validators: [CustomValidators.requiredTrimmed(), Validators.minLength(8), Validators.pattern(PASSWORD_REGEX)],
}),
[AccountSettingsPasswordFormControls.ConfirmPassword]: new FormControl('', {
nonNullable: true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
<small [class]="isError() ? 'text-danger' : ''">
{{ 'auth.common.password.requirements' | translate }}
</small>
@if (validationError) {
<small class="text-danger font-semibold mt-1">
@switch (validationError) {
@case ('required') {
{{ 'auth.common.password.validation.required' | translate }}
}
@case ('minlength') {
{{ 'auth.common.password.validation.minlength' | translate }}
}
@case ('pattern') {
{{ 'auth.common.password.validation.pattern' | translate }}
}
}
</small>
} @else {
<small class="hint-text font-semibold mt-1">
{{ 'auth.common.password.requirements' | translate }}
</small>
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
:host {
color: var(--primary-blue-1);
font-weight: 600;
font-size: 0.85rem;
.text-danger {
color: var(--red-1);
}

.text-danger {
color: var(--red-1);
}
.hint-text {
color: var(--pr-blue-1);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { TranslatePipe } from '@ngx-translate/core';

import { ChangeDetectionStrategy, Component, input } from '@angular/core';

import { BooleanOrNullOrUndefined } from '@osf/shared/helpers';
import { CommonModule } from '@angular/common';
import { Component, input } from '@angular/core';
import { AbstractControl } from '@angular/forms';

@Component({
selector: 'osf-password-input-hint',
imports: [TranslatePipe],
imports: [TranslatePipe, CommonModule],
templateUrl: './password-input-hint.component.html',
styleUrl: './password-input-hint.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class PasswordInputHintComponent {
isError = input<BooleanOrNullOrUndefined>(false);
control = input<AbstractControl | null>(null);

get validationError(): string | null {
const ctrl = this.control();
if (!ctrl || !ctrl.errors || !ctrl.touched) return null;

if (ctrl.errors['required']) return 'required';
if (ctrl.errors['minlength']) return 'minlength';
if (ctrl.errors['pattern']) return 'pattern';

return null;
}
}
15 changes: 8 additions & 7 deletions src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,12 @@
"new": "New Password",
"confirm": "Confirm New Password",
"mismatch": "Passwords must match.",
"requirements": "Your password needs to be at least 8 characters long, include both lower- and upper-case characters, and have at least one number and special character"
"requirements": "Your password needs to be at least 8 characters long, include both lower- and upper-case characters, and have at least one number and special character",
"validation": {
"required": "Password is required.",
"minlength": "Password must be at least 8 characters long.",
"pattern": "Password must include lowercase, uppercase, and at least one number and special character."
}
}
},
"forgotPassword": {
Expand Down Expand Up @@ -1172,7 +1177,7 @@
"seeAllFiles": "See All Files in a Provider",
"seeAllFilesDescription": "All connected storage providers are displayed in the dropdown above the files list. Choose one provider to view contents.",
"selectFilesFolders": "Select Files/Folders",
"selectFilesFoldersDescription": "Click on a row (outside of the file or folder name). Click on more rows to select multiple files. To select a range of files, click a file to begin selection and then shift+click another file to select the range. Select the ellipses on the right side of the row to see more file options.",
"selectFilesFoldersDescription": "Click on a row (outside of the file or folder name). Click on more rows to select multiple files. Select the ellipses on the right side of the row to see more file options.",
"openViewFiles": "Open/View Files and Folders",
"openViewFilesDescription": "Click a file name to go to view the file in the OSF. Opens file in a new tab. Click on the folder to open the contents in the files list.",
"upload": "Upload",
Expand Down Expand Up @@ -1902,14 +1907,10 @@
"newPassword": "New password",
"newPasswordPlaceholder": "Enter your new password",
"confirmPassword": "Confirm password",
"confirmPasswordPlaceholder": "Confirm your new password",
"passwordRequirements": "Your password needs to be at least 8 characters long, include both lower- and upper-case characters, and have at least one number or special character"
"confirmPasswordPlaceholder": "Confirm your new password"
},
"validation": {
"oldPasswordRequired": "Old password is required",
"newPasswordRequired": "New password is required",
"newPasswordMinLength": "Password must be at least 8 characters long.",
"newPasswordPattern": "Password must include lowercase, uppercase, and at least one number or special character.",
"confirmPasswordRequired": "Please confirm your password",
"passwordsDoNotMatch": "Passwords do not match",
"sameAsOldPassword": "New password must be different from old password"
Expand Down
Loading