Polish before Release 2 (#3723)

Co-authored-by: Amelia <77553571+Fesaa@users.noreply.github.com>
This commit is contained in:
Joe Milazzo 2025-04-11 09:07:17 -06:00 committed by GitHub
parent 67d7d8467e
commit 4453482d93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 201 additions and 154 deletions

View file

@ -39,7 +39,7 @@
"luxon": "^3.6.1",
"ng-circle-progress": "^1.7.1",
"ng-lazyload-image": "^9.1.3",
"ng-select2-component": "^17.2.3",
"ng-select2-component": "^17.2.4",
"ngx-color-picker": "^19.0.0",
"ngx-extended-pdf-viewer": "^23.0.0-alpha.7",
"ngx-file-drop": "^16.0.0",
@ -7412,9 +7412,9 @@
}
},
"node_modules/ng-select2-component": {
"version": "17.2.3",
"resolved": "https://registry.npmjs.org/ng-select2-component/-/ng-select2-component-17.2.3.tgz",
"integrity": "sha512-JNik7OWqya4ERuqlfnYiJHkaqyZtHqUhATIZ9yUxmadWWNIn8I3Lwa7qt0KtPpR01O9HJC0PtHXhvev88Cju2A==",
"version": "17.2.4",
"resolved": "https://registry.npmjs.org/ng-select2-component/-/ng-select2-component-17.2.4.tgz",
"integrity": "sha512-pfRQg1gY1NsQkBNAYYeSYJjejKwz1z+9bKWor8/8toCNbvh9TYMOKpcz3FrNvhR6v/Hto/quddajaxjD81TOgg==",
"dependencies": {
"ngx-infinite-scroll": ">=18.0.0 || >=19.0.0",
"tslib": "^2.3.0"

View file

@ -47,7 +47,7 @@
"luxon": "^3.6.1",
"ng-circle-progress": "^1.7.1",
"ng-lazyload-image": "^9.1.3",
"ng-select2-component": "^17.2.3",
"ng-select2-component": "^17.2.4",
"ngx-color-picker": "^19.0.0",
"ngx-extended-pdf-viewer": "^23.0.0-alpha.7",
"ngx-file-drop": "^16.0.0",

View file

@ -1,22 +1,20 @@
import { HttpClient } from '@angular/common/http';
import {DestroyRef, inject, Injectable } from '@angular/core';
import {catchError, Observable, of, ReplaySubject, shareReplay, throwError} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {DestroyRef, inject, Injectable} from '@angular/core';
import {Observable, of, ReplaySubject, shareReplay} from 'rxjs';
import {filter, map, switchMap, tap} from 'rxjs/operators';
import { environment } from 'src/environments/environment';
import { Preferences } from '../_models/preferences/preferences';
import { User } from '../_models/user';
import { Router } from '@angular/router';
import { EVENTS, MessageHubService } from './message-hub.service';
import { ThemeService } from './theme.service';
import { InviteUserResponse } from '../_models/auth/invite-user-response';
import { UserUpdateEvent } from '../_models/events/user-update-event';
import { AgeRating } from '../_models/metadata/age-rating';
import { AgeRestriction } from '../_models/metadata/age-restriction';
import { TextResonse } from '../_types/text-response';
import {environment} from 'src/environments/environment';
import {Preferences} from '../_models/preferences/preferences';
import {User} from '../_models/user';
import {Router} from '@angular/router';
import {EVENTS, MessageHubService} from './message-hub.service';
import {ThemeService} from './theme.service';
import {InviteUserResponse} from '../_models/auth/invite-user-response';
import {UserUpdateEvent} from '../_models/events/user-update-event';
import {AgeRating} from '../_models/metadata/age-rating';
import {AgeRestriction} from '../_models/metadata/age-restriction';
import {TextResonse} from '../_types/text-response';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import {Action} from "./action-factory.service";
import {CoverImageSize} from "../admin/_models/cover-image-size";
import {LicenseInfo} from "../_models/kavitaplus/license-info";
import {LicenseService} from "./license.service";
import {LocalizationService} from "./localization.service";
@ -132,7 +130,7 @@ export class AccountService {
}
hasChangeAgeRestrictionRole(user: User) {
return user && user.roles.includes(Role.ChangeRestriction);
return user && !user.roles.includes(Role.Admin) && user.roles.includes(Role.ChangeRestriction);
}
hasDownloadRole(user: User) {
@ -199,9 +197,9 @@ export class AccountService {
if (this.currentUser) {
// BUG: StopHubConnection has a promise in it, this needs to be async
// But that really messes everything up
this.messageHub.stopHubConnection();
this.messageHub.createHubConnection(this.currentUser);
if (!isSameUser) {
this.messageHub.stopHubConnection();
this.messageHub.createHubConnection(this.currentUser);
this.licenseService.hasValidLicense().subscribe();
}
this.startRefreshTokenTimer();

View file

@ -17,12 +17,8 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<div class="input-group">
<input id="settings-hostname" aria-describedby="hostname-validations" class="form-control" formControlName="hostName" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
<button type="button" class="btn btn-outline-secondary" (click)="autofillGmail()">{{t('gmail-label')}}</button>
<button type="button" class="btn btn-outline-secondary" (click)="autofillOutlook()">{{t('outlook-label')}}</button>
</div>
<input id="settings-hostname" aria-describedby="hostname-validations" class="form-control" formControlName="hostName" type="text"
[class.is-invalid]="formControl.invalid && !formControl.untouched" appEnterBlur>
@if (formControl.errors; as errors) {
<div id="hostname-validations" class="invalid-feedback" style="display: inline-block">
@ -69,7 +65,11 @@
{{formControl.value | defaultValue}}
</ng-template>
<ng-template #edit>
<input type="text" class="form-control" formControlName="host" id="settings-host" appEnterBlur />
<div class="input-group">
<input type="text" class="form-control" formControlName="host" id="settings-host" appEnterBlur />
<button type="button" class="btn btn-outline-secondary" (click)="autofillGmail()">{{t('gmail-label')}}</button>
<button type="button" class="btn btn-outline-secondary" (click)="autofillOutlook()">{{t('outlook-label')}}</button>
</div>
</ng-template>
</app-setting-item>
}

View file

@ -18,7 +18,7 @@
</div>
<div class="col-md-4 col-10 mb-2">
@if (formGroup.get('comparison')?.value !== FilterComparison.IsEmpty) {
@if (IsEmptySelected) {
@if (predicateType$ | async; as predicateType) {
@switch (predicateType) {
@case (PredicateType.Text) {

View file

@ -170,6 +170,10 @@ export class MetadataFilterRowComponent implements OnInit {
private readonly mangaFormatPipe = new MangaFormatPipe(this.translocoService);
private readonly ageRatingPipe = new AgeRatingPipe();
get IsEmptySelected() {
return parseInt(this.formGroup.get('comparison')?.value + '', 10) !== FilterComparison.IsEmpty;
}
get UiLabel(): FilterRowUi | null {
const field = parseInt(this.formGroup.get('input')!.value, 10) as FilterField;
@ -348,6 +352,7 @@ export class MetadataFilterRowComponent implements OnInit {
this.formGroup.get('filterValue')?.patchValue('');
this.formGroup.get('comparison')?.patchValue(StringComparisons[0]);
}
this.cdRef.markForCheck();
return;
}
@ -363,10 +368,13 @@ export class MetadataFilterRowComponent implements OnInit {
this.validComparisons$.next([...new Set(comps)]);
this.predicateType$.next(PredicateType.Number);
if (this.loaded) {
this.formGroup.get('filterValue')?.patchValue(0);
this.formGroup.get('comparison')?.patchValue(NumberComparisons[0]);
}
this.cdRef.markForCheck();
return;
}
@ -383,6 +391,7 @@ export class MetadataFilterRowComponent implements OnInit {
this.formGroup.get('filterValue')?.patchValue(false);
this.formGroup.get('comparison')?.patchValue(DateComparisons[0]);
}
this.cdRef.markForCheck();
return;
}
@ -400,6 +409,7 @@ export class MetadataFilterRowComponent implements OnInit {
this.formGroup.get('filterValue')?.patchValue(false);
this.formGroup.get('comparison')?.patchValue(BooleanComparisons[0]);
}
this.cdRef.markForCheck();
return;
}
@ -421,15 +431,15 @@ export class MetadataFilterRowComponent implements OnInit {
this.formGroup.get('filterValue')?.patchValue(0);
this.formGroup.get('comparison')?.patchValue(comps[0]);
}
this.cdRef.markForCheck();
return;
}
}
onDateSelect(_: NgbDate) {
this.propagateFilterUpdate();
}
updateIfDateFilled() {
this.propagateFilterUpdate();
}

View file

@ -8,11 +8,13 @@
<label for="username" class="form-label">{{t('username-label')}}</label>
<input id="username" class="form-control custom-input" formControlName="username" type="text" autocomplete="username"
[class.is-invalid]="registerForm.get('username')?.invalid && registerForm.get('username')?.touched" aria-describedby="username-validations">
<div id="username-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('username')?.errors?.required">
{{t('required-field')}}
@if (registerForm.dirty || registerForm.touched) {
<div id="username-validations" class="invalid-feedback">
@if (registerForm.get('username')?.errors?.required) {
<div>{{t('required-field')}}</div>
}
</div>
</div>
}
</div>
<div class="mb-3 text-start">
@ -22,16 +24,18 @@
<span class="visually-hidden" id="email-help">
<ng-container [ngTemplateOutlet]="emailTooltip"></ng-container>
</span>
<input class="form-control custom-input" type="email" inputmode="email" id="email" autocomplete="email" formControlName="email" required aria-describedby="email-help"
<input class="form-control custom-input" type="email" inputmode="email" id="email" autocomplete="email" formControlName="email" aria-describedby="email-help"
[class.is-invalid]="registerForm.get('email')?.invalid && registerForm.get('email')?.touched">
<div id="email-validations" class="invalid-feedback" *ngIf="registerForm.dirty || registerForm.touched">
<div *ngIf="registerForm.get('email')?.errors?.required">
{{t('required-field')}}
@if (registerForm.dirty || registerForm.touched) {
<div id="email-validations" class="invalid-feedback">
@if (registerForm.get('email')?.errors?.required) {
<div>{{t('required-field')}}</div>
} @else if (registerForm.get('email')?.errors?.email) {
<div>{{t('valid-email')}}</div>
}
</div>
<div *ngIf="registerForm.get('email')?.errors?.email">
{{t('valid-email')}}
</div>
</div>
}
</div>
<div class="mb-3 text-start">

View file

@ -1,13 +1,13 @@
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
import { FormGroup, FormControl, Validators, ReactiveFormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import { ToastrService } from 'ngx-toastr';
import { take } from 'rxjs/operators';
import { AccountService } from 'src/app/_services/account.service';
import { MemberService } from 'src/app/_services/member.service';
import { NgbTooltip } from '@ng-bootstrap/ng-bootstrap';
import { NgIf, NgTemplateOutlet } from '@angular/common';
import { SplashContainerComponent } from '../splash-container/splash-container.component';
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import {Router} from '@angular/router';
import {ToastrService} from 'ngx-toastr';
import {take} from 'rxjs/operators';
import {AccountService} from 'src/app/_services/account.service';
import {MemberService} from 'src/app/_services/member.service';
import {NgbTooltip} from '@ng-bootstrap/ng-bootstrap';
import {NgTemplateOutlet} from '@angular/common';
import {SplashContainerComponent} from '../splash-container/splash-container.component';
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {NavService} from "../../../_services/nav.service";
@ -15,25 +15,28 @@ import {NavService} from "../../../_services/nav.service";
* This is exclusively used to register the first user on the server and nothing else
*/
@Component({
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [SplashContainerComponent, ReactiveFormsModule, NgIf, NgbTooltip, NgTemplateOutlet, TranslocoDirective]
selector: 'app-register',
templateUrl: './register.component.html',
styleUrls: ['./register.component.scss'],
imports: [SplashContainerComponent, ReactiveFormsModule, NgbTooltip, NgTemplateOutlet, TranslocoDirective],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class RegisterComponent {
private readonly navService = inject(NavService);
private readonly router = inject(Router);
private readonly accountService = inject(AccountService);
private readonly toastr = inject(ToastrService);
private readonly memberService = inject(MemberService);
registerForm: FormGroup = new FormGroup({
email: new FormControl('', [Validators.required]),
username: new FormControl('', [Validators.required]),
email: new FormControl('', []),
password: new FormControl('', [Validators.required, Validators.maxLength(256),
Validators.minLength(6), Validators.pattern("^.{6,256}$")]),
});
private readonly navService = inject(NavService);
constructor(private router: Router, private accountService: AccountService,
private toastr: ToastrService, private memberService: MemberService) {
constructor() {
this.navService.hideNavBar();
this.navService.hideSideNav();

View file

@ -2,9 +2,16 @@ import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ContentChild, ElementRef, EventEmitter, HostListener,
ContentChild,
ElementRef,
EventEmitter,
HostListener,
inject,
Input, OnChanges, Output, SimpleChange, SimpleChanges,
Input,
OnChanges,
Output,
SimpleChange,
SimpleChanges,
TemplateRef
} from '@angular/core';
import {TranslocoDirective} from "@jsverse/transloco";
@ -28,6 +35,7 @@ import {AbstractControl} from "@angular/forms";
export class SettingItemComponent implements OnChanges {
private readonly cdRef = inject(ChangeDetectorRef);
private readonly elementRef = inject(ElementRef);
@Input({required:true}) title: string = '';
@Input() editLabel: string | undefined = undefined;
@ -98,11 +106,10 @@ export class SettingItemComponent implements OnChanges {
if (!this.canEdit) return;
if (this.control != null && this.control.invalid) return;
console.log('isEditMode', this.isEditMode, 'currentValue', change.currentValue);
this.isEditMode = change.currentValue;
//this.editMode.emit(this.isEditMode);
this.cdRef.markForCheck();
this.focusInput();
}
}
@ -114,7 +121,27 @@ export class SettingItemComponent implements OnChanges {
this.isEditMode = !this.isEditMode;
this.editMode.emit(this.isEditMode);
this.focusInput();
this.cdRef.markForCheck();
}
focusInput() {
if (this.isEditMode) {
setTimeout(() => {
const inputElem = this.findFirstInput();
if (inputElem) {
inputElem.focus();
}
}, 10);
}
}
private findFirstInput(): HTMLInputElement | null {
const nativeInputs = [...this.elementRef.nativeElement.querySelectorAll('input'), ...this.elementRef.nativeElement.querySelectorAll('select'), ...this.elementRef.nativeElement.querySelectorAll('textarea')];
if (nativeInputs.length === 0) return null;
return nativeInputs[0];
}
}

View file

@ -239,6 +239,12 @@ export class SideNavComponent implements OnInit {
}
async reorderDrop($event: CdkDragDrop<any, any, SideNavStream>) {
// Don't allow dropping on non SideNav items
const fixedSideNavItems = 3;
if ($event.currentIndex < fixedSideNavItems) {
return;
}
const stream = $event.item.data;
// Offset the home, back, and customize button
this.navService.updateSideNavStreamPosition(stream.name, stream.id, stream.order, $event.currentIndex - 3).subscribe({

View file

@ -1,6 +1,6 @@
<ng-container *transloco="let t; read:'change-age-restriction'">
@if (user) {
<app-setting-item [title]="t('age-restriction-label')" [canEdit]="accountService.hasChangeAgeRestrictionRole(user) || accountService.hasAdminRole(user)">
<app-setting-item [title]="t('age-restriction-label')" [canEdit]="accountService.hasChangeAgeRestrictionRole(user)">
<ng-template #view>
<span class="col-12" [ngClass]="{'disabled': !accountService.hasChangeAgeRestrictionRole(user) && !accountService.hasAdminRole(user)}">{{user.ageRestriction.ageRating | ageRating }}
@if (user.ageRestriction.ageRating !== AgeRating.NotApplicable && user.ageRestriction.includeUnknowns) {

View file

@ -1,7 +1,8 @@
<ng-container *transloco="let t; read:'change-email'">
<app-setting-item [title]="t('email-title')" [canEdit]="canEdit">
<ng-template #extra>
<app-setting-item [title]="t('email-title')" [canEdit]="canEdit" [isEditMode]="isEditMode" (editMode)="updateEditMode($event)">
<ng-template #view>
<span>{{user?.email}}</span>
@if(emailConfirmed) {
<i class="fa-solid fa-circle-check ms-1 confirm-icon" aria-hidden="true" [ngbTooltip]="t('email-confirmed')"></i>
<span class="visually-hidden">{{t('email-confirmed')}}</span>
@ -11,10 +12,6 @@
}
</ng-template>
<ng-template #view>
<span>{{user?.email}}</span>
</ng-template>
<ng-template #edit>
@if (errors.length > 0) {
<div class="alert alert-danger" role="alert">

View file

@ -1,55 +1,58 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject, OnInit} from '@angular/core';
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import {ToastrService} from 'ngx-toastr';
import {shareReplay} from 'rxjs';
import {User} from 'src/app/_models/user';
import {AccountService} from 'src/app/_services/account.service';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import { ApiKeyComponent } from '../api-key/api-key.component';
import { NgbTooltip, NgbCollapse } from '@ng-bootstrap/ng-bootstrap';
import {ApiKeyComponent} from '../api-key/api-key.component';
import {NgbTooltip} from '@ng-bootstrap/ng-bootstrap';
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {ScrobbleProviderNamePipe} from "../../_pipes/scrobble-provider-name.pipe";
import {SettingTitleComponent} from "../../settings/_components/setting-title/setting-title.component";
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
@Component({
selector: 'app-change-email',
templateUrl: './change-email.component.html',
styleUrls: ['./change-email.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgbTooltip, ReactiveFormsModule, ApiKeyComponent, TranslocoDirective, SettingItemComponent]
selector: 'app-change-email',
templateUrl: './change-email.component.html',
styleUrls: ['./change-email.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [NgbTooltip, ReactiveFormsModule, ApiKeyComponent, TranslocoDirective, SettingItemComponent]
})
export class ChangeEmailComponent implements OnInit {
private readonly destroyRef = inject(DestroyRef);
private readonly toastr = inject(ToastrService);
private readonly cdRef = inject(ChangeDetectorRef);
protected readonly accountService = inject(AccountService);
form: FormGroup = new FormGroup({});
user: User | undefined = undefined;
errors: string[] = [];
isViewMode: boolean = true;
isEditMode: boolean = false;
emailLink: string = '';
emailConfirmed: boolean = true;
hasValidEmail: boolean = true;
canEdit: boolean = false;
public get email() { return this.form.get('email'); }
protected get email() { return this.form.get('email'); }
makeLink: (val: string) => string = (val: string) => {return this.emailLink};
constructor(public accountService: AccountService, private toastr: ToastrService, private readonly cdRef: ChangeDetectorRef) { }
ngOnInit(): void {
this.accountService.currentUser$.pipe(takeUntilDestroyed(this.destroyRef), shareReplay()).subscribe(user => {
this.user = user;
this.user = user!;
this.canEdit = !this.accountService.hasReadOnlyRole(user!);
this.form.addControl('email', new FormControl(user?.email, [Validators.required, Validators.email]));
this.form.addControl('password', new FormControl('', [Validators.required]));
this.cdRef.markForCheck();
this.accountService.isEmailConfirmed().subscribe((confirmed) => {
this.emailConfirmed = confirmed;
this.cdRef.markForCheck();
});
this.accountService.isEmailValid().subscribe(isValid => {
this.hasValidEmail = isValid;
this.cdRef.markForCheck();
@ -68,42 +71,31 @@ export class ChangeEmailComponent implements OnInit {
const model = this.form.value;
this.errors = [];
this.accountService.updateEmail(model.email, model.password).subscribe(updateEmailResponse => {
if (updateEmailResponse.invalidEmail) {
this.toastr.success(translate('toasts.email-sent-to-no-existing', {email: model.email}));
}
if (updateEmailResponse.emailSent) {
} else if (updateEmailResponse.emailSent) {
this.toastr.success(translate('toasts.email-sent-to'));
} else {
this.toastr.success(translate('toasts.change-email-no-email'));
this.accountService.refreshAccount().subscribe(user => {
this.user = user;
this.form.get('email')?.setValue(this.user?.email);
this.cdRef.markForCheck();
});
}
this.isViewMode = true;
this.resetForm();
this.accountService.refreshAccount().subscribe(user => {
this.user = user;
this.resetForm();
this.cdRef.markForCheck();
});
this.isEditMode = false;
this.cdRef.markForCheck();
}, err => {
this.errors = err;
this.cdRef.markForCheck();
})
}
toggleViewMode() {
this.isViewMode = !this.isViewMode;
this.resetForm();
}
updateEditMode(mode: boolean) {
this.isViewMode = !mode;
updateEditMode(val: boolean) {
this.isEditMode = val;
this.cdRef.markForCheck();
this.resetForm();
}
}

View file

@ -1,5 +1,5 @@
<ng-container *transloco="let t; read:'change-password'">
<app-setting-item [title]="t('password-label')" [canEdit]="canEdit">
<app-setting-item [title]="t('password-label')" [canEdit]="canEdit" [isEditMode]="isEditMode" (editMode)="updateEditMode($event)">
<ng-template #view>
<span class="col-12">***************</span>
</ng-template>

View file

@ -7,16 +7,13 @@ import {
OnDestroy,
OnInit
} from '@angular/core';
import { FormControl, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
import { ToastrService } from 'ngx-toastr';
import { map, Observable, of, shareReplay } from 'rxjs';
import { User } from 'src/app/_models/user';
import { AccountService } from 'src/app/_services/account.service';
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import {ToastrService} from 'ngx-toastr';
import {map, Observable, of, shareReplay} from 'rxjs';
import {User} from 'src/app/_models/user';
import {AccountService} from 'src/app/_services/account.service';
import {takeUntilDestroyed} from "@angular/core/rxjs-interop";
import { NgbCollapse } from '@ng-bootstrap/ng-bootstrap';
import { AsyncPipe } from '@angular/common';
import {translate, TranslocoDirective} from "@jsverse/transloco";
import {SettingTitleComponent} from "../../settings/_components/setting-title/setting-title.component";
import {SettingItemComponent} from "../../settings/_components/setting-item/setting-item.component";
@Component({
@ -39,7 +36,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
observableHandles: Array<any> = [];
passwordsMatch = false;
resetPasswordErrors: string[] = [];
isViewMode: boolean = true;
isEditMode: boolean = false;
canEdit: boolean = false;
@ -90,7 +87,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
this.observableHandles.push(this.accountService.resetPassword(this.user?.username, model.confirmPassword, model.oldPassword).subscribe(() => {
this.toastr.success(translate('toasts.password-updated'));
this.resetPasswordForm();
this.isViewMode = true;
this.isEditMode = false;
this.cdRef.markForCheck();
}, err => {
this.resetPasswordErrors = err;
@ -99,7 +96,7 @@ export class ChangePasswordComponent implements OnInit, OnDestroy {
}
updateEditMode(mode: boolean) {
this.isViewMode = !mode;
this.isEditMode = mode;
this.cdRef.markForCheck();
}
}