refactor: remove LoginService and FirebaseService, add PasswordVisibilityService and integrate
This commit is contained in:
parent
c2c5bd850e
commit
99b1e14034
11 changed files with 60 additions and 749 deletions
|
|
@ -19,7 +19,7 @@
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
#password="ngModel"
|
#password="ngModel"
|
||||||
[type]="loginService.passwordFieldType"
|
[type]="pwVisibility.passwordFieldType"
|
||||||
placeholder="{{ 'register.password' | translate }}"
|
placeholder="{{ 'register.password' | translate }}"
|
||||||
class="custom-input"
|
class="custom-input"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
|
|
@ -36,8 +36,8 @@
|
||||||
} @else {
|
} @else {
|
||||||
<img
|
<img
|
||||||
class="passwordEye"
|
class="passwordEye"
|
||||||
(click)="loginService.togglePasswordVisibility()"
|
(click)="pwVisibility.togglePasswordVisibility()"
|
||||||
[src]="loginService.passwordIcon"
|
[src]="pwVisibility.passwordIcon"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
|
|
@ -52,7 +52,7 @@
|
||||||
id="passwordConfirm"
|
id="passwordConfirm"
|
||||||
name="passwordConfirm"
|
name="passwordConfirm"
|
||||||
#passwordConfirm="ngModel"
|
#passwordConfirm="ngModel"
|
||||||
[type]="loginService.passwordFieldType"
|
[type]="pwVisibility.passwordFieldType"
|
||||||
placeholder="{{ 'register.passwordConfirm' | translate }}"
|
placeholder="{{ 'register.passwordConfirm' | translate }}"
|
||||||
class="custom-input"
|
class="custom-input"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
|
|
@ -69,8 +69,8 @@
|
||||||
} @else {
|
} @else {
|
||||||
<img
|
<img
|
||||||
class="passwordEyeConfirm"
|
class="passwordEyeConfirm"
|
||||||
(click)="loginService.togglePasswordVisibility()"
|
(click)="pwVisibility.togglePasswordVisibility()"
|
||||||
[src]="loginService.passwordIcon"
|
[src]="pwVisibility.passwordIcon"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { ButtonStateService } from '../../../../services/button-state.service';
|
import { ButtonStateService } from '../../../../services/button-state.service';
|
||||||
import { AuthService } from '../../../../services/auth.service';
|
import { AuthService } from '../../../../services/auth.service';
|
||||||
import { LoginService } from '../../../../services/login.service';
|
import { PasswordVisibilityService } from '../../../../services/password-visibility.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pw-reset',
|
selector: 'app-pw-reset',
|
||||||
|
|
@ -38,7 +38,7 @@ export class PwResetComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public loginService: LoginService,
|
public pwVisibility: PasswordVisibilityService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private buttonStateService: ButtonStateService,
|
private buttonStateService: ButtonStateService,
|
||||||
private route: ActivatedRoute
|
private route: ActivatedRoute
|
||||||
|
|
|
||||||
|
|
@ -35,9 +35,6 @@
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (!mail.valid && mail.touched && !isButtonDisabled()) {
|
@if (!mail.valid && mail.touched && !isButtonDisabled()) {
|
||||||
<p>{{ "login.errorMail0" | translate }}</p>
|
<p>{{ "login.errorMail0" | translate }}</p>
|
||||||
} @if (loginService.errorCode == 'auth/invalid-email' &&
|
|
||||||
!isButtonDisabled()) {
|
|
||||||
<p>{{ "login.errorMail1" | translate }}</p>
|
|
||||||
} @if (mail.valid && mail.touched &&
|
} @if (mail.valid && mail.touched &&
|
||||||
!isEmailValid(loginData.email.toLowerCase()) && !isButtonDisabled()) {
|
!isEmailValid(loginData.email.toLowerCase()) && !isButtonDisabled()) {
|
||||||
<p>{{ "login.errorMail2" | translate }}</p>
|
<p>{{ "login.errorMail2" | translate }}</p>
|
||||||
|
|
@ -48,7 +45,7 @@
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
#password="ngModel"
|
#password="ngModel"
|
||||||
[type]="loginService.passwordFieldType"
|
[type]="pwVisibility.passwordFieldType"
|
||||||
placeholder="{{ 'login.password' | translate }}"
|
placeholder="{{ 'login.password' | translate }}"
|
||||||
class="custom-input"
|
class="custom-input"
|
||||||
autocomplete="current-password"
|
autocomplete="current-password"
|
||||||
|
|
@ -67,16 +64,13 @@
|
||||||
<img
|
<img
|
||||||
class="passwordEye"
|
class="passwordEye"
|
||||||
*ngIf="isPasswordIconVisible"
|
*ngIf="isPasswordIconVisible"
|
||||||
(click)="loginService.togglePasswordVisibility()"
|
(click)="pwVisibility.togglePasswordVisibility()"
|
||||||
[src]="loginService.passwordIcon"
|
[src]="pwVisibility.passwordIcon"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (!password.valid && password.touched && !isButtonDisabled()) {
|
@if (!password.valid && password.touched && !isButtonDisabled()) {
|
||||||
<p>{{ "login.errorPassword0" | translate }}</p>
|
<p>{{ "login.errorPassword0" | translate }}</p>
|
||||||
} @if (loginService.errorCode == 'auth/invalid-credential' &&
|
|
||||||
!isButtonDisabled()) {
|
|
||||||
<p>{{ "login.errorPassword1" | translate }}</p>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox">
|
<div class="checkbox">
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ import { Component } from '@angular/core';
|
||||||
import { FormsModule, NgForm } from '@angular/forms';
|
import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { FormBtnComponent } from '../../shared/components/buttons/form-btn/form-btn.component';
|
import { FormBtnComponent } from '../../shared/components/buttons/form-btn/form-btn.component';
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||||
import { LoginService } from '../../services/login.service';
|
|
||||||
import { FooterComponent } from './footer/footer.component';
|
import { FooterComponent } from './footer/footer.component';
|
||||||
import { HeaderComponent } from './header/header.component';
|
import { HeaderComponent } from './header/header.component';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
@ -12,6 +11,7 @@ import { OverlayService } from '../../services/overlay.service';
|
||||||
import { AuthService } from '../../services/auth.service';
|
import { AuthService } from '../../services/auth.service';
|
||||||
import { TokenService } from '../../services/token.service';
|
import { TokenService } from '../../services/token.service';
|
||||||
import { ButtonStateService } from '../../services/button-state.service';
|
import { ButtonStateService } from '../../services/button-state.service';
|
||||||
|
import { PasswordVisibilityService } from '../../services/password-visibility.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
|
|
@ -39,13 +39,12 @@ export class LoginComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
public pwVisibility: PasswordVisibilityService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
public loginService: LoginService,
|
|
||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
private buttonStateService: ButtonStateService,
|
private buttonStateService: ButtonStateService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute
|
||||||
private router: Router
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
id="password"
|
id="password"
|
||||||
name="password"
|
name="password"
|
||||||
#password="ngModel"
|
#password="ngModel"
|
||||||
[type]="loginService.passwordFieldType"
|
[type]="pwVisibility.passwordFieldType"
|
||||||
placeholder="{{ 'register.password' | translate }}"
|
placeholder="{{ 'register.password' | translate }}"
|
||||||
class="custom-input"
|
class="custom-input"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
|
|
@ -102,8 +102,8 @@
|
||||||
} @else {
|
} @else {
|
||||||
<img
|
<img
|
||||||
class="passwordEye"
|
class="passwordEye"
|
||||||
(click)="loginService.togglePasswordVisibility()"
|
(click)="pwVisibility.togglePasswordVisibility()"
|
||||||
[src]="loginService.passwordIcon"
|
[src]="pwVisibility.passwordIcon"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
|
|
@ -119,7 +119,7 @@
|
||||||
id="passwordConfirm"
|
id="passwordConfirm"
|
||||||
name="passwordConfirm"
|
name="passwordConfirm"
|
||||||
#passwordConfirm="ngModel"
|
#passwordConfirm="ngModel"
|
||||||
[type]="loginService.passwordFieldType"
|
[type]="pwVisibility.passwordFieldType"
|
||||||
placeholder="{{ 'register.passwordConfirm' | translate }}"
|
placeholder="{{ 'register.passwordConfirm' | translate }}"
|
||||||
class="custom-input"
|
class="custom-input"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
|
|
@ -136,8 +136,8 @@
|
||||||
} @else {
|
} @else {
|
||||||
<img
|
<img
|
||||||
class="passwordEyeConfirm"
|
class="passwordEyeConfirm"
|
||||||
(click)="loginService.togglePasswordVisibility()"
|
(click)="pwVisibility.togglePasswordVisibility()"
|
||||||
[src]="loginService.passwordIcon"
|
[src]="pwVisibility.passwordIcon"
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { FooterComponent } from '../footer/footer.component';
|
||||||
import { FormsModule, NgForm } from '@angular/forms';
|
import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FormBtnComponent } from '../../../shared/components/buttons/form-btn/form-btn.component';
|
import { FormBtnComponent } from '../../../shared/components/buttons/form-btn/form-btn.component';
|
||||||
import { LoginService } from '../../../services/login.service';
|
import { PasswordVisibilityService } from '../../../services/password-visibility.service';
|
||||||
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
import { TranslateModule, TranslateService } from '@ngx-translate/core';
|
||||||
|
|
@ -43,7 +43,7 @@ export class RegisterComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public loginService: LoginService,
|
public pwVisibility: PasswordVisibilityService,
|
||||||
public translateService: TranslateService,
|
public translateService: TranslateService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
private buttonStateService: ButtonStateService
|
private buttonStateService: ButtonStateService
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,9 @@ import { ToastNotificationService } from './toast-notification.service';
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
private currentUserIdSubject = new BehaviorSubject<string | null>(null);
|
private currentUserIdSubject = new BehaviorSubject<string | null>(null);
|
||||||
|
|
||||||
|
passwordFieldType: string = 'password';
|
||||||
|
passwordIcon: string = './../../../assets/img/login/close-eye.svg';
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
|
|
@ -112,4 +115,17 @@ export class AuthService {
|
||||||
getCurrentUserId(): Observable<string | null> {
|
getCurrentUserId(): Observable<string | null> {
|
||||||
return this.currentUserIdSubject.asObservable();
|
return this.currentUserIdSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
togglePasswordVisibility() {
|
||||||
|
this.passwordFieldType =
|
||||||
|
this.passwordFieldType === 'password' ? 'text' : 'password';
|
||||||
|
this.toggleIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleIcon() {
|
||||||
|
this.passwordIcon =
|
||||||
|
this.passwordIcon === './../../../assets/img/login/close-eye.svg'
|
||||||
|
? './../../../assets/img/login/open-eye.svg'
|
||||||
|
: './../../../assets/img/login/close-eye.svg';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,358 +0,0 @@
|
||||||
import { Injectable, OnDestroy, inject } from '@angular/core';
|
|
||||||
import {
|
|
||||||
Firestore,
|
|
||||||
addDoc,
|
|
||||||
collection,
|
|
||||||
deleteDoc,
|
|
||||||
doc,
|
|
||||||
onSnapshot,
|
|
||||||
setDoc,
|
|
||||||
updateDoc,
|
|
||||||
} from '@angular/fire/firestore';
|
|
||||||
import { Task } from '../interfaces/task.interface';
|
|
||||||
import { User } from '../interfaces/user.interface';
|
|
||||||
import CryptoES from 'crypto-es';
|
|
||||||
import { CryptoESSecretKey } from './../environments/config';
|
|
||||||
import { Observable, of } from 'rxjs';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class FirebaseService implements OnDestroy {
|
|
||||||
firestore: Firestore = inject(Firestore);
|
|
||||||
private secretKey: string = CryptoESSecretKey.secretKey;
|
|
||||||
|
|
||||||
allTasks: Task[] = [];
|
|
||||||
filteredTasks: Task[] = [];
|
|
||||||
allUsers: User[] = [];
|
|
||||||
|
|
||||||
unsubTask;
|
|
||||||
unsubUser;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.unsubTask = this.subTaskList();
|
|
||||||
this.unsubUser = this.subUserList();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------- TASKS ------------- //
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes to Firestore for the list of all tasks.
|
|
||||||
*
|
|
||||||
* This function uses the `onSnapshot` function from `@angular/fire/firestore` to
|
|
||||||
* subscribe to the 'tasks' collection in Firestore. When the data in the
|
|
||||||
* collection changes, this function is called with a `QuerySnapshot` object as an
|
|
||||||
* argument. The function then iterates over the `QuerySnapshot` and creates a
|
|
||||||
* `Task` object from each document in the snapshot. The created `Task` objects are
|
|
||||||
* then stored in the `allTasks` array.
|
|
||||||
*
|
|
||||||
* @returns The unsubscribe function from `onSnapshot`.
|
|
||||||
*/
|
|
||||||
subTaskList() {
|
|
||||||
return onSnapshot(collection(this.firestore, 'tasks'), (list) => {
|
|
||||||
this.allTasks = [];
|
|
||||||
list.forEach((element) => {
|
|
||||||
const taskWithId = { id: element.id, ...element.data() } as Task;
|
|
||||||
this.allTasks.push(taskWithId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of all tasks.
|
|
||||||
*
|
|
||||||
* This function simply returns the value of the `allTasks` property, which is
|
|
||||||
* an array of `Task` objects that is kept up-to-date by the `subTaskList`
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* @returns The list of all tasks.
|
|
||||||
*/
|
|
||||||
getAllTasks(): Task[] {
|
|
||||||
return this.allTasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of tasks that match the current filter.
|
|
||||||
*
|
|
||||||
* This function simply returns the value of the `filteredTasks` property, which
|
|
||||||
* is an array of `Task` objects that is kept up-to-date by the `searchTask`
|
|
||||||
* function.
|
|
||||||
*
|
|
||||||
* @returns The list of filtered tasks.
|
|
||||||
*/
|
|
||||||
getFiltertTasks(): Task[] {
|
|
||||||
return this.filteredTasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the status of a task in the Firestore database.
|
|
||||||
*
|
|
||||||
* This function updates the status of the task identified by `taskId`
|
|
||||||
* using the status from the `allTasks` array at the specified `index`.
|
|
||||||
*
|
|
||||||
* @param taskId The ID of the task to be updated.
|
|
||||||
* @param index The index of the task in the `allTasks` array.
|
|
||||||
*/
|
|
||||||
async updateTask(taskId: string, index: number) {
|
|
||||||
await updateDoc(doc(collection(this.firestore, 'tasks'), taskId), {
|
|
||||||
status: this.allTasks[index].status,
|
|
||||||
}).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the subtasksDone property of a task in the Firestore database.
|
|
||||||
*
|
|
||||||
* This function updates the subtasksDone property of the task identified by
|
|
||||||
* `taskId` with the `array` parameter. The `array` parameter is an array of booleans
|
|
||||||
* that indicates which subtasks are completed.
|
|
||||||
*
|
|
||||||
* @param taskId The ID of the task to be updated.
|
|
||||||
* @param array An array of booleans that indicates which subtasks are completed.
|
|
||||||
*/
|
|
||||||
async updateSubTask(taskId: string, array: boolean[]) {
|
|
||||||
await updateDoc(doc(collection(this.firestore, 'tasks'), taskId), {
|
|
||||||
subtasksDone: array,
|
|
||||||
}).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the task identified by `taskId` with the data from the `newData` object.
|
|
||||||
*
|
|
||||||
* This function uses the `setDoc` function from `@angular/fire/firestore` to
|
|
||||||
* replace the task identified by `taskId` with the data from the `newData` object.
|
|
||||||
* The `newData` object should be of type `Task` and should contain all the fields
|
|
||||||
* that are required for a task.
|
|
||||||
*
|
|
||||||
* @param taskId The ID of the task to be replaced.
|
|
||||||
* @param newData The new task data.
|
|
||||||
*/
|
|
||||||
async replaceTaskData(taskId: string, newData: Task) {
|
|
||||||
await setDoc(
|
|
||||||
doc(collection(this.firestore, 'tasks'), taskId),
|
|
||||||
newData
|
|
||||||
).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the task with the specified ID from the Firestore database.
|
|
||||||
*
|
|
||||||
* This function uses the `deleteDoc` function to remove the task identified by
|
|
||||||
* `taskId` from the 'tasks' collection in Firestore.
|
|
||||||
*
|
|
||||||
* @param taskId The ID of the task to be deleted.
|
|
||||||
*/
|
|
||||||
async deleteTask(taskId: string) {
|
|
||||||
await deleteDoc(doc(collection(this.firestore, 'tasks'), taskId)).catch(
|
|
||||||
(err) => {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new task to the Firestore database.
|
|
||||||
*
|
|
||||||
* This function uses the `addDoc` function from `@angular/fire/firestore` to add
|
|
||||||
* the task to the 'tasks' collection in Firestore. The `task` parameter should be
|
|
||||||
* of type `Task` and should contain all the fields that are required for a task.
|
|
||||||
*
|
|
||||||
* @param task The new task data to be added.
|
|
||||||
*/
|
|
||||||
async addNewTask(task: Task) {
|
|
||||||
await addDoc(collection(this.firestore, 'tasks'), task).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------- USERS ------------- //
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Subscribes to Firestore for the list of all users.
|
|
||||||
*
|
|
||||||
* This function uses the `onSnapshot` function from `@angular/fire/firestore` to
|
|
||||||
* subscribe to the 'users' collection in Firestore. When the data in the
|
|
||||||
* collection changes, this function is called with a `QuerySnapshot` object as an
|
|
||||||
* argument. The function then iterates over the `QuerySnapshot` and creates a
|
|
||||||
* `User` object from each document in the snapshot. The created `User` objects are
|
|
||||||
* then stored in the `allUsers` array.
|
|
||||||
*
|
|
||||||
* @returns The unsubscribe function from `onSnapshot`.
|
|
||||||
*/
|
|
||||||
subUserList() {
|
|
||||||
return onSnapshot(collection(this.firestore, 'users'), (list) => {
|
|
||||||
this.allUsers = [];
|
|
||||||
list.forEach((element) => {
|
|
||||||
const userWithId = { id: element.id, ...element.data() } as User;
|
|
||||||
this.allUsers.push(userWithId);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the list of all users.
|
|
||||||
*
|
|
||||||
* @returns An array of User objects.
|
|
||||||
*/
|
|
||||||
getAllUsers(): User[] {
|
|
||||||
return this.allUsers;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a list of all users excluding those with initials 'G' (typically representing guest users).
|
|
||||||
*
|
|
||||||
* @returns An array of User objects without guest users.
|
|
||||||
*/
|
|
||||||
getAllUserWithoutGuest(): User[] {
|
|
||||||
return this.getAllUsers().filter((user) => user.initials !== 'G');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a list of all users excluding guest users and the current user and the task creator.
|
|
||||||
*
|
|
||||||
* @param taskCreator - The id of the task creator.
|
|
||||||
* @returns An array of User objects excluding guest users, the current user, and the task creator.
|
|
||||||
*/
|
|
||||||
getFilteredUsers(taskCreator: string): User[] {
|
|
||||||
const currentUser = this.getCurrentUserId();
|
|
||||||
const filteredUsers = this.getAllUsers().filter(
|
|
||||||
(user) => user.initials !== 'G' && user.id !== currentUser
|
|
||||||
);
|
|
||||||
return filteredUsers.filter((user) => user.id !== taskCreator);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a list of users from the list of all users that have the given userId.
|
|
||||||
*
|
|
||||||
* @param userId - The id of the user to be retrieved.
|
|
||||||
* @returns An array of User objects with the given userId.
|
|
||||||
*/
|
|
||||||
getUserDataFromId(userId: string): User[] {
|
|
||||||
return this.getAllUsers().filter((user) => user.id === userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves a list of users from the list of all users that have the given userUid.
|
|
||||||
*
|
|
||||||
* @param userUid - The unique identifier of the user to be retrieved.
|
|
||||||
* @returns An array of User objects with the given userUid.
|
|
||||||
*/
|
|
||||||
getUserDataFromUid(userUid: string): User[] {
|
|
||||||
return this.getAllUsers().filter((user) => user.id === userUid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the current user ID from local storage.
|
|
||||||
*
|
|
||||||
* The current user ID is stored in local storage encrypted with the secret key.
|
|
||||||
* This method decrypts the value and returns the current user ID as a string.
|
|
||||||
* If the value does not exist or is not decryptable, it returns null.
|
|
||||||
* @returns The current user ID as a string, or null if not found.
|
|
||||||
*/
|
|
||||||
getCurrentUserId() {
|
|
||||||
const encryptedValue = localStorage.getItem('currentUserJOIN');
|
|
||||||
if (encryptedValue) {
|
|
||||||
const bytes = CryptoES.AES.decrypt(encryptedValue, this.secretKey);
|
|
||||||
const decryptedValue = bytes.toString(CryptoES.enc.Utf8);
|
|
||||||
return JSON.parse(decryptedValue);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves specific user information from the list of all users.
|
|
||||||
*
|
|
||||||
* @param userId - The id of the user whose information is to be retrieved.
|
|
||||||
* @param query - The specific field of the user object to be retrieved, such as 'firstName', 'email', etc.
|
|
||||||
* @returns An array containing the values of the specified field for the user with the given userId.
|
|
||||||
*/
|
|
||||||
getUserDetails(userId: string, query: keyof User) {
|
|
||||||
return this.getAllUsers()
|
|
||||||
.filter((user) => user.id === userId)
|
|
||||||
.map((user) => user[query]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes a user document from the Firestore database.
|
|
||||||
*
|
|
||||||
* @param docId The id of the document to be deleted.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
* @throws An error if the deletion attempt fails.
|
|
||||||
*/
|
|
||||||
async deleteUser(docId: string) {
|
|
||||||
await deleteDoc(doc(collection(this.firestore, 'users'), docId)).catch(
|
|
||||||
(err) => {
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates a user document in the Firestore database.
|
|
||||||
*
|
|
||||||
* @param docId The id of the document to be updated.
|
|
||||||
* @param data The object with the new data to be updated.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
* @throws An error if the update attempt fails.
|
|
||||||
*/
|
|
||||||
async updateUserData(docId: string, data: any) {
|
|
||||||
await updateDoc(
|
|
||||||
doc(collection(this.firestore, 'users'), docId),
|
|
||||||
data
|
|
||||||
).catch((err) => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a new user to the Firestore database.
|
|
||||||
*
|
|
||||||
* @param userData The data of the user to be added.
|
|
||||||
* @returns A Promise resolving to the newly added user document.
|
|
||||||
* @throws An error if the add attempt fails.
|
|
||||||
*/
|
|
||||||
async addNewUser(userData: User) {
|
|
||||||
try {
|
|
||||||
return await addDoc(collection(this.firestore, 'users'), userData);
|
|
||||||
} catch (err) {
|
|
||||||
console.error(err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------- AUTH ------------- //
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the current user from local storage.
|
|
||||||
*
|
|
||||||
* The current user is stored in local storage encrypted with the secret key.
|
|
||||||
* This method decrypts the value and returns the current user as an Observable,
|
|
||||||
* or null if not found.
|
|
||||||
* @returns An Observable resolving to the current user, or null if not found.
|
|
||||||
*/
|
|
||||||
getAuthUser(): Observable<any> {
|
|
||||||
const encryptedValue = localStorage.getItem('currentUserJOIN');
|
|
||||||
if (encryptedValue) {
|
|
||||||
const bytes = CryptoES.AES.decrypt(encryptedValue, this.secretKey);
|
|
||||||
const decryptedValue = bytes.toString(CryptoES.enc.Utf8);
|
|
||||||
return of(JSON.parse(decryptedValue));
|
|
||||||
}
|
|
||||||
return of(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------- Destroy ------------- //
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Lifecycle hook that is called when the component is about to be destroyed.
|
|
||||||
* Unsubscribes from task and user changes to prevent memory leaks.
|
|
||||||
*/
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.unsubTask();
|
|
||||||
this.unsubUser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,361 +0,0 @@
|
||||||
import { Injectable, inject } from '@angular/core';
|
|
||||||
import {
|
|
||||||
getAuth,
|
|
||||||
signInWithEmailAndPassword,
|
|
||||||
signInWithPopup,
|
|
||||||
GoogleAuthProvider,
|
|
||||||
createUserWithEmailAndPassword,
|
|
||||||
sendPasswordResetEmail,
|
|
||||||
confirmPasswordReset,
|
|
||||||
} from 'firebase/auth';
|
|
||||||
import { FirebaseService } from './firebase.service';
|
|
||||||
import {
|
|
||||||
Firestore,
|
|
||||||
addDoc,
|
|
||||||
collection,
|
|
||||||
doc,
|
|
||||||
getDocs,
|
|
||||||
query,
|
|
||||||
updateDoc,
|
|
||||||
where,
|
|
||||||
} from '@angular/fire/firestore';
|
|
||||||
import { User } from '../interfaces/user.interface';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import CryptoES from 'crypto-es';
|
|
||||||
import { CryptoESSecretKey } from '../environments/config';
|
|
||||||
import { catchError, map, Observable, of } from 'rxjs';
|
|
||||||
import { ButtonStateService } from './button-state.service';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class LoginService {
|
|
||||||
firestore: Firestore = inject(Firestore);
|
|
||||||
passwordFieldType: string = 'password';
|
|
||||||
passwordIcon: string = './../../../assets/img/login/close-eye.svg';
|
|
||||||
errorCode: string = '';
|
|
||||||
|
|
||||||
private secretKey: string = CryptoESSecretKey.secretKey;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private firebaseService: FirebaseService,
|
|
||||||
private buttonStateService: ButtonStateService,
|
|
||||||
private router: Router
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a user is logged in.
|
|
||||||
*
|
|
||||||
* @returns An Observable resolving to a boolean indicating whether a user is logged in.
|
|
||||||
*/
|
|
||||||
checkAuthUser(): Observable<boolean> {
|
|
||||||
return this.firebaseService.getAuthUser().pipe(
|
|
||||||
map((user) => {
|
|
||||||
if (user) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
catchError(() => {
|
|
||||||
return of(false);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs in a user given their email and password.
|
|
||||||
* @param loginData An object with properties `mail` and `password`.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
* @throws An error if the login attempt fails.
|
|
||||||
*/
|
|
||||||
login(loginData: { mail: string; password: string }) {
|
|
||||||
signInWithEmailAndPassword(getAuth(), loginData.mail, loginData.password)
|
|
||||||
.then((userCredential) => {
|
|
||||||
const user = userCredential.user;
|
|
||||||
const userData = this.firebaseService.getUserDataFromUid(user.uid);
|
|
||||||
if (userData.length > 0 && userData[0].id) {
|
|
||||||
this.getUserIdInLocalStorage(userData[0].id);
|
|
||||||
this.updateUserOnlineStatus(userData[0].id, true);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.errorCode = error.code;
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a new user given their name, first name, last name, email and password.
|
|
||||||
* @param registerData An object with properties `name`, `firstName`, `lastName`, `mail` and `password`.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
* @throws An error if the registration attempt fails.
|
|
||||||
*/
|
|
||||||
register(registerData: {
|
|
||||||
name: string;
|
|
||||||
firstName: string;
|
|
||||||
lastName: string;
|
|
||||||
mail: string;
|
|
||||||
password: string;
|
|
||||||
}) {
|
|
||||||
createUserWithEmailAndPassword(
|
|
||||||
getAuth(),
|
|
||||||
registerData.mail,
|
|
||||||
registerData.password
|
|
||||||
)
|
|
||||||
.then((userCredential) => {
|
|
||||||
const user = userCredential.user;
|
|
||||||
|
|
||||||
const userDataToSave: User = {
|
|
||||||
email: user.email || '',
|
|
||||||
firstName: registerData.firstName
|
|
||||||
? registerData.firstName.charAt(0).toUpperCase() +
|
|
||||||
registerData.firstName.slice(1)
|
|
||||||
: '',
|
|
||||||
lastName: registerData.lastName
|
|
||||||
? registerData.lastName.charAt(0).toUpperCase() +
|
|
||||||
registerData.lastName.slice(1)
|
|
||||||
: '',
|
|
||||||
isContactOnly: false,
|
|
||||||
isOnline: true,
|
|
||||||
phone: '',
|
|
||||||
initials: registerData.name
|
|
||||||
? registerData.firstName.slice(0, 1).toUpperCase() +
|
|
||||||
registerData.lastName.slice(0, 1).toUpperCase()
|
|
||||||
: '',
|
|
||||||
color: '',
|
|
||||||
lastLogin: new Date().getTime(),
|
|
||||||
};
|
|
||||||
this.createUserInFirestore(userDataToSave);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Google login method.
|
|
||||||
*
|
|
||||||
* Signs in the user with Google Authentication.
|
|
||||||
* If the user is not in the database, creates a new user with the provided name and email.
|
|
||||||
* If the user is already in the database, logins the user.
|
|
||||||
*
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
* @memberof LoginService
|
|
||||||
*/
|
|
||||||
googleLogin() {
|
|
||||||
const auth = getAuth();
|
|
||||||
const provider = new GoogleAuthProvider();
|
|
||||||
|
|
||||||
signInWithPopup(auth, provider)
|
|
||||||
.then((userCredential) => {
|
|
||||||
const user = userCredential.user;
|
|
||||||
const usersCollection = collection(this.firestore, 'users');
|
|
||||||
const querySnapshot = query(
|
|
||||||
usersCollection,
|
|
||||||
where('uId', '==', user.uid)
|
|
||||||
);
|
|
||||||
getDocs(querySnapshot).then((snapshot) => {
|
|
||||||
if (snapshot.empty) {
|
|
||||||
const displayName = user.displayName || '';
|
|
||||||
const [firstName = '', lastName = ''] = displayName.split(' ');
|
|
||||||
this.createUserInFirestore({
|
|
||||||
email: user.email || 'no mail',
|
|
||||||
firstName: firstName.charAt(0).toUpperCase() + firstName.slice(1),
|
|
||||||
lastName: lastName.charAt(0).toUpperCase() + lastName.slice(1),
|
|
||||||
isContactOnly: false,
|
|
||||||
isOnline: true,
|
|
||||||
phone: '',
|
|
||||||
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
|
||||||
color: '',
|
|
||||||
lastLogin: 0,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.ifExistUser(user.uid);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new user in the Firestore database with the given user data.
|
|
||||||
* If the user already exists in the database, the method does nothing.
|
|
||||||
* @param user The user data to save. The user data should contain the following properties: `uId`, `email`, `firstName`, `lastName`, `initials`, `color`.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
*/
|
|
||||||
async createUserInFirestore(user: User) {
|
|
||||||
const userDataToSave: User = {
|
|
||||||
email: user.email,
|
|
||||||
firstName: user.firstName || '',
|
|
||||||
lastName: user.lastName || '',
|
|
||||||
isContactOnly: false,
|
|
||||||
isOnline: true,
|
|
||||||
phone: '',
|
|
||||||
initials: user.initials,
|
|
||||||
color: user.color,
|
|
||||||
lastLogin: new Date().getTime(),
|
|
||||||
};
|
|
||||||
const usersCollection = collection(this.firestore, 'users');
|
|
||||||
try {
|
|
||||||
const docRef = await addDoc(usersCollection, userDataToSave);
|
|
||||||
//this.ifExistUser(user.uId);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a user with the given user id exists in the database.
|
|
||||||
* If the user exists, the method saves the user's id in the local storage and
|
|
||||||
* updates the user's online status in the database.
|
|
||||||
* @param user The id of the user to check.
|
|
||||||
* @returns void
|
|
||||||
*/
|
|
||||||
ifExistUser(user: string) {
|
|
||||||
const userData = this.firebaseService.getUserDataFromUid(user);
|
|
||||||
if (userData.length > 0 && userData[0].id) {
|
|
||||||
this.getUserIdInLocalStorage(userData[0].id);
|
|
||||||
this.updateUserOnlineStatus(userData[0].id, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the online status of the user with the given id in the Firestore database.
|
|
||||||
* If the user's status is set to true, the user's lastLogin property is also updated
|
|
||||||
* to the current time.
|
|
||||||
* @param userId The id of the user to update.
|
|
||||||
* @param status The new online status of the user.
|
|
||||||
* @returns A Promise resolving to void.
|
|
||||||
*/
|
|
||||||
async updateUserOnlineStatus(userId: string, status: boolean) {
|
|
||||||
await updateDoc(doc(collection(this.firestore, 'users'), userId), {
|
|
||||||
status: status,
|
|
||||||
lastLogin: new Date().getTime(),
|
|
||||||
});
|
|
||||||
window.location.reload();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the visibility of the password field.
|
|
||||||
*
|
|
||||||
* This function switches the input type between 'password' and 'text',
|
|
||||||
* allowing the user to view or hide the password as needed.
|
|
||||||
* It also updates the icon to reflect the current visibility state.
|
|
||||||
*/
|
|
||||||
togglePasswordVisibility() {
|
|
||||||
this.passwordFieldType =
|
|
||||||
this.passwordFieldType === 'password' ? 'text' : 'password';
|
|
||||||
this.toggleIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Toggles the password visibility icon.
|
|
||||||
*
|
|
||||||
* This function switches the icon src between the 'close eye' and 'open eye'
|
|
||||||
* icons, indicating whether the password is hidden or visible.
|
|
||||||
*/
|
|
||||||
toggleIcon() {
|
|
||||||
this.passwordIcon =
|
|
||||||
this.passwordIcon === './../../../assets/img/login/close-eye.svg'
|
|
||||||
? './../../../assets/img/login/open-eye.svg'
|
|
||||||
: './../../../assets/img/login/close-eye.svg';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves the given userId to local storage, encrypted with the secret key.
|
|
||||||
*
|
|
||||||
* The userId is first stringified and then encrypted with the secret key.
|
|
||||||
* The encrypted string is then saved to local storage under the key
|
|
||||||
* 'currentUserJOIN'. Additionally, the current timestamp is saved to local
|
|
||||||
* storage under the key 'sessionTimeJOIN'.
|
|
||||||
*
|
|
||||||
* @param userId The id of the user to be saved.
|
|
||||||
*/
|
|
||||||
getUserIdInLocalStorage(userId: string): void {
|
|
||||||
const encryptedValue = CryptoES.AES.encrypt(
|
|
||||||
JSON.stringify(userId),
|
|
||||||
this.secretKey
|
|
||||||
).toString();
|
|
||||||
localStorage.setItem('currentUserJOIN', encryptedValue);
|
|
||||||
localStorage.setItem('sessionTimeJOIN', new Date().getTime().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// LOGOUT
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logs out the current user by deleting the user ID from local storage and
|
|
||||||
* updating the user's online status to offline in the Firestore database.
|
|
||||||
*
|
|
||||||
* @param userId The id of the user to log out.
|
|
||||||
*/
|
|
||||||
logout(userId: string) {
|
|
||||||
this.deleteUserIdInLocalStorage();
|
|
||||||
this.updateUserOnlineStatus(userId, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the user ID from local storage, effectively logging the user out.
|
|
||||||
*
|
|
||||||
* This function removes the user ID from local storage by deleting the
|
|
||||||
* 'currentUserJOIN' and 'sessionTimeJOIN' items.
|
|
||||||
*/
|
|
||||||
deleteUserIdInLocalStorage() {
|
|
||||||
localStorage.removeItem('currentUserJOIN');
|
|
||||||
localStorage.removeItem('sessionTimeJOIN');
|
|
||||||
}
|
|
||||||
|
|
||||||
// FORGOT PASSWORD
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates the password reset process for the given email address.
|
|
||||||
*
|
|
||||||
* This function sends a password reset email to the specified email address
|
|
||||||
* using Firebase Authentication. Upon successful sending of the email, the
|
|
||||||
* user is redirected to the password reset notice page. If there is an error,
|
|
||||||
* the button will be re-enabled for the user to try again.
|
|
||||||
*
|
|
||||||
* @param email The email address of the user requesting a password reset.
|
|
||||||
*/
|
|
||||||
passwordReset(email: string) {
|
|
||||||
const auth = getAuth();
|
|
||||||
const actionCodeSettings = {
|
|
||||||
url: 'https://join.andre-kempf.com/',
|
|
||||||
handleCodeInApp: true,
|
|
||||||
};
|
|
||||||
sendPasswordResetEmail(auth, email, actionCodeSettings)
|
|
||||||
.then(() => {
|
|
||||||
this.router.navigate(['/login/notice/pw-send']);
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resets the user's password given the new password and the oobCode from the
|
|
||||||
* password reset email.
|
|
||||||
*
|
|
||||||
* This function sends a request to Firebase Authentication to reset the user's
|
|
||||||
* password. If the request is successful, it navigates to the password reset
|
|
||||||
* notice page and re-enables the submit button. If there is an error, the
|
|
||||||
* button will be re-enabled for the user to try again.
|
|
||||||
*
|
|
||||||
* @param newPW The new password to be set for the user.
|
|
||||||
* @param oobCode The one-time code from the password reset email.
|
|
||||||
*/
|
|
||||||
newPassword(newPW: string, oobCode: string) {
|
|
||||||
const auth = getAuth();
|
|
||||||
confirmPasswordReset(auth, oobCode, newPW)
|
|
||||||
.then(() => {
|
|
||||||
this.router.navigate(['/login/notice/pw-change']);
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
this.buttonStateService.disableButton();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
22
src/app/services/password-visibility.service.ts
Normal file
22
src/app/services/password-visibility.service.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class PasswordVisibilityService {
|
||||||
|
passwordFieldType: string = 'password';
|
||||||
|
passwordIcon: string = './../../../assets/img/login/close-eye.svg';
|
||||||
|
|
||||||
|
togglePasswordVisibility() {
|
||||||
|
this.passwordFieldType =
|
||||||
|
this.passwordFieldType === 'password' ? 'text' : 'password';
|
||||||
|
this.toggleIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleIcon() {
|
||||||
|
this.passwordIcon =
|
||||||
|
this.passwordIcon === './../../../assets/img/login/close-eye.svg'
|
||||||
|
? './../../../assets/img/login/open-eye.svg'
|
||||||
|
: './../../../assets/img/login/close-eye.svg';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@ import { Router, RouterModule } from '@angular/router';
|
||||||
import { LanguageService } from '../../../../services/language.service';
|
import { LanguageService } from '../../../../services/language.service';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LoginService } from '../../../../services/login.service';
|
|
||||||
import { AuthService } from '../../../../services/auth.service';
|
import { AuthService } from '../../../../services/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue