refactor: SharedService refactored and dissolved, created ButtonStateService, renamed ContactEditDialog to ContactOverlay and moved to Overlays
This commit is contained in:
parent
8659c16517
commit
db242700e0
44 changed files with 209 additions and 726 deletions
|
|
@ -1 +1 @@
|
||||||
<router-outlet></router-outlet> <app-overlay></app-overlay>
|
<router-outlet></router-outlet>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,10 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { OverlayComponent } from './shared/components/overlay/overlay.component';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [RouterOutlet, OverlayComponent],
|
imports: [RouterOutlet],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
styleUrl: './app.component.scss',
|
styleUrl: './app.component.scss',
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import { OverlayService } from '../../services/overlay.service';
|
||||||
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 } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { SharedService } from '../../services/shared.service';
|
|
||||||
import { AuthService } from '../../services/auth.service';
|
import { AuthService } from '../../services/auth.service';
|
||||||
import { firstValueFrom, map } from 'rxjs';
|
import { firstValueFrom, map } from 'rxjs';
|
||||||
import { TaskService } from '../../services/task.service';
|
import { TaskService } from '../../services/task.service';
|
||||||
|
|
@ -49,7 +48,6 @@ export class AddTaskComponent implements OnInit {
|
||||||
constructor(
|
constructor(
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
private sharedService: SharedService,
|
|
||||||
private taskService: TaskService,
|
private taskService: TaskService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<section>
|
|
||||||
<div class="dialog">
|
|
||||||
<p>
|
|
||||||
{{ "contactDeleteDialog.deleteContact" | translate }}
|
|
||||||
</p>
|
|
||||||
<div class="btns">
|
|
||||||
<div class="btn">
|
|
||||||
<div class="btn-cancel" (click)="cancelDeleteContact()">
|
|
||||||
{{ "contactDeleteDialog.btnCancel" | translate }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="btn">
|
|
||||||
<div class="btn-delete-contact" (click)="deleteContact()">
|
|
||||||
{{ "contactDeleteDialog.btnDelete" | translate }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
@ -1,109 +0,0 @@
|
||||||
section {
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dialog {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
background-color: var(--white);
|
|
||||||
width: 600px;
|
|
||||||
height: 200px;
|
|
||||||
border-radius: 26px;
|
|
||||||
margin: 24px;
|
|
||||||
border: 2px solid rgba($color: #000000, $alpha: 0.1);
|
|
||||||
p {
|
|
||||||
text-align: center;
|
|
||||||
font-size: 27px;
|
|
||||||
font-weight: 500;
|
|
||||||
margin-bottom: 12px;
|
|
||||||
padding: 0 12px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btns {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
width: 111px;
|
|
||||||
height: 57px;
|
|
||||||
margin: 0 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-cancel {
|
|
||||||
padding: 12px;
|
|
||||||
margin: 12px 12px;
|
|
||||||
border-radius: 10px;
|
|
||||||
border-color: var(--black);
|
|
||||||
background-color: var(--dark-blue);
|
|
||||||
color: var(--white);
|
|
||||||
font-size: 23px;
|
|
||||||
font-weight: 400;
|
|
||||||
transition: 125ms ease-in-out;
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--light-blue);
|
|
||||||
box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-delete-contact {
|
|
||||||
padding: 12px;
|
|
||||||
margin: 12px 12px;
|
|
||||||
border-radius: 10px;
|
|
||||||
color: var(--red);
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid var(--red);
|
|
||||||
font-size: 23px;
|
|
||||||
font-weight: 400;
|
|
||||||
transition: 125ms ease-in-out;
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
color: var(--white);
|
|
||||||
background-color: var(--red);
|
|
||||||
border-color: var(--black);
|
|
||||||
box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 450px) {
|
|
||||||
.dialog {
|
|
||||||
p {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (max-width: 350px) {
|
|
||||||
.dialog {
|
|
||||||
width: 280px;
|
|
||||||
p {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
width: 100px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn-delete-contact,
|
|
||||||
.btn-cancel {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ContactDeleteComponent } from './contact-delete.component';
|
|
||||||
|
|
||||||
describe('ContactDeleteComponent', () => {
|
|
||||||
let component: ContactDeleteComponent;
|
|
||||||
let fixture: ComponentFixture<ContactDeleteComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
imports: [ContactDeleteComponent]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ContactDeleteComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
import { Component, Input } from '@angular/core';
|
|
||||||
import { SharedService } from '../../../services/shared.service';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { FirebaseService } from '../../../services/firebase.service';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-contact-delete',
|
|
||||||
standalone: true,
|
|
||||||
imports: [TranslateModule],
|
|
||||||
templateUrl: './contact-delete.component.html',
|
|
||||||
styleUrl: './contact-delete.component.scss',
|
|
||||||
})
|
|
||||||
export class ContactDeleteComponent {
|
|
||||||
@Input() currentUserId: string = '';
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
private sharedService: SharedService,
|
|
||||||
private firebaseService: FirebaseService,
|
|
||||||
private router: Router
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deletes the current user and performs cleanup operations.
|
|
||||||
* This method deletes the user with the current user ID from the database,
|
|
||||||
* navigates to the contacts page, and closes any open dialog flags in the shared service.
|
|
||||||
* It also checks if the deleted contact was assigned to any tasks and removes them.
|
|
||||||
*/
|
|
||||||
deleteContact() {
|
|
||||||
this.firebaseService.deleteUser(this.currentUserId);
|
|
||||||
this.router.navigate(['contacts']);
|
|
||||||
this.sharedService.isDeleteContactDialogOpen = false;
|
|
||||||
this.sharedService.isAnyDialogOpen = false;
|
|
||||||
this.checkIfContactAnAssigned();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the deleted contact was assigned to any tasks and removes them.
|
|
||||||
* This method retrieves all tasks from the database, iterates over them,
|
|
||||||
* and checks if the current user ID is in the task's assigned array.
|
|
||||||
* If the ID is found, it is removed from the array and the modified task
|
|
||||||
* is updated in the database.
|
|
||||||
*/
|
|
||||||
checkIfContactAnAssigned() {
|
|
||||||
const tasks = this.firebaseService.getAllTasks();
|
|
||||||
|
|
||||||
tasks.forEach((task) => {
|
|
||||||
const index = task.assigned.indexOf(this.currentUserId);
|
|
||||||
if (index !== -1) {
|
|
||||||
task.assigned.splice(index, 1);
|
|
||||||
const { id, ...taskWithoutIds } = task;
|
|
||||||
if (task.id) {
|
|
||||||
this.firebaseService.replaceTaskData(task.id, taskWithoutIds);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the delete contact dialog by setting the appropriate flags in the shared service.
|
|
||||||
* If the edit contact dialog is not open, it also closes any open dialog flags in the shared service.
|
|
||||||
*/
|
|
||||||
cancelDeleteContact() {
|
|
||||||
this.sharedService.isDeleteContactDialogOpen = false;
|
|
||||||
if (!this.sharedService.isEditContactDialogOpen) {
|
|
||||||
this.sharedService.isAnyDialogOpen = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -49,17 +49,17 @@
|
||||||
@if(selectedUser.isContactOnly || currentUser && selectedUser.id ===
|
@if(selectedUser.isContactOnly || currentUser && selectedUser.id ===
|
||||||
currentUser.id) {
|
currentUser.id) {
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<div class="btn btn-edit">
|
<div class="btn btn-edit" (click)="editContact(selectedUser)">
|
||||||
<img src="./../../../../assets/img/contact/edit.svg" alt="" />
|
<img src="./../../../../assets/img/contact/edit.svg" alt="" />
|
||||||
<p (click)="openEditDialog()">
|
<p>
|
||||||
{{ "contacts.btnEdit0" | translate }}
|
{{ "contacts.btnEdit0" | translate }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@if (selectedUser.isContactOnly || currentUser && selectedUser.id !==
|
@if (selectedUser.isContactOnly || currentUser && selectedUser.id !==
|
||||||
currentUser.id) {
|
currentUser.id) {
|
||||||
<div class="btn btn-delete">
|
<div class="btn btn-delete" (click)="openDeleteContactDialog()">
|
||||||
<img src="./../../../../assets/img/contact/delete.svg" alt="" />
|
<img src="./../../../../assets/img/contact/delete.svg" alt="" />
|
||||||
<p (click)="deleteContact()">
|
<p>
|
||||||
{{ "contacts.btnDelete0" | translate }}
|
{{ "contacts.btnDelete0" | translate }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -96,10 +96,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
} @if (sharedService.isMobileNavbarOpen) {
|
} @if (isMobileNavbarOpen) {
|
||||||
<app-contact-nav
|
<!-- TODO -->
|
||||||
[deleteContact]="deleteContact"
|
|
||||||
[openEditDialog]="openEditDialog"
|
|
||||||
></app-contact-nav>
|
|
||||||
}
|
}
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,22 @@
|
||||||
import {
|
import {
|
||||||
Component,
|
Component,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
HostListener,
|
|
||||||
Input,
|
Input,
|
||||||
Output,
|
Output,
|
||||||
SimpleChanges,
|
SimpleChanges,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { SharedService } from '../../../services/shared.service';
|
|
||||||
import { ContactNavComponent } from '../contact-nav/contact-nav.component';
|
|
||||||
import { FirebaseService } from '../../../services/firebase.service';
|
import { FirebaseService } from '../../../services/firebase.service';
|
||||||
import { LanguageService } from '../../../services/language.service';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { UserService } from '../../../services/user.service';
|
import { UserService } from '../../../services/user.service';
|
||||||
import { finalize } from 'rxjs';
|
import { finalize } from 'rxjs';
|
||||||
import { User } from '../../../interfaces/user.interface';
|
import { User } from '../../../interfaces/user.interface';
|
||||||
|
import { OverlayService } from '../../../services/overlay.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact-detail',
|
selector: 'app-contact-detail',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CommonModule, TranslateModule, ContactNavComponent],
|
imports: [CommonModule, TranslateModule],
|
||||||
templateUrl: './contact-detail.component.html',
|
templateUrl: './contact-detail.component.html',
|
||||||
styleUrl: './contact-detail.component.scss',
|
styleUrl: './contact-detail.component.scss',
|
||||||
})
|
})
|
||||||
|
|
@ -31,10 +27,11 @@ export class ContactDetailComponent {
|
||||||
|
|
||||||
isLoading: boolean = false;
|
isLoading: boolean = false;
|
||||||
selectedUser: User | null = null;
|
selectedUser: User | null = null;
|
||||||
|
isMobileNavbarOpen: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public sharedService: SharedService,
|
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
|
private overlayService: OverlayService,
|
||||||
private userService: UserService
|
private userService: UserService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -84,68 +81,24 @@ export class ContactDetailComponent {
|
||||||
* the mobile navigation bar when the user clicks the three points icon.
|
* the mobile navigation bar when the user clicks the three points icon.
|
||||||
*/
|
*/
|
||||||
toggleNav() {
|
toggleNav() {
|
||||||
this.sharedService.isMobileNavbarOpen =
|
this.isMobileNavbarOpen = !this.isMobileNavbarOpen;
|
||||||
!this.sharedService.isMobileNavbarOpen;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the edit contact dialog by setting the appropriate flags in the shared service.
|
* Opens the edit contact dialog by setting the appropriate flags in the shared service.
|
||||||
* This method is used by the contact details component to open the edit contact dialog when the user clicks the edit button.
|
* This method is used by the contact details component to open the edit contact dialog when the user clicks the edit button.
|
||||||
*/
|
*/
|
||||||
openEditDialog() {
|
editContact(userData: User) {
|
||||||
this.sharedService.isAnyDialogOpen = true;
|
this.overlayService.setOverlayData('contactOverlay', userData);
|
||||||
this.sharedService.isEditContactDialogOpen = true;
|
this.isMobileNavbarOpen = false;
|
||||||
this.sharedService.isMobileNavbarOpen = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens the delete contact dialog by setting the appropriate flags in the shared service.
|
* Opens the delete contact dialog by setting the appropriate flags in the shared service.
|
||||||
* This method is used by the contact details component to open the delete contact dialog when the user clicks the delete button.
|
* This method is used by the contact details component to open the delete contact dialog when the user clicks the delete button.
|
||||||
*/
|
*/
|
||||||
deleteContact() {
|
openDeleteContactDialog() {
|
||||||
this.sharedService.isAnyDialogOpen = true;
|
// TODO
|
||||||
this.sharedService.isDeleteContactDialogOpen = true;
|
this.isMobileNavbarOpen = false;
|
||||||
this.sharedService.isMobileNavbarOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@HostListener('document:click', ['$event'])
|
|
||||||
/**
|
|
||||||
* Handles the opening of the contact edit, new contact, and delete contact
|
|
||||||
* dialogs when the respective buttons are clicked.
|
|
||||||
*
|
|
||||||
* @param event The MouseEvent that was triggered.
|
|
||||||
*/
|
|
||||||
checkOpenContactEdit(event: MouseEvent) {
|
|
||||||
const targetElement = event.target as HTMLElement;
|
|
||||||
|
|
||||||
if (targetElement.closest('.btn-edit')) {
|
|
||||||
this.setDialogStatus(true, true, false, false);
|
|
||||||
} else if (targetElement.closest('.btn-new')) {
|
|
||||||
this.setDialogStatus(true, false, true, false);
|
|
||||||
} else if (targetElement.closest('.btn-delete')) {
|
|
||||||
this.setDialogStatus(true, false, false, true);
|
|
||||||
} else if (!targetElement.closest('.dialog')) {
|
|
||||||
this.setDialogStatus(false, false, false, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the dialog status flags in the shared service.
|
|
||||||
*
|
|
||||||
* @param anyOpen - Indicates if any dialog is open.
|
|
||||||
* @param editOpen - Indicates if the edit contact dialog is open.
|
|
||||||
* @param newOpen - Indicates if the new contact dialog is open.
|
|
||||||
* @param deleteOpen - Indicates if the delete contact dialog is open.
|
|
||||||
*/
|
|
||||||
private setDialogStatus(
|
|
||||||
anyOpen: boolean,
|
|
||||||
editOpen: boolean,
|
|
||||||
newOpen: boolean,
|
|
||||||
deleteOpen: boolean
|
|
||||||
) {
|
|
||||||
this.sharedService.isAnyDialogOpen = anyOpen;
|
|
||||||
this.sharedService.isEditContactDialogOpen = editOpen;
|
|
||||||
this.sharedService.isNewContactDialogOpen = newOpen;
|
|
||||||
this.sharedService.isDeleteContactDialogOpen = deleteOpen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<nav class="navbar">
|
|
||||||
<div class="link btn-edit">
|
|
||||||
<span (click)="openEditDialog()">{{
|
|
||||||
"contacts.btnEdit1" | translate
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="link btn-delete">
|
|
||||||
<span (click)="deleteContact()">{{
|
|
||||||
"contacts.btnDelete1" | translate
|
|
||||||
}}</span>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
.navbar {
|
|
||||||
position: fixed;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
bottom: 146px;
|
|
||||||
right: 80px;
|
|
||||||
width: 110px;
|
|
||||||
height: 108px;
|
|
||||||
background-color: var(--bgSidebar);
|
|
||||||
border-radius: 20px 20px 0 20px;
|
|
||||||
box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.1);
|
|
||||||
padding: 10px;
|
|
||||||
z-index: 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
.link {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
height: 46px;
|
|
||||||
padding: 8px 16px;
|
|
||||||
border-radius: 8px;
|
|
||||||
color: var(--white);
|
|
||||||
cursor: pointer;
|
|
||||||
span {
|
|
||||||
text-align: center;
|
|
||||||
width: 118px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
overflow-wrap: break-word;
|
|
||||||
white-space: normal;
|
|
||||||
}
|
|
||||||
&:hover {
|
|
||||||
background-color: var(--very-dark-blue);
|
|
||||||
span {
|
|
||||||
color: var(--light-blue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ContactNavComponent } from './contact-nav.component';
|
|
||||||
|
|
||||||
describe('ContactNavComponent', () => {
|
|
||||||
let component: ContactNavComponent;
|
|
||||||
let fixture: ComponentFixture<ContactNavComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TestBed.configureTestingModule({
|
|
||||||
imports: [ContactNavComponent]
|
|
||||||
})
|
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ContactNavComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import { Component, Input } from '@angular/core';
|
|
||||||
import { SharedService } from '../../../services/shared.service';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-contact-nav',
|
|
||||||
standalone: true,
|
|
||||||
imports: [TranslateModule],
|
|
||||||
templateUrl: './contact-nav.component.html',
|
|
||||||
styleUrl: './contact-nav.component.scss',
|
|
||||||
})
|
|
||||||
export class ContactNavComponent {
|
|
||||||
@Input() deleteContact!: () => any;
|
|
||||||
@Input() openEditDialog!: () => any;
|
|
||||||
|
|
||||||
constructor(public sharedService: SharedService) {}
|
|
||||||
}
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
'd-none': !showAllUsers && selectedUserId != null
|
'd-none': !showAllUsers && selectedUserId != null
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<button class="btn-new" type="submit" (click)="openNewContactDialog()">
|
<button class="btn-new" type="submit" (click)="addNewContact()">
|
||||||
<div class="btn-inside">
|
<div class="btn-inside">
|
||||||
<span>{{ "contacts.btnNew" | translate }}</span>
|
<span>{{ "contacts.btnNew" | translate }}</span>
|
||||||
<img src="./../../../assets/img/contact/add.svg" alt="check" />
|
<img src="./../../../assets/img/contact/add.svg" alt="check" />
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,12 @@
|
||||||
import { Component, HostListener } from '@angular/core';
|
import { Component, HostListener } from '@angular/core';
|
||||||
import { User } from '../../interfaces/user.interface';
|
import { User } from '../../interfaces/user.interface';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
|
||||||
import { ContactDetailComponent } from './contact-detail/contact-detail.component';
|
import { ContactDetailComponent } from './contact-detail/contact-detail.component';
|
||||||
import { SharedService } from '../../services/shared.service';
|
|
||||||
import { FirebaseService } from '../../services/firebase.service';
|
import { FirebaseService } from '../../services/firebase.service';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { ApiService } from '../../services/api.service';
|
|
||||||
import { UserService } from '../../services/user.service';
|
import { UserService } from '../../services/user.service';
|
||||||
import { finalize } from 'rxjs';
|
import { finalize } from 'rxjs';
|
||||||
|
import { OverlayService } from '../../services/overlay.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contacts',
|
selector: 'app-contacts',
|
||||||
|
|
@ -27,7 +25,7 @@ export class ContactsComponent {
|
||||||
constructor(
|
constructor(
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
public sharedService: SharedService
|
private overlayService: OverlayService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -95,15 +93,8 @@ export class ContactsComponent {
|
||||||
return uniqueFirstLetters;
|
return uniqueFirstLetters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
addNewContact() {
|
||||||
* Opens the new contact dialog.
|
this.overlayService.setOverlayData('contactOverlay', 'new');
|
||||||
* This function sets the isAnyDialogOpen and isNewContactDialogOpen
|
|
||||||
* properties of the shared service to true, which will open the new contact
|
|
||||||
* dialog.
|
|
||||||
*/
|
|
||||||
openNewContactDialog() {
|
|
||||||
this.sharedService.isAnyDialogOpen = true;
|
|
||||||
this.sharedService.isNewContactDialogOpen = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@HostListener('window:resize', ['$event'])
|
@HostListener('window:resize', ['$event'])
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@
|
||||||
[disabled]="
|
[disabled]="
|
||||||
mail.invalid ||
|
mail.invalid ||
|
||||||
!pwResetData.mail ||
|
!pwResetData.mail ||
|
||||||
sharedService.isBtnDisabled ||
|
isButtonDisabled() ||
|
||||||
!checkIfUserEmailIsValid(pwResetData.mail)
|
!checkIfUserEmailIsValid(pwResetData.mail)
|
||||||
"
|
"
|
||||||
></app-form-btn>
|
></app-form-btn>
|
||||||
|
|
|
||||||
|
|
@ -6,8 +6,8 @@ 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';
|
||||||
import { LoginService } from '../../../services/login.service';
|
import { LoginService } from '../../../services/login.service';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
|
||||||
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
import { BtnBackComponent } from '../../../shared/components/buttons/btn-back/btn-back.component';
|
||||||
|
import { ButtonStateService } from '../../../services/button-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-forgot-pw',
|
selector: 'app-forgot-pw',
|
||||||
|
|
@ -31,16 +31,20 @@ export class ForgotPwComponent {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public loginService: LoginService,
|
public loginService: LoginService,
|
||||||
public sharedService: SharedService
|
private buttonStateService: ButtonStateService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
onSubmit(ngForm: NgForm) {
|
onSubmit(ngForm: NgForm) {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.buttonStateService.enableButton();
|
||||||
if (ngForm.submitted && ngForm.form.valid) {
|
if (ngForm.submitted && ngForm.form.valid) {
|
||||||
this.loginService.passwordReset(this.pwResetData.mail.toLowerCase());
|
this.loginService.passwordReset(this.pwResetData.mail.toLowerCase());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isButtonDisabled() {
|
||||||
|
return this.buttonStateService.isButtonDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
checkIfUserEmailIsValid(emailValue: string) {
|
checkIfUserEmailIsValid(emailValue: string) {
|
||||||
const emailRegex = /^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,}$/;
|
const emailRegex = /^[\w.%+-]+@[\w.-]+\.[a-zA-Z]{2,}$/;
|
||||||
if (emailRegex.test(emailValue)) {
|
if (emailRegex.test(emailValue)) {
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@
|
||||||
!pwResetData.password ||
|
!pwResetData.password ||
|
||||||
passwordConfirm.invalid ||
|
passwordConfirm.invalid ||
|
||||||
!pwResetData.passwordConfirm ||
|
!pwResetData.passwordConfirm ||
|
||||||
sharedService.isBtnDisabled ||
|
isButtonDisabled() ||
|
||||||
pwResetData.password.length < 6 ||
|
pwResetData.password.length < 6 ||
|
||||||
pwResetData.password !== pwResetData.passwordConfirm
|
pwResetData.password !== pwResetData.passwordConfirm
|
||||||
"
|
"
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,10 @@ import { FormBtnComponent } from '../../../../shared/components/buttons/form-btn
|
||||||
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';
|
||||||
import { FirebaseService } from '../../../../services/firebase.service';
|
|
||||||
import { LoginService } from '../../../../services/login.service';
|
import { LoginService } from '../../../../services/login.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { SharedService } from '../../../../services/shared.service';
|
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
import { ButtonStateService } from '../../../../services/button-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pw-reset',
|
selector: 'app-pw-reset',
|
||||||
|
|
@ -35,11 +34,9 @@ export class PwResetComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private firebaseService: FirebaseService,
|
|
||||||
public loginService: LoginService,
|
public loginService: LoginService,
|
||||||
public sharedService: SharedService,
|
private buttonStateService: ButtonStateService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute
|
||||||
private router: Router
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
|
@ -50,8 +47,12 @@ export class PwResetComponent {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isButtonDisabled() {
|
||||||
|
return this.buttonStateService.isButtonDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
onSubmit(ngForm: NgForm) {
|
onSubmit(ngForm: NgForm) {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.buttonStateService.enableButton();
|
||||||
if (ngForm.submitted && ngForm.form.valid) {
|
if (ngForm.submitted && ngForm.form.valid) {
|
||||||
this.loginService.newPassword(this.pwResetData.password, this.oobCode);
|
this.loginService.newPassword(this.pwResetData.password, this.oobCode);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
@if (sharedService.isBtnDisabled) {
|
@if (isButtonDisabled()) {
|
||||||
<div class="loading-dialog">
|
<div class="loading-dialog">
|
||||||
<div id="loading" class="loader"></div>
|
<div id="loading" class="loader"></div>
|
||||||
<div id="loadingText" class="loading-text">
|
<div id="loadingText" class="loading-text">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { ButtonStateService } from '../../../services/button-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-loading-dialog',
|
selector: 'app-loading-dialog',
|
||||||
|
|
@ -10,5 +10,9 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
styleUrl: './loading-dialog.component.scss',
|
styleUrl: './loading-dialog.component.scss',
|
||||||
})
|
})
|
||||||
export class LoadingDialogComponent {
|
export class LoadingDialogComponent {
|
||||||
constructor(public sharedService: SharedService) {}
|
constructor(private buttonStateService: ButtonStateService) {}
|
||||||
|
|
||||||
|
isButtonDisabled() {
|
||||||
|
return this.buttonStateService.isButtonDisabled;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,14 +33,14 @@
|
||||||
<img class="custom-img" alt="" />
|
<img class="custom-img" alt="" />
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (!mail.valid && mail.touched && !sharedService.isBtnDisabled) {
|
@if (!mail.valid && mail.touched && !isButtonDisabled()) {
|
||||||
<p>{{ "login.errorMail0" | translate }}</p>
|
<p>{{ "login.errorMail0" | translate }}</p>
|
||||||
} @if (loginService.errorCode == 'auth/invalid-email' &&
|
} @if (loginService.errorCode == 'auth/invalid-email' &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "login.errorMail1" | translate }}</p>
|
<p>{{ "login.errorMail1" | translate }}</p>
|
||||||
} @if (mail.valid && mail.touched &&
|
} @if (mail.valid && mail.touched &&
|
||||||
!checkIfUserEmailIsValid(loginData.email.toLowerCase()) &&
|
!checkIfUserEmailIsValid(loginData.email.toLowerCase()) &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "login.errorMail2" | translate }}</p>
|
<p>{{ "login.errorMail2" | translate }}</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -73,11 +73,10 @@
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (!password.valid && password.touched &&
|
@if (!password.valid && password.touched && !isButtonDisabled()) {
|
||||||
!sharedService.isBtnDisabled) {
|
|
||||||
<p>{{ "login.errorPassword0" | translate }}</p>
|
<p>{{ "login.errorPassword0" | translate }}</p>
|
||||||
} @if (loginService.errorCode == 'auth/invalid-credential' &&
|
} @if (loginService.errorCode == 'auth/invalid-credential' &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "login.errorPassword1" | translate }}</p>
|
<p>{{ "login.errorPassword1" | translate }}</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -120,7 +119,7 @@
|
||||||
!loginData.email ||
|
!loginData.email ||
|
||||||
password.invalid ||
|
password.invalid ||
|
||||||
!loginData.password ||
|
!loginData.password ||
|
||||||
sharedService.isBtnDisabled ||
|
isButtonDisabled() ||
|
||||||
!checkIfUserEmailIsValid(loginData.email)
|
!checkIfUserEmailIsValid(loginData.email)
|
||||||
"
|
"
|
||||||
></app-form-btn>
|
></app-form-btn>
|
||||||
|
|
@ -128,7 +127,7 @@
|
||||||
[class]="'btn-guest-login'"
|
[class]="'btn-guest-login'"
|
||||||
[type]="'button'"
|
[type]="'button'"
|
||||||
[value]="'login.guest' | translate"
|
[value]="'login.guest' | translate"
|
||||||
[disabled]="sharedService.isBtnDisabled"
|
[disabled]="isButtonDisabled()"
|
||||||
(click)="guestLogin()"
|
(click)="guestLogin()"
|
||||||
></app-form-btn>
|
></app-form-btn>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,8 @@ import { CommonModule } from '@angular/common';
|
||||||
import { Component } from '@angular/core';
|
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 { FirebaseService } from '../../services/firebase.service';
|
|
||||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||||
import { LoginService } from '../../services/login.service';
|
import { LoginService } from '../../services/login.service';
|
||||||
import { SharedService } from '../../services/shared.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';
|
||||||
|
|
@ -13,6 +11,7 @@ import { LoadingDialogComponent } from './loading-dialog/loading-dialog.componen
|
||||||
import { OverlayService } from '../../services/overlay.service';
|
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';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
|
|
@ -43,8 +42,8 @@ export class LoginComponent {
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
public loginService: LoginService,
|
public loginService: LoginService,
|
||||||
private tokenService: TokenService,
|
private tokenService: TokenService,
|
||||||
public sharedService: SharedService,
|
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
|
private buttonStateService: ButtonStateService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
@ -65,26 +64,30 @@ export class LoginComponent {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isButtonDisabled() {
|
||||||
|
return this.buttonStateService.isButtonDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
deleteTokens() {
|
deleteTokens() {
|
||||||
this.tokenService.deleteAuthToken();
|
this.tokenService.deleteAuthToken();
|
||||||
this.tokenService.deleteUserId();
|
this.tokenService.deleteUserId();
|
||||||
}
|
}
|
||||||
|
|
||||||
async onSubmit(ngForm: NgForm) {
|
async onSubmit(ngForm: NgForm) {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.buttonStateService.enableButton();
|
||||||
if (ngForm.submitted && ngForm.form.valid) {
|
if (ngForm.submitted && ngForm.form.valid) {
|
||||||
try {
|
try {
|
||||||
await this.authService.login(this.loginData, this.checkboxRememberMe);
|
await this.authService.login(this.loginData, this.checkboxRememberMe);
|
||||||
this.router.navigate(['/summary']);
|
this.router.navigate(['/summary']);
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
guestLogin() {
|
guestLogin() {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.buttonStateService.enableButton();
|
||||||
this.loginData.email = 'guest@guestaccount.com';
|
this.loginData.email = 'guest@guestaccount.com';
|
||||||
this.loginData.password = 'guest@guestaccount.com';
|
this.loginData.password = 'guest@guestaccount.com';
|
||||||
this.isPasswordIconVisible = !this.isPasswordIconVisible;
|
this.isPasswordIconVisible = !this.isPasswordIconVisible;
|
||||||
|
|
|
||||||
|
|
@ -39,11 +39,10 @@
|
||||||
<img class="custom-img" alt="" />
|
<img class="custom-img" alt="" />
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (name.hasError('pattern') && name.touched &&
|
@if (name.hasError('pattern') && name.touched && !isButtonDisabled())
|
||||||
!sharedService.isBtnDisabled) {
|
{
|
||||||
<p>{{ "register.errorPattern" | translate }}</p>
|
<p>{{ "register.errorPattern" | translate }}</p>
|
||||||
} @else { @if (!name.valid && name.touched &&
|
} @else { @if (!name.valid && name.touched && !isButtonDisabled()) {
|
||||||
!sharedService.isBtnDisabled) {
|
|
||||||
<p>{{ "register.errorName" | translate }}</p>
|
<p>{{ "register.errorName" | translate }}</p>
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -70,15 +69,15 @@
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if(!mail.valid && mail.touched &&
|
@if(!mail.valid && mail.touched &&
|
||||||
!checkIfUserEmailIsValid(registerData.mail.toLowerCase()) &&
|
!checkIfUserEmailIsValid(registerData.mail.toLowerCase()) &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "register.errorMail0" | translate }}</p>
|
<p>{{ "register.errorMail0" | translate }}</p>
|
||||||
} @else { @if (mail.touched &&
|
} @else { @if (mail.touched &&
|
||||||
!checkIfUserEmailIsValid(registerData.mail.toLowerCase()) &&
|
!checkIfUserEmailIsValid(registerData.mail.toLowerCase()) &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "register.errorMail1" | translate }}</p>
|
<p>{{ "register.errorMail1" | translate }}</p>
|
||||||
} @else { @if
|
} @else { @if
|
||||||
(existEmailOnServer(registerData.mail.toLowerCase()).length > 0 &&
|
(existEmailOnServer(registerData.mail.toLowerCase()).length > 0 &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "register.errorMail2" | translate }}</p>
|
<p>{{ "register.errorMail2" | translate }}</p>
|
||||||
} } }
|
} } }
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -109,11 +108,10 @@
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (!password.valid && password.touched &&
|
@if (!password.valid && password.touched && !isButtonDisabled()) {
|
||||||
!sharedService.isBtnDisabled) {
|
|
||||||
<p>{{ "register.errorPassword0" | translate }}</p>
|
<p>{{ "register.errorPassword0" | translate }}</p>
|
||||||
} @else { @if (registerData.password.length < 6 && password.touched &&
|
} @else { @if (registerData.password.length < 6 && password.touched &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "register.errorPassword1" | translate }}</p>
|
<p>{{ "register.errorPassword1" | translate }}</p>
|
||||||
} }
|
} }
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -145,11 +143,11 @@
|
||||||
}
|
}
|
||||||
<div class="error-msg">
|
<div class="error-msg">
|
||||||
@if (!passwordConfirm.valid && passwordConfirm.touched &&
|
@if (!passwordConfirm.valid && passwordConfirm.touched &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "register.errorPassword0" | translate }}</p>
|
<p>{{ "register.errorPassword0" | translate }}</p>
|
||||||
} @if (registerData.password !== registerData.passwordConfirm &&
|
} @if (registerData.password !== registerData.passwordConfirm &&
|
||||||
registerData.password !== "" && registerData.passwordConfirm !== "" &&
|
registerData.password !== "" && registerData.passwordConfirm !== "" &&
|
||||||
!sharedService.isBtnDisabled) {
|
!isButtonDisabled()) {
|
||||||
<p>{{ "register.errorPassword2" | translate }}</p>
|
<p>{{ "register.errorPassword2" | translate }}</p>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -188,7 +186,7 @@
|
||||||
password.invalid ||
|
password.invalid ||
|
||||||
!registerData.password ||
|
!registerData.password ||
|
||||||
!checkbox.valid ||
|
!checkbox.valid ||
|
||||||
sharedService.isBtnDisabled ||
|
isButtonDisabled() ||
|
||||||
registerData.password.length < 6 ||
|
registerData.password.length < 6 ||
|
||||||
registerData.password !== registerData.passwordConfirm ||
|
registerData.password !== registerData.passwordConfirm ||
|
||||||
!checkIfUserEmailIsValid(registerData.mail)
|
!checkIfUserEmailIsValid(registerData.mail)
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,11 @@ 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 { FirebaseService } from '../../../services/firebase.service';
|
import { FirebaseService } from '../../../services/firebase.service';
|
||||||
import { LoginService } from '../../../services/login.service';
|
import { LoginService } from '../../../services/login.service';
|
||||||
import { SharedService } from '../../../services/shared.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';
|
||||||
import { LoadingDialogComponent } from '../loading-dialog/loading-dialog.component';
|
import { LoadingDialogComponent } from '../loading-dialog/loading-dialog.component';
|
||||||
|
import { ButtonStateService } from '../../../services/button-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-register',
|
selector: 'app-register',
|
||||||
|
|
@ -43,18 +43,22 @@ export class RegisterComponent {
|
||||||
constructor(
|
constructor(
|
||||||
private firebaseService: FirebaseService,
|
private firebaseService: FirebaseService,
|
||||||
public loginService: LoginService,
|
public loginService: LoginService,
|
||||||
public sharedService: SharedService,
|
public translateService: TranslateService,
|
||||||
public translateService: TranslateService
|
private buttonStateService: ButtonStateService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
onSubmit(ngForm: NgForm) {
|
onSubmit(ngForm: NgForm) {
|
||||||
this.sharedService.isBtnDisabled = true;
|
this.buttonStateService.enableButton();
|
||||||
if (ngForm.submitted && ngForm.form.valid) {
|
if (ngForm.submitted && ngForm.form.valid) {
|
||||||
this.splitName();
|
this.splitName();
|
||||||
this.loginService.register(this.registerData);
|
this.loginService.register(this.registerData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isButtonDisabled() {
|
||||||
|
return this.buttonStateService.isButtonDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
splitName() {
|
splitName() {
|
||||||
const names = this.registerData.name.split(' ');
|
const names = this.registerData.name.split(' ');
|
||||||
this.registerData.firstName = names[0];
|
this.registerData.firstName = names[0];
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,4 @@
|
||||||
<div
|
<div>
|
||||||
[ngClass]="{
|
|
||||||
'blur-background': sharedService.isAnyDialogOpen
|
|
||||||
}"
|
|
||||||
>
|
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<app-sidebar></app-sidebar>
|
<app-sidebar></app-sidebar>
|
||||||
<app-header></app-header>
|
<app-header></app-header>
|
||||||
|
|
@ -12,23 +8,4 @@
|
||||||
</div>
|
</div>
|
||||||
<app-sidebar-mobile></app-sidebar-mobile>
|
<app-sidebar-mobile></app-sidebar-mobile>
|
||||||
</div>
|
</div>
|
||||||
@if (sharedService.isNewContactDialogOpen) {
|
<app-overlay></app-overlay>
|
||||||
<app-contact-edit
|
|
||||||
[ngClass]="{
|
|
||||||
'blur-background': sharedService.isDeleteContactDialogOpen,
|
|
||||||
'd-none': sharedService.isDeleteContactDialogOpen
|
|
||||||
}"
|
|
||||||
></app-contact-edit>
|
|
||||||
} @if (sharedService.isEditContactDialogOpen) {
|
|
||||||
<app-contact-edit
|
|
||||||
[currentUserId]="sharedService.currentUserId"
|
|
||||||
[ngClass]="{
|
|
||||||
'blur-background': sharedService.isDeleteContactDialogOpen,
|
|
||||||
'd-none': sharedService.isDeleteContactDialogOpen
|
|
||||||
}"
|
|
||||||
></app-contact-edit>
|
|
||||||
} @if (sharedService.isDeleteContactDialogOpen) {
|
|
||||||
<app-contact-delete
|
|
||||||
[currentUserId]="sharedService.currentUserId"
|
|
||||||
></app-contact-delete>
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,14 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { NavigationEnd, Router, RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { filter } from 'rxjs';
|
|
||||||
import { FirebaseService } from '../../services/firebase.service';
|
|
||||||
import { LanguageService } from '../../services/language.service';
|
import { LanguageService } from '../../services/language.service';
|
||||||
import { SharedService } from '../../services/shared.service';
|
|
||||||
import { SidebarMobileComponent } from '../../shared/components/sidebar/sidebar-mobile/sidebar-mobile.component';
|
import { SidebarMobileComponent } from '../../shared/components/sidebar/sidebar-mobile/sidebar-mobile.component';
|
||||||
import { SidebarComponent } from '../../shared/components/sidebar/sidebar.component';
|
import { SidebarComponent } from '../../shared/components/sidebar/sidebar.component';
|
||||||
import { ContactDeleteComponent } from '../contacts/contact-delete/contact-delete.component';
|
|
||||||
import { ContactEditNewComponent } from '../contacts/contact-edit-new/contact-edit-new.component';
|
|
||||||
import { HeaderComponent } from '../../shared/components/header/header.component';
|
import { HeaderComponent } from '../../shared/components/header/header.component';
|
||||||
|
import { UserService } from '../../services/user.service';
|
||||||
|
import { User } from '../../interfaces/user.interface';
|
||||||
|
import { OverlayComponent } from '../../shared/components/overlay/overlay.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-main-layout',
|
selector: 'app-main-layout',
|
||||||
|
|
@ -19,83 +18,27 @@ import { HeaderComponent } from '../../shared/components/header/header.component
|
||||||
HeaderComponent,
|
HeaderComponent,
|
||||||
SidebarComponent,
|
SidebarComponent,
|
||||||
SidebarMobileComponent,
|
SidebarMobileComponent,
|
||||||
ContactEditNewComponent,
|
|
||||||
ContactDeleteComponent,
|
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
OverlayComponent,
|
||||||
],
|
],
|
||||||
templateUrl: './main-layout.component.html',
|
templateUrl: './main-layout.component.html',
|
||||||
styleUrl: './main-layout.component.scss',
|
styleUrl: './main-layout.component.scss',
|
||||||
})
|
})
|
||||||
export class MainLayoutComponent {
|
export class MainLayoutComponent {
|
||||||
isLoggedIn: string = '';
|
currentUser: User | null = null;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public langService: LanguageService,
|
public langService: LanguageService,
|
||||||
public sharedService: SharedService,
|
private userService: UserService
|
||||||
private firebaseService: FirebaseService,
|
) {}
|
||||||
private router: Router
|
|
||||||
) {
|
ngOnInit(): void {
|
||||||
this.checkAndClearLocalStorage();
|
this.loadCurrentUser();
|
||||||
this.isLoggedIn = this.firebaseService.getCurrentUserId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
loadCurrentUser(): void {
|
||||||
* Lifecycle hook that is called after the component has been initialized.
|
this.userService.getCurrentUser().subscribe((userData) => {
|
||||||
*
|
this.currentUser = userData;
|
||||||
* Checks if the user is logged in by verifying the `isLoggedIn` property.
|
|
||||||
*/
|
|
||||||
ngOnInit() {
|
|
||||||
if (this.isLoggedIn === null) {
|
|
||||||
this.checkPwResetRoute();
|
|
||||||
} else {
|
|
||||||
this.router.navigate(['/summary']);
|
|
||||||
this.sharedService.isBtnDisabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clears the local storage after a certain time period (12h) has
|
|
||||||
* passed since the last login.
|
|
||||||
*/
|
|
||||||
checkAndClearLocalStorage() {
|
|
||||||
const startTime = localStorage.getItem('sessionTimeJOIN');
|
|
||||||
|
|
||||||
if (startTime) {
|
|
||||||
const startTimeMills = parseInt(startTime);
|
|
||||||
const currentTime = new Date().getTime();
|
|
||||||
const timeDifference = 12 * 60 * 60 * 1000; // 12h
|
|
||||||
if (currentTime - startTimeMills > timeDifference) {
|
|
||||||
localStorage.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Listens to router events and checks if the current route is one of the
|
|
||||||
* allowed routes for password reset, registration, forgotten password,
|
|
||||||
* or login. If it is not, it navigates to the login page.
|
|
||||||
*/
|
|
||||||
checkPwResetRoute() {
|
|
||||||
this.router.events
|
|
||||||
.pipe(filter((event) => event instanceof NavigationEnd))
|
|
||||||
.subscribe(() => {
|
|
||||||
const urlTree = this.router.parseUrl(this.router.url);
|
|
||||||
const firstSegment = this.getFirstSegment(urlTree);
|
|
||||||
const allowedRoutes = ['pw-reset', 'register', 'forgot-pw', 'login'];
|
|
||||||
|
|
||||||
if (!allowedRoutes.includes(firstSegment)) {
|
|
||||||
this.router.navigate(['/login']);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the first segment of the current URL or an empty string if it does not exist.
|
|
||||||
*
|
|
||||||
* @param urlTree The current URL tree.
|
|
||||||
* @returns The first segment of the current URL or an empty string if it does not exist.
|
|
||||||
*/
|
|
||||||
private getFirstSegment(urlTree: any): string {
|
|
||||||
return urlTree.root.children['primary']?.segments[0]?.path || '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
16
src/app/services/button-state.service.ts
Normal file
16
src/app/services/button-state.service.ts
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class ButtonStateService {
|
||||||
|
isButtonDisabled: boolean = false;
|
||||||
|
|
||||||
|
disableButton() {
|
||||||
|
this.isButtonDisabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
enableButton() {
|
||||||
|
this.isButtonDisabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,34 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class ColorService {
|
|
||||||
generateRandomColor(): string {
|
|
||||||
const letters = '0123456789ABCDEF';
|
|
||||||
let color = '#';
|
|
||||||
let isGrayScale = true;
|
|
||||||
|
|
||||||
while (isGrayScale) {
|
|
||||||
for (let i = 0; i < 6; i++) {
|
|
||||||
color += letters[Math.floor(Math.random() * 16)];
|
|
||||||
}
|
|
||||||
const rgb = this.hexToRgb(color);
|
|
||||||
if (rgb.r !== rgb.g || rgb.g !== rgb.b) {
|
|
||||||
isGrayScale = false;
|
|
||||||
} else {
|
|
||||||
color = '#';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return color;
|
|
||||||
}
|
|
||||||
|
|
||||||
hexToRgb(hex: string): { r: number; g: number; b: number } {
|
|
||||||
const bigint = parseInt(hex.substring(1), 16);
|
|
||||||
const r = (bigint >> 16) & 255;
|
|
||||||
const g = (bigint >> 8) & 255;
|
|
||||||
const b = bigint & 255;
|
|
||||||
return { r, g, b };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -19,13 +19,12 @@ import {
|
||||||
updateDoc,
|
updateDoc,
|
||||||
where,
|
where,
|
||||||
} from '@angular/fire/firestore';
|
} from '@angular/fire/firestore';
|
||||||
import { SharedService } from './shared.service';
|
|
||||||
import { User } from '../interfaces/user.interface';
|
import { User } from '../interfaces/user.interface';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import CryptoES from 'crypto-es';
|
import CryptoES from 'crypto-es';
|
||||||
import { CryptoESSecretKey } from '../environments/config';
|
import { CryptoESSecretKey } from '../environments/config';
|
||||||
import { catchError, map, Observable, of } from 'rxjs';
|
import { catchError, map, Observable, of } from 'rxjs';
|
||||||
import { ColorService } from './color.service';
|
import { ButtonStateService } from './button-state.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
|
@ -40,8 +39,7 @@ export class LoginService {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private firebaseService: FirebaseService,
|
private firebaseService: FirebaseService,
|
||||||
private colorService: ColorService,
|
private buttonStateService: ButtonStateService,
|
||||||
public sharedService: SharedService,
|
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
|
|
@ -83,7 +81,7 @@ export class LoginService {
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.errorCode = error.code;
|
this.errorCode = error.code;
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -126,13 +124,13 @@ export class LoginService {
|
||||||
? registerData.firstName.slice(0, 1).toUpperCase() +
|
? registerData.firstName.slice(0, 1).toUpperCase() +
|
||||||
registerData.lastName.slice(0, 1).toUpperCase()
|
registerData.lastName.slice(0, 1).toUpperCase()
|
||||||
: '',
|
: '',
|
||||||
color: this.colorService.generateRandomColor(),
|
color: '',
|
||||||
lastLogin: new Date().getTime(),
|
lastLogin: new Date().getTime(),
|
||||||
};
|
};
|
||||||
this.createUserInFirestore(userDataToSave);
|
this.createUserInFirestore(userDataToSave);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,7 +169,7 @@ export class LoginService {
|
||||||
isOnline: true,
|
isOnline: true,
|
||||||
phone: '',
|
phone: '',
|
||||||
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
initials: firstName.slice(0, 1) + lastName.slice(0, 1),
|
||||||
color: this.colorService.generateRandomColor(),
|
color: '',
|
||||||
lastLogin: 0,
|
lastLogin: 0,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -180,7 +178,7 @@ export class LoginService {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -333,10 +331,10 @@ export class LoginService {
|
||||||
sendPasswordResetEmail(auth, email, actionCodeSettings)
|
sendPasswordResetEmail(auth, email, actionCodeSettings)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.router.navigate(['/login/notice/pw-send']);
|
this.router.navigate(['/login/notice/pw-send']);
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,10 +355,10 @@ export class LoginService {
|
||||||
confirmPasswordReset(auth, oobCode, newPW)
|
confirmPasswordReset(auth, oobCode, newPW)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.router.navigate(['/login/notice/pw-change']);
|
this.router.navigate(['/login/notice/pw-change']);
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.sharedService.isBtnDisabled = false;
|
this.buttonStateService.disableButton();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class SharedService {
|
|
||||||
isBtnDisabled: boolean = false;
|
|
||||||
isAnyDialogOpen: boolean = false;
|
|
||||||
isMobileNavbarOpen: boolean = false;
|
|
||||||
isNewContactDialogOpen: boolean = false;
|
|
||||||
isEditContactDialogOpen: boolean = false;
|
|
||||||
isDeleteContactDialogOpen: boolean = false;
|
|
||||||
currentUserId: string = '';
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
<div class="btn" (click)="closeClicked()">
|
<div class="btn">
|
||||||
<img src="./../../../../assets/img/close.svg" />
|
<img src="./../../../../assets/img/close.svg" />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { SharedService } from '../../../../services/shared.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-btn-close',
|
selector: 'app-btn-close',
|
||||||
|
|
@ -9,19 +8,5 @@ import { SharedService } from '../../../../services/shared.service';
|
||||||
styleUrl: './btn-close.component.scss',
|
styleUrl: './btn-close.component.scss',
|
||||||
})
|
})
|
||||||
export class BtnCloseComponent {
|
export class BtnCloseComponent {
|
||||||
@Input() isContactDialogOpen: boolean = false;
|
constructor() {}
|
||||||
|
|
||||||
constructor(private sharedService: SharedService) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the close button is clicked.
|
|
||||||
* Sets isAnyDialogOpen to false and sets
|
|
||||||
* isEditContactDialogOpen and isNewContactDialogOpen
|
|
||||||
* to the value of isContactDialogOpen.
|
|
||||||
*/
|
|
||||||
closeClicked() {
|
|
||||||
this.sharedService.isAnyDialogOpen = false;
|
|
||||||
this.sharedService.isEditContactDialogOpen = this.isContactDialogOpen;
|
|
||||||
this.sharedService.isNewContactDialogOpen = this.isContactDialogOpen;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,13 +121,12 @@
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
@if (currentUserId && currentUserId !==
|
@if (selectedUser && selectedUser !== firebaseService.getCurrentUserId()){
|
||||||
firebaseService.getCurrentUserId()){
|
|
||||||
<app-form-btn
|
<app-form-btn
|
||||||
class="btn-delete"
|
class="btn-delete"
|
||||||
type="button"
|
type="button"
|
||||||
value="{{ 'contactDialogForm.btnDelete' | translate }}"
|
value="{{ 'contactDialogForm.btnDelete' | translate }}"
|
||||||
(click)="deleteContact()"
|
(click)="closeDialog()"
|
||||||
></app-form-btn>
|
></app-form-btn>
|
||||||
} @else {
|
} @else {
|
||||||
<app-form-btn
|
<app-form-btn
|
||||||
|
|
@ -9,12 +9,10 @@ import {
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { FormsModule, NgForm } from '@angular/forms';
|
import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { SharedService } from '../../../../services/shared.service';
|
import { FormBtnComponent } from '../../../buttons/form-btn/form-btn.component';
|
||||||
import { FirebaseService } from '../../../../services/firebase.service';
|
import { User } from '@sentry/angular';
|
||||||
import { FormBtnComponent } from '../../../../shared/components/buttons/form-btn/form-btn.component';
|
import { FirebaseService } from '../../../../../services/firebase.service';
|
||||||
import { User } from '../../../../interfaces/user.interface';
|
import { ResizeService } from '../../../../../services/resize.service';
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { ResizeService } from '../../../../services/resize.service';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact-form',
|
selector: 'app-contact-form',
|
||||||
|
|
@ -24,20 +22,17 @@ import { ResizeService } from '../../../../services/resize.service';
|
||||||
styleUrl: './contact-form.component.scss',
|
styleUrl: './contact-form.component.scss',
|
||||||
})
|
})
|
||||||
export class ContactFormComponent implements OnInit, OnChanges {
|
export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
@Input() currentUserId: string = '';
|
@Input() selectedUser: any = [];
|
||||||
@Input() randomColor: string = '';
|
@Input() randomColor: string = '';
|
||||||
@Input() newColor: string = '';
|
@Input() newColor: string = '';
|
||||||
@Input() currentColor: string = '';
|
@Input() currentColor: string = '';
|
||||||
@Output() initialsEmitter = new EventEmitter<string>();
|
@Output() initialsEmitter = new EventEmitter<string>();
|
||||||
|
@Output() closeDialogEmitter = new EventEmitter<string>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
public resizeService: ResizeService,
|
public resizeService: ResizeService
|
||||||
public sharedService: SharedService
|
) {}
|
||||||
) {
|
|
||||||
this.updateContactData();
|
|
||||||
}
|
|
||||||
|
|
||||||
contactData = {
|
contactData = {
|
||||||
firstName: '',
|
firstName: '',
|
||||||
|
|
@ -68,7 +63,8 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
* properties of the userData object.
|
* properties of the userData object.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (!this.currentUserId) {
|
this.updateContactData();
|
||||||
|
if (!this.selectedUser) {
|
||||||
this.userData = {
|
this.userData = {
|
||||||
...this.userData,
|
...this.userData,
|
||||||
color: this.randomColor,
|
color: this.randomColor,
|
||||||
|
|
@ -84,7 +80,7 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
* @param changes an object containing the changed input properties
|
* @param changes an object containing the changed input properties
|
||||||
*/
|
*/
|
||||||
ngOnChanges(changes: SimpleChanges) {
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
if (changes['currentUserId']) {
|
if (changes['selectedUser']) {
|
||||||
this.updateContactData();
|
this.updateContactData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +105,7 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
? this.contactData.firstName.slice(0, 1).toUpperCase() +
|
? this.contactData.firstName.slice(0, 1).toUpperCase() +
|
||||||
this.contactData.lastName.slice(0, 1).toUpperCase()
|
this.contactData.lastName.slice(0, 1).toUpperCase()
|
||||||
: '';
|
: '';
|
||||||
if (!this.currentUserId) {
|
if (!this.selectedUser) {
|
||||||
this.userData = {
|
this.userData = {
|
||||||
...this.userData,
|
...this.userData,
|
||||||
initials: initials,
|
initials: initials,
|
||||||
|
|
@ -130,7 +126,7 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
* object. Otherwise, it updates the contactData object.
|
* object. Otherwise, it updates the contactData object.
|
||||||
*/
|
*/
|
||||||
updateUserData() {
|
updateUserData() {
|
||||||
if (!this.currentUserId) {
|
if (!this.selectedUser) {
|
||||||
this.userData = {
|
this.userData = {
|
||||||
...this.userData,
|
...this.userData,
|
||||||
firstName: this.capitalizeFirstLetter(this.contactData.firstName),
|
firstName: this.capitalizeFirstLetter(this.contactData.firstName),
|
||||||
|
|
@ -193,21 +189,11 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
* joined into strings using a comma separator.
|
* joined into strings using a comma separator.
|
||||||
*/
|
*/
|
||||||
private updateContactData() {
|
private updateContactData() {
|
||||||
this.contactData.firstName = this.firebaseService
|
this.contactData.firstName = this.selectedUser.firstName;
|
||||||
.getUserDetails(this.currentUserId, 'firstName')
|
this.contactData.lastName = this.selectedUser.lastName;
|
||||||
.join(', ');
|
this.contactData.email = this.selectedUser.email;
|
||||||
this.contactData.lastName = this.firebaseService
|
this.contactData.phone = this.selectedUser.phone;
|
||||||
.getUserDetails(this.currentUserId, 'lastName')
|
this.contactData.initials = this.selectedUser.initials;
|
||||||
.join(', ');
|
|
||||||
this.contactData.email = this.firebaseService
|
|
||||||
.getUserDetails(this.currentUserId, 'email')
|
|
||||||
.join(', ');
|
|
||||||
this.contactData.phone = this.firebaseService
|
|
||||||
.getUserDetails(this.currentUserId, 'phone')
|
|
||||||
.join(', ');
|
|
||||||
this.contactData.initials = this.firebaseService
|
|
||||||
.getUserDetails(this.currentUserId, 'initials')
|
|
||||||
.join(', ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -220,45 +206,15 @@ export class ContactFormComponent implements OnInit, OnChanges {
|
||||||
*/
|
*/
|
||||||
onSubmit(ngForm: NgForm) {
|
onSubmit(ngForm: NgForm) {
|
||||||
if (ngForm.submitted && ngForm.form.valid) {
|
if (ngForm.submitted && ngForm.form.valid) {
|
||||||
if (this.currentUserId) {
|
|
||||||
console.log(this.newColor, this.currentColor);
|
|
||||||
|
|
||||||
this.newColor !== ''
|
this.newColor !== ''
|
||||||
? (this.contactData.color = this.newColor)
|
? (this.contactData.color = this.newColor)
|
||||||
: (this.contactData.color = this.currentColor);
|
: (this.contactData.color = this.currentColor);
|
||||||
this.firebaseService.updateUserData(
|
console.log('Save');
|
||||||
this.currentUserId,
|
|
||||||
this.contactData
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
this.newColor !== ''
|
|
||||||
? (this.userData.color = this.newColor)
|
|
||||||
: (this.userData.color = this.randomColor);
|
|
||||||
const { id, ...taskWithoutIds } = this.userData;
|
|
||||||
this.firebaseService.addNewUser(taskWithoutIds).then((docRef) => {
|
|
||||||
this.router.navigate([`/contacts/${docRef.id}`]);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the delete contact dialog and the main dialog overlay.
|
|
||||||
*/
|
|
||||||
deleteContact() {
|
|
||||||
this.sharedService.isDeleteContactDialogOpen = false;
|
|
||||||
this.sharedService.isAnyDialogOpen = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the contact dialog by updating the shared service flags
|
|
||||||
* to indicate that no dialog, edit contact dialog, or new contact dialog
|
|
||||||
* is currently open.
|
|
||||||
*/
|
|
||||||
closeDialog() {
|
closeDialog() {
|
||||||
this.sharedService.isAnyDialogOpen = false;
|
this.closeDialogEmitter.emit('');
|
||||||
this.sharedService.isEditContactDialogOpen = false;
|
|
||||||
this.sharedService.isNewContactDialogOpen = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,23 +1,22 @@
|
||||||
@if (currentUserId) { @for (user of
|
@if (overlayData !== "new") {
|
||||||
firebaseService.getUserDataFromId(currentUserId); track user) {
|
|
||||||
<section>
|
<section>
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<img src="./../../../../assets/img/logo.svg" alt="" />
|
<img src="./../../../../assets/img/logo.svg" alt="" />
|
||||||
<p>{{ "contacts.editContact" | translate }}</p>
|
<p>{{ "contacts.editContact" | translate }}</p>
|
||||||
<app-btn-close [isContactDialogOpen]="false"></app-btn-close>
|
<app-btn-close (click)="closeDialog()"></app-btn-close>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="badge">
|
<div class="badge">
|
||||||
<div class="picker">
|
<div class="picker">
|
||||||
<input
|
<input
|
||||||
[(colorPicker)]="currentColor"
|
[(colorPicker)]="overlayData.color"
|
||||||
[style.background]="newColor === '' ? user.color : newColor"
|
[style.background]="newColor === '' ? overlayData.color : newColor"
|
||||||
(colorPickerChange)="updateColor($event)"
|
(colorPickerChange)="updateColor($event)"
|
||||||
/>
|
/>
|
||||||
<div class="initials">
|
<div class="initials">
|
||||||
@if (!userInitials) {
|
@if (!userInitials) {
|
||||||
{{ user.initials }} } @else {
|
{{ overlayData.initials }} } @else {
|
||||||
{{ userInitials }}
|
{{ userInitials }}
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -26,22 +25,23 @@ firebaseService.getUserDataFromId(currentUserId); track user) {
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<app-contact-form
|
<app-contact-form
|
||||||
(initialsEmitter)="initialsEmitter($event)"
|
(initialsEmitter)="initialsEmitter($event)"
|
||||||
[currentUserId]="currentUserId"
|
(closeDialogEmitter)="closeDialog()"
|
||||||
|
[selectedUser]="overlayData"
|
||||||
[newColor]="newColor"
|
[newColor]="newColor"
|
||||||
[currentColor]="user.color"
|
[currentColor]="overlayData.color"
|
||||||
></app-contact-form>
|
></app-contact-form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="notice">{{ "contacts.notice" | translate }}</div>
|
<div class="notice">{{ "contacts.notice" | translate }}</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
} } @else {
|
} @else {
|
||||||
<section>
|
<section>
|
||||||
<div class="dialog">
|
<div class="dialog">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<img src="./../../../../assets/img/logo.svg" alt="" />
|
<img src="./../../../../assets/img/logo.svg" alt="" />
|
||||||
<p>{{ "contacts.addContact" | translate }}</p>
|
<p>{{ "contacts.addContact" | translate }}</p>
|
||||||
<app-btn-close [isContactDialogOpen]="false"></app-btn-close>
|
<app-btn-close (click)="closeDialog()"></app-btn-close>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="badge">
|
<div class="badge">
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
import { ContactEditNewComponent } from './contact-edit-new.component';
|
import { ContactOverlayComponent } from './contact-overlay.component';
|
||||||
|
|
||||||
describe('ContactEditComponent', () => {
|
describe('ContactOverlayComponent', () => {
|
||||||
let component: ContactEditNewComponent;
|
let component: ContactOverlayComponent;
|
||||||
let fixture: ComponentFixture<ContactEditNewComponent>;
|
let fixture: ComponentFixture<ContactOverlayComponent>;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [ContactEditNewComponent],
|
imports: [ContactOverlayComponent],
|
||||||
}).compileComponents();
|
}).compileComponents();
|
||||||
|
|
||||||
fixture = TestBed.createComponent(ContactEditNewComponent);
|
fixture = TestBed.createComponent(ContactOverlayComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
});
|
});
|
||||||
|
|
@ -1,15 +1,13 @@
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { BtnCloseComponent } from '../../../shared/components/buttons/btn-close/btn-close.component';
|
|
||||||
import { FirebaseService } from '../../../services/firebase.service';
|
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
|
||||||
import { ContactFormComponent } from './contact-form/contact-form.component';
|
import { ContactFormComponent } from './contact-form/contact-form.component';
|
||||||
import { SharedService } from '../../../services/shared.service';
|
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { ColorPickerModule } from 'ngx-color-picker';
|
import { ColorPickerModule } from 'ngx-color-picker';
|
||||||
import { ColorService } from '../../../services/color.service';
|
import { FirebaseService } from '../../../../services/firebase.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-contact-edit',
|
selector: 'app-contact-overlay',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
|
@ -18,22 +16,19 @@ import { ColorService } from '../../../services/color.service';
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
ColorPickerModule,
|
ColorPickerModule,
|
||||||
],
|
],
|
||||||
templateUrl: './contact-edit-new.component.html',
|
templateUrl: './contact-overlay.component.html',
|
||||||
styleUrl: './contact-edit-new.component.scss',
|
styleUrl: './contact-overlay.component.scss',
|
||||||
})
|
})
|
||||||
export class ContactEditNewComponent implements OnInit {
|
export class ContactOverlayComponent implements OnInit {
|
||||||
@Input() currentUserId: string = '';
|
@Input() overlayData: any = [];
|
||||||
@Input() currentColor: string = '';
|
@Input() overlayType: string = '';
|
||||||
|
@Output() closeDialogEmitter = new EventEmitter<string>();
|
||||||
|
|
||||||
randomColor: string = '';
|
randomColor: string = '';
|
||||||
userInitials: string = '';
|
userInitials: string = '';
|
||||||
newColor: string = '';
|
newColor: string = '';
|
||||||
|
|
||||||
constructor(
|
constructor(public firebaseService: FirebaseService) {}
|
||||||
public firebaseService: FirebaseService,
|
|
||||||
public sharedService: SharedService,
|
|
||||||
private colorService: ColorService
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lifecycle hook that is called after data-bound properties of a directive are
|
* Lifecycle hook that is called after data-bound properties of a directive are
|
||||||
|
|
@ -41,7 +36,16 @@ export class ContactEditNewComponent implements OnInit {
|
||||||
* This method sets a random color for the user to be edited.
|
* This method sets a random color for the user to be edited.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.randomColor = this.colorService.generateRandomColor();
|
this.randomColor = this.getRandomColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
getRandomColor(): string {
|
||||||
|
const letters = '0123456789ABCDEF';
|
||||||
|
let color = '#';
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
color += letters[Math.floor(Math.random() * 16)];
|
||||||
|
}
|
||||||
|
return color;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,6 +59,10 @@ export class ContactEditNewComponent implements OnInit {
|
||||||
this.userInitials = emitter;
|
this.userInitials = emitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
closeDialog() {
|
||||||
|
this.closeDialogEmitter.emit('');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the newColor variable with the newly selected color.
|
* Updates the newColor variable with the newly selected color.
|
||||||
*
|
*
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { SharedService } from '../../../../services/shared.service';
|
|
||||||
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
@ -16,7 +15,7 @@ export class DialogOverlayComponent {
|
||||||
@Input() overlayType: string = '';
|
@Input() overlayType: string = '';
|
||||||
@Output() closeDialogEmitter = new EventEmitter<string>();
|
@Output() closeDialogEmitter = new EventEmitter<string>();
|
||||||
|
|
||||||
constructor(public sharedService: SharedService, private router: Router) {}
|
constructor(private router: Router) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to the login route and emits an empty string via the
|
* Navigates to the login route and emits an empty string via the
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,18 @@
|
||||||
[overlayType]="overlayType"
|
[overlayType]="overlayType"
|
||||||
(closeDialogEmitter)="onCloseOverlay($event)"
|
(closeDialogEmitter)="onCloseOverlay($event)"
|
||||||
></app-task-edit-overlay>
|
></app-task-edit-overlay>
|
||||||
}@if (overlayType === "dialog") {
|
} @if (overlayType === "dialog") {
|
||||||
<app-dialog-overlay
|
<app-dialog-overlay
|
||||||
[overlayData]="overlayData"
|
[overlayData]="overlayData"
|
||||||
[overlayType]="overlayType"
|
[overlayType]="overlayType"
|
||||||
(closeDialogEmitter)="onCloseOverlay($event)"
|
(closeDialogEmitter)="onCloseOverlay($event)"
|
||||||
></app-dialog-overlay>
|
></app-dialog-overlay>
|
||||||
|
} @if (overlayType === "contactOverlay") {
|
||||||
|
<app-contact-overlay
|
||||||
|
[overlayData]="overlayData"
|
||||||
|
[overlayType]="overlayType"
|
||||||
|
(closeDialogEmitter)="onCloseOverlay($event)"
|
||||||
|
></app-contact-overlay>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { TaskOverlayComponent } from './task-overlay/task-overlay.component';
|
||||||
import { TaskEditOverlayComponent } from './task-edit-overlay/task-edit-overlay.component';
|
import { TaskEditOverlayComponent } from './task-edit-overlay/task-edit-overlay.component';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { DialogOverlayComponent } from './dialog-overlay/dialog-overlay.component';
|
import { DialogOverlayComponent } from './dialog-overlay/dialog-overlay.component';
|
||||||
|
import { ContactOverlayComponent } from './contact-overlay/contact-overlay.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-overlay',
|
selector: 'app-overlay',
|
||||||
|
|
@ -14,6 +15,7 @@ import { DialogOverlayComponent } from './dialog-overlay/dialog-overlay.componen
|
||||||
TaskOverlayComponent,
|
TaskOverlayComponent,
|
||||||
TaskEditOverlayComponent,
|
TaskEditOverlayComponent,
|
||||||
DialogOverlayComponent,
|
DialogOverlayComponent,
|
||||||
|
ContactOverlayComponent,
|
||||||
],
|
],
|
||||||
templateUrl: './overlay.component.html',
|
templateUrl: './overlay.component.html',
|
||||||
styleUrl: './overlay.component.scss',
|
styleUrl: './overlay.component.scss',
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue