feat: add takeUntil to manage subscriptions lifecycle and prevent memory leaks
This commit is contained in:
parent
86692177a0
commit
ea1e14b1a8
15 changed files with 373 additions and 218 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { FormsModule, NgForm } from '@angular/forms';
|
import { FormsModule, NgForm } from '@angular/forms';
|
||||||
import { AssignedComponent } from './assigned/assigned.component';
|
import { AssignedComponent } from './assigned/assigned.component';
|
||||||
import { Subtask, Task } from '../../interfaces/task.interface';
|
import { Subtask, Task } from '../../interfaces/task.interface';
|
||||||
|
|
@ -8,7 +8,7 @@ import { FormBtnComponent } from '../../shared/components/buttons/form-btn/form-
|
||||||
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 { AuthService } from '../../services/auth.service';
|
import { AuthService } from '../../services/auth.service';
|
||||||
import { firstValueFrom, map } from 'rxjs';
|
import { firstValueFrom, map, Subject, takeUntil } from 'rxjs';
|
||||||
import { TaskService } from '../../services/task.service';
|
import { TaskService } from '../../services/task.service';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { UpdateNotifierService } from '../../services/update-notifier.service';
|
import { UpdateNotifierService } from '../../services/update-notifier.service';
|
||||||
|
|
@ -27,7 +27,7 @@ import { ToastNotificationService } from '../../services/toast-notification.serv
|
||||||
templateUrl: './add-task.component.html',
|
templateUrl: './add-task.component.html',
|
||||||
styleUrl: './add-task.component.scss',
|
styleUrl: './add-task.component.scss',
|
||||||
})
|
})
|
||||||
export class AddTaskComponent implements OnInit {
|
export class AddTaskComponent implements OnInit, OnDestroy {
|
||||||
@Input() overlayData: string = '';
|
@Input() overlayData: string = '';
|
||||||
@Input() overlayType: string = '';
|
@Input() overlayType: string = '';
|
||||||
@Input() overlayMobile: boolean = false;
|
@Input() overlayMobile: boolean = false;
|
||||||
|
|
@ -36,6 +36,8 @@ export class AddTaskComponent implements OnInit {
|
||||||
dateInPast: boolean = false;
|
dateInPast: boolean = false;
|
||||||
subtaskValue: string = '';
|
subtaskValue: string = '';
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
private taskService: TaskService,
|
private taskService: TaskService,
|
||||||
|
|
@ -67,16 +69,24 @@ export class AddTaskComponent implements OnInit {
|
||||||
* - Sets up route parameters to determine task status.
|
* - Sets up route parameters to determine task status.
|
||||||
* - Loads any existing task data from local storage.
|
* - Loads any existing task data from local storage.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.setCurrentUserId();
|
this.setCurrentUserId();
|
||||||
this.loadExistingTaskData();
|
this.loadExistingTaskData();
|
||||||
this.routeParams();
|
this.routeParams();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentUserId() {
|
setCurrentUserId() {
|
||||||
this.authService
|
this.authService
|
||||||
.getCurrentUserId()
|
.getCurrentUserId()
|
||||||
.pipe(map((userId) => userId ?? ''))
|
.pipe(
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
map((userId) => userId ?? '')
|
||||||
|
)
|
||||||
.subscribe((userId) => {
|
.subscribe((userId) => {
|
||||||
this.taskData.creator = userId;
|
this.taskData.creator = userId;
|
||||||
});
|
});
|
||||||
|
|
@ -103,14 +113,12 @@ export class AddTaskComponent implements OnInit {
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
routeParams() {
|
routeParams() {
|
||||||
if (this.route.params.subscribe()) {
|
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||||
this.route.params.subscribe((params) => {
|
|
||||||
if (params['id']) {
|
if (params['id']) {
|
||||||
this.taskData.status = params['id'];
|
this.taskData.status = params['id'];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads any existing task data from local storage and assigns it to the taskData object.
|
* Loads any existing task data from local storage and assigns it to the taskData object.
|
||||||
|
|
@ -270,7 +278,10 @@ export class AddTaskComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
createTask(ngForm: NgForm) {
|
createTask(ngForm: NgForm) {
|
||||||
this.apiService.saveNewTask(this.taskData).subscribe({
|
this.apiService
|
||||||
|
.saveNewTask(this.taskData)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
this.toastNotificationService.createTaskSuccessToast();
|
this.toastNotificationService.createTaskSuccessToast();
|
||||||
this.updateNotifierService.notifyUpdate('task');
|
this.updateNotifierService.notifyUpdate('task');
|
||||||
|
|
@ -286,7 +297,10 @@ export class AddTaskComponent implements OnInit {
|
||||||
|
|
||||||
updateTask(ngForm: NgForm) {
|
updateTask(ngForm: NgForm) {
|
||||||
// OverlayData = Current TaskId
|
// OverlayData = Current TaskId
|
||||||
this.apiService.updateTask(this.taskData, this.overlayData).subscribe({
|
this.apiService
|
||||||
|
.updateTask(this.taskData, this.overlayData)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
this.toastNotificationService.updateTaskSuccessToast();
|
this.toastNotificationService.updateTaskSuccessToast();
|
||||||
this.updateNotifierService.notifyUpdate('task');
|
this.updateNotifierService.notifyUpdate('task');
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,8 @@ import {
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
HostListener,
|
HostListener,
|
||||||
Input,
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
Output,
|
Output,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
@ -11,7 +13,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { User } from '../../../interfaces/user.interface';
|
import { User } from '../../../interfaces/user.interface';
|
||||||
import { ApiService } from '../../../services/api.service';
|
import { ApiService } from '../../../services/api.service';
|
||||||
import { map, catchError, of } from 'rxjs';
|
import { map, catchError, of, Subject, takeUntil } from 'rxjs';
|
||||||
import { Assignee } from '../../../interfaces/task.interface';
|
import { Assignee } from '../../../interfaces/task.interface';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
|
@ -21,7 +23,7 @@ import { Assignee } from '../../../interfaces/task.interface';
|
||||||
templateUrl: './assigned.component.html',
|
templateUrl: './assigned.component.html',
|
||||||
styleUrl: './assigned.component.scss',
|
styleUrl: './assigned.component.scss',
|
||||||
})
|
})
|
||||||
export class AssignedComponent {
|
export class AssignedComponent implements OnInit, OnDestroy {
|
||||||
@Input() taskCreator: string = '';
|
@Input() taskCreator: string = '';
|
||||||
@Input() currentAssignees: Assignee[] = [];
|
@Input() currentAssignees: Assignee[] = [];
|
||||||
@Output() assignedChange = new EventEmitter<string[]>();
|
@Output() assignedChange = new EventEmitter<string[]>();
|
||||||
|
|
@ -35,16 +37,24 @@ export class AssignedComponent {
|
||||||
dialogX: number = 0;
|
dialogX: number = 0;
|
||||||
dialogY: number = 0;
|
dialogY: number = 0;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(private apiService: ApiService) {}
|
constructor(private apiService: ApiService) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.loadUsers();
|
this.loadUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
loadUsers(): void {
|
loadUsers(): void {
|
||||||
this.apiService
|
this.apiService
|
||||||
.getUsers()
|
.getUsers()
|
||||||
.pipe(
|
.pipe(
|
||||||
|
takeUntil(this.destroy$),
|
||||||
map((users) => users.filter((user) => user.id !== this.taskCreator)),
|
map((users) => users.filter((user) => user.id !== this.taskCreator)),
|
||||||
catchError(() => of([]))
|
catchError(() => of([]))
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { DragDropService } from '../../services/drag-drop.service';
|
import { DragDropService } from '../../services/drag-drop.service';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TaskComponent } from './task/task.component';
|
import { TaskComponent } from './task/task.component';
|
||||||
|
|
@ -32,14 +32,23 @@ import { ResizeService } from '../../services/resize.service';
|
||||||
templateUrl: './board.component.html',
|
templateUrl: './board.component.html',
|
||||||
styleUrl: './board.component.scss',
|
styleUrl: './board.component.scss',
|
||||||
})
|
})
|
||||||
export class BoardComponent {
|
export class BoardComponent implements OnInit, OnDestroy {
|
||||||
private destroy$ = new Subject<void>();
|
|
||||||
|
|
||||||
readonly TODO = 'todo';
|
readonly TODO = 'todo';
|
||||||
readonly IN_PROGRESS = 'inprogress';
|
readonly IN_PROGRESS = 'inprogress';
|
||||||
readonly AWAIT_FEEDBACK = 'awaitfeedback';
|
readonly AWAIT_FEEDBACK = 'awaitfeedback';
|
||||||
readonly DONE = 'done';
|
readonly DONE = 'done';
|
||||||
|
|
||||||
|
allTasks: Task[] = [];
|
||||||
|
filteredTasks: { [key: string]: Task[] } = {};
|
||||||
|
|
||||||
|
searchValue: string = '';
|
||||||
|
searchInput: boolean = false;
|
||||||
|
taskMovedTo: string = '';
|
||||||
|
taskMovedFrom: string = '';
|
||||||
|
isLoading = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public dragDropService: DragDropService,
|
public dragDropService: DragDropService,
|
||||||
public overlayService: OverlayService,
|
public overlayService: OverlayService,
|
||||||
|
|
@ -51,27 +60,26 @@ export class BoardComponent {
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
allTasks: Task[] = [];
|
ngOnInit(): void {
|
||||||
filteredTasks: { [key: string]: Task[] } = {};
|
|
||||||
|
|
||||||
searchValue: string = '';
|
|
||||||
searchInput: boolean = false;
|
|
||||||
taskMovedTo: string = '';
|
|
||||||
taskMovedFrom: string = '';
|
|
||||||
isLoading = false;
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
this.loadAllTasks();
|
this.loadAllTasks();
|
||||||
this.subscribeToTaskUpdates();
|
this.subscribeToTaskUpdates();
|
||||||
this.subscribeToDragDropEvents();
|
this.subscribeToDragDropEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
loadAllTasks(): void {
|
loadAllTasks(): void {
|
||||||
this.isLoading = true;
|
this.isLoading = true;
|
||||||
|
|
||||||
this.taskService
|
this.taskService
|
||||||
.getTasksWithUsers()
|
.getTasksWithUsers()
|
||||||
.pipe(finalize(() => (this.isLoading = false)))
|
.pipe(
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
finalize(() => (this.isLoading = false))
|
||||||
|
)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
this.allTasks = response.allTasks;
|
this.allTasks = response.allTasks;
|
||||||
|
|
@ -111,15 +119,21 @@ export class BoardComponent {
|
||||||
* - `itemMovedFrom`: Sets `taskMovedFrom` to the status.
|
* - `itemMovedFrom`: Sets `taskMovedFrom` to the status.
|
||||||
*/
|
*/
|
||||||
private subscribeToDragDropEvents(): void {
|
private subscribeToDragDropEvents(): void {
|
||||||
this.dragDropService.itemDropped.subscribe(({ task, status }) => {
|
this.dragDropService.itemDropped
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(({ task, status }) => {
|
||||||
this.handleItemDropped(task, status);
|
this.handleItemDropped(task, status);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dragDropService.itemMovedTo.subscribe(({ status }) => {
|
this.dragDropService.itemMovedTo
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(({ status }) => {
|
||||||
this.taskMovedTo = status;
|
this.taskMovedTo = status;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.dragDropService.itemMovedFrom.subscribe(({ status }) => {
|
this.dragDropService.itemMovedFrom
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(({ status }) => {
|
||||||
this.taskMovedFrom = status;
|
this.taskMovedFrom = status;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -142,7 +156,10 @@ export class BoardComponent {
|
||||||
handleItemDropped(task: Task, status: string): void {
|
handleItemDropped(task: Task, status: string): void {
|
||||||
if (!task || task.status === status) return;
|
if (!task || task.status === status) return;
|
||||||
|
|
||||||
this.apiService.updateTaskStatus(task.id!, status).subscribe({
|
this.apiService
|
||||||
|
.updateTaskStatus(task.id!, status)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
next: () => {
|
next: () => {
|
||||||
this.toastNotificationService.taskStatusUpdatedToast();
|
this.toastNotificationService.taskStatusUpdatedToast();
|
||||||
this.updateTaskStatus(task.id!, status);
|
this.updateTaskStatus(task.id!, status);
|
||||||
|
|
@ -201,9 +218,4 @@ export class BoardComponent {
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy() {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,15 @@ import {
|
||||||
Component,
|
Component,
|
||||||
EventEmitter,
|
EventEmitter,
|
||||||
Input,
|
Input,
|
||||||
|
OnChanges,
|
||||||
|
OnDestroy,
|
||||||
Output,
|
Output,
|
||||||
SimpleChanges,
|
SimpleChanges,
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
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, lastValueFrom } from 'rxjs';
|
import { finalize, lastValueFrom, Subject, takeUntil } from 'rxjs';
|
||||||
import { User } from '../../../interfaces/user.interface';
|
import { User } from '../../../interfaces/user.interface';
|
||||||
import { OverlayService } from '../../../services/overlay.service';
|
import { OverlayService } from '../../../services/overlay.service';
|
||||||
import { ApiService } from '../../../services/api.service';
|
import { ApiService } from '../../../services/api.service';
|
||||||
|
|
@ -23,7 +25,7 @@ import { ConfirmDialogComponent } from '../../../shared/components/confirm-dialo
|
||||||
templateUrl: './contact-detail.component.html',
|
templateUrl: './contact-detail.component.html',
|
||||||
styleUrl: './contact-detail.component.scss',
|
styleUrl: './contact-detail.component.scss',
|
||||||
})
|
})
|
||||||
export class ContactDetailComponent {
|
export class ContactDetailComponent implements OnChanges, OnDestroy {
|
||||||
@Input() selectedUserId: string | null = null;
|
@Input() selectedUserId: string | null = null;
|
||||||
@Input() currentUser: User | null = null;
|
@Input() currentUser: User | null = null;
|
||||||
@Output() contactClosed = new EventEmitter<boolean>();
|
@Output() contactClosed = new EventEmitter<boolean>();
|
||||||
|
|
@ -33,6 +35,8 @@ export class ContactDetailComponent {
|
||||||
showMobileNavbar = false;
|
showMobileNavbar = false;
|
||||||
showConfirmDialog = false;
|
showConfirmDialog = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
|
|
@ -56,6 +60,38 @@ export class ContactDetailComponent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the user data with the given id and sets it to the `selectedUser` property.
|
||||||
|
*/
|
||||||
|
loadUser(): void {
|
||||||
|
this.isLoading = true;
|
||||||
|
|
||||||
|
if (!this.selectedUserId) {
|
||||||
|
this.isLoading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userService
|
||||||
|
.getUserById(this.selectedUserId)
|
||||||
|
.pipe(
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
finalize(() => (this.isLoading = false))
|
||||||
|
)
|
||||||
|
.subscribe({
|
||||||
|
next: (response) => {
|
||||||
|
this.selectedUser = response;
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Error loading the tasks:', err);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Emits an event with the value false to trigger the contact list to close.
|
* Emits an event with the value false to trigger the contact list to close.
|
||||||
*/
|
*/
|
||||||
|
|
@ -104,28 +140,4 @@ export class ContactDetailComponent {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads the user data with the given id and sets it to the `selectedUser` property.
|
|
||||||
*/
|
|
||||||
loadUser(): void {
|
|
||||||
this.isLoading = true;
|
|
||||||
|
|
||||||
if (!this.selectedUserId) {
|
|
||||||
this.isLoading = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.userService
|
|
||||||
.getUserById(this.selectedUserId)
|
|
||||||
.pipe(finalize(() => (this.isLoading = false)))
|
|
||||||
.subscribe({
|
|
||||||
next: (response) => {
|
|
||||||
this.selectedUser = response;
|
|
||||||
},
|
|
||||||
error: (err) => {
|
|
||||||
console.error('Error loading the tasks:', err);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, HostListener } from '@angular/core';
|
import { Component, HostListener, OnDestroy, OnInit } 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 { ContactDetailComponent } from './contact-detail/contact-detail.component';
|
import { ContactDetailComponent } from './contact-detail/contact-detail.component';
|
||||||
|
|
@ -15,15 +15,15 @@ import { UpdateNotifierService } from '../../services/update-notifier.service';
|
||||||
templateUrl: './contacts.component.html',
|
templateUrl: './contacts.component.html',
|
||||||
styleUrl: './contacts.component.scss',
|
styleUrl: './contacts.component.scss',
|
||||||
})
|
})
|
||||||
export class ContactsComponent {
|
export class ContactsComponent implements OnInit, OnDestroy {
|
||||||
private destroy$ = new Subject<void>();
|
|
||||||
|
|
||||||
allUsers: User[] = [];
|
allUsers: User[] = [];
|
||||||
currentUser: User | null = null;
|
currentUser: User | null = null;
|
||||||
selectedUserId: string | null = null;
|
selectedUserId: string | null = null;
|
||||||
showAllUsers: boolean = false;
|
showAllUsers: boolean = false;
|
||||||
isLoading: boolean = false;
|
isLoading: boolean = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
|
|
@ -35,6 +35,11 @@ export class ContactsComponent {
|
||||||
this.initializeData();
|
this.initializeData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
private async initializeData(): Promise<void> {
|
private async initializeData(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.loadAllUsers();
|
await this.loadAllUsers();
|
||||||
|
|
@ -74,7 +79,10 @@ export class ContactsComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadCurrentUser(): void {
|
private loadCurrentUser(): void {
|
||||||
this.userService.getCurrentUser().subscribe({
|
this.userService
|
||||||
|
.getCurrentUser()
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
next: (userData) => {
|
next: (userData) => {
|
||||||
this.currentUser = userData;
|
this.currentUser = userData;
|
||||||
},
|
},
|
||||||
|
|
@ -130,9 +138,4 @@ export class ContactsComponent {
|
||||||
this.showAllUsers = true;
|
this.showAllUsers = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
|
||||||
this.destroy$.next();
|
|
||||||
this.destroy$.complete();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnDestroy, OnInit } 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 { 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 { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subject, Subscription, takeUntil } 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 { PasswordVisibilityService } from '../../../../services/password-visibility.service';
|
import { PasswordVisibilityService } from '../../../../services/password-visibility.service';
|
||||||
|
|
@ -25,7 +25,7 @@ import { PasswordVisibilityService } from '../../../../services/password-visibil
|
||||||
templateUrl: './pw-reset.component.html',
|
templateUrl: './pw-reset.component.html',
|
||||||
styleUrl: './pw-reset.component.scss',
|
styleUrl: './pw-reset.component.scss',
|
||||||
})
|
})
|
||||||
export class PwResetComponent {
|
export class PwResetComponent implements OnInit, OnDestroy {
|
||||||
private routeSubscription: Subscription = new Subscription();
|
private routeSubscription: Subscription = new Subscription();
|
||||||
|
|
||||||
uid: string = '';
|
uid: string = '';
|
||||||
|
|
@ -37,6 +37,8 @@ export class PwResetComponent {
|
||||||
passwordConfirm: '',
|
passwordConfirm: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public pwVisibility: PasswordVisibilityService,
|
public pwVisibility: PasswordVisibilityService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
|
@ -45,16 +47,19 @@ export class PwResetComponent {
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.routeSubscription = this.route.params.subscribe((params) => {
|
this.routeParams();
|
||||||
this.uid = params['uid'];
|
|
||||||
this.token = params['token'];
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.routeSubscription) {
|
this.destroy$.next();
|
||||||
this.routeSubscription.unsubscribe();
|
this.destroy$.complete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
routeParams() {
|
||||||
|
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||||
|
this.uid = params['uid'];
|
||||||
|
this.token = params['token'];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
isButtonDisabled() {
|
isButtonDisabled() {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnDestroy, OnInit } 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';
|
||||||
|
|
@ -12,6 +12,7 @@ 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';
|
import { PasswordVisibilityService } from '../../services/password-visibility.service';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-login',
|
selector: 'app-login',
|
||||||
|
|
@ -29,7 +30,7 @@ import { PasswordVisibilityService } from '../../services/password-visibility.se
|
||||||
templateUrl: './login.component.html',
|
templateUrl: './login.component.html',
|
||||||
styleUrl: './login.component.scss',
|
styleUrl: './login.component.scss',
|
||||||
})
|
})
|
||||||
export class LoginComponent {
|
export class LoginComponent implements OnInit, OnDestroy {
|
||||||
isPasswordIconVisible: boolean = true;
|
isPasswordIconVisible: boolean = true;
|
||||||
checkboxRememberMe: boolean = false;
|
checkboxRememberMe: boolean = false;
|
||||||
|
|
||||||
|
|
@ -38,6 +39,8 @@ export class LoginComponent {
|
||||||
password: '',
|
password: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public pwVisibility: PasswordVisibilityService,
|
public pwVisibility: PasswordVisibilityService,
|
||||||
private authService: AuthService,
|
private authService: AuthService,
|
||||||
|
|
@ -47,13 +50,18 @@ export class LoginComponent {
|
||||||
private route: ActivatedRoute
|
private route: ActivatedRoute
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.routeParams();
|
this.routeParams();
|
||||||
this.deleteTokens();
|
this.deleteTokens();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
routeParams() {
|
routeParams() {
|
||||||
this.route.params.subscribe((params) => {
|
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||||
if (params['id'] && params['id'] === 'pw-send') {
|
if (params['id'] && params['id'] === 'pw-send') {
|
||||||
this.overlayService.setOverlayData('dialog', 'pw-send');
|
this.overlayService.setOverlayData('dialog', 'pw-send');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { LanguageService } from '../../services/language.service';
|
import { LanguageService } from '../../services/language.service';
|
||||||
|
|
@ -8,6 +8,7 @@ import { HeaderComponent } from '../../shared/components/header/header.component
|
||||||
import { UserService } from '../../services/user.service';
|
import { UserService } from '../../services/user.service';
|
||||||
import { User } from '../../interfaces/user.interface';
|
import { User } from '../../interfaces/user.interface';
|
||||||
import { OverlayComponent } from '../../shared/components/overlay/overlay.component';
|
import { OverlayComponent } from '../../shared/components/overlay/overlay.component';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-main-layout',
|
selector: 'app-main-layout',
|
||||||
|
|
@ -23,9 +24,11 @@ import { OverlayComponent } from '../../shared/components/overlay/overlay.compon
|
||||||
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 implements OnInit, OnDestroy {
|
||||||
currentUser: User | null = null;
|
currentUser: User | null = null;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public langService: LanguageService,
|
public langService: LanguageService,
|
||||||
private userService: UserService
|
private userService: UserService
|
||||||
|
|
@ -35,8 +38,16 @@ export class MainLayoutComponent {
|
||||||
this.loadCurrentUser();
|
this.loadCurrentUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
loadCurrentUser(): void {
|
loadCurrentUser(): void {
|
||||||
this.userService.getCurrentUser().subscribe((userData) => {
|
this.userService
|
||||||
|
.getCurrentUser()
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((userData) => {
|
||||||
this.currentUser = userData;
|
this.currentUser = userData;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import { Component } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
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 { Task } from '../../interfaces/task.interface';
|
import { Task } from '../../interfaces/task.interface';
|
||||||
import { TaskService } from '../../services/task.service';
|
import { TaskService } from '../../services/task.service';
|
||||||
import { LoadingSpinnerComponent } from '../../shared/components/loading-spinner/loading-spinner.component';
|
import { LoadingSpinnerComponent } from '../../shared/components/loading-spinner/loading-spinner.component';
|
||||||
import { finalize } from 'rxjs';
|
import { finalize, Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
import { UserService } from '../../services/user.service';
|
import { UserService } from '../../services/user.service';
|
||||||
import { User } from '../../interfaces/user.interface';
|
import { User } from '../../interfaces/user.interface';
|
||||||
|
|
@ -16,13 +16,14 @@ import { User } from '../../interfaces/user.interface';
|
||||||
templateUrl: './summary.component.html',
|
templateUrl: './summary.component.html',
|
||||||
styleUrl: './summary.component.scss',
|
styleUrl: './summary.component.scss',
|
||||||
})
|
})
|
||||||
export class SummaryComponent {
|
export class SummaryComponent implements OnInit, OnDestroy {
|
||||||
nextUrgendTask: number[] = [];
|
|
||||||
|
|
||||||
allTasks: Task[] = [];
|
allTasks: Task[] = [];
|
||||||
|
nextUrgendTask: number[] = [];
|
||||||
currentUser: User | null = null;
|
currentUser: User | null = null;
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private translateService: TranslateService,
|
private translateService: TranslateService,
|
||||||
private userService: UserService,
|
private userService: UserService,
|
||||||
|
|
@ -32,11 +33,16 @@ export class SummaryComponent {
|
||||||
/**
|
/**
|
||||||
* This method loads all tasks from the TaskService.
|
* This method loads all tasks from the TaskService.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.loadAllTasks();
|
this.loadAllTasks();
|
||||||
this.loadCurrentUser();
|
this.loadCurrentUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads all tasks from the TaskService.
|
* Loads all tasks from the TaskService.
|
||||||
*/
|
*/
|
||||||
|
|
@ -45,7 +51,10 @@ export class SummaryComponent {
|
||||||
|
|
||||||
this.taskService
|
this.taskService
|
||||||
.getTasks()
|
.getTasks()
|
||||||
.pipe(finalize(() => (this.isLoading = false)))
|
.pipe(
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
finalize(() => (this.isLoading = false))
|
||||||
|
)
|
||||||
.subscribe({
|
.subscribe({
|
||||||
next: (response) => {
|
next: (response) => {
|
||||||
this.allTasks = response;
|
this.allTasks = response;
|
||||||
|
|
@ -57,7 +66,10 @@ export class SummaryComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadCurrentUser(): void {
|
loadCurrentUser(): void {
|
||||||
this.userService.getCurrentUser().subscribe((userData) => {
|
this.userService
|
||||||
|
.getCurrentUser()
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((userData) => {
|
||||||
this.currentUser = userData;
|
this.currentUser = userData;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
import { Component, HostListener } from '@angular/core';
|
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { RouterModule } from '@angular/router';
|
import { RouterModule } from '@angular/router';
|
||||||
import { NavbarComponent } from './navbar/navbar.component';
|
import { NavbarComponent } from './navbar/navbar.component';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
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 { User } from '../../../interfaces/user.interface';
|
import { User } from '../../../interfaces/user.interface';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-header',
|
selector: 'app-header',
|
||||||
|
|
@ -13,25 +14,35 @@ import { User } from '../../../interfaces/user.interface';
|
||||||
templateUrl: './header.component.html',
|
templateUrl: './header.component.html',
|
||||||
styleUrl: './header.component.scss',
|
styleUrl: './header.component.scss',
|
||||||
})
|
})
|
||||||
export class HeaderComponent {
|
export class HeaderComponent implements OnInit, OnDestroy {
|
||||||
showNavbar: boolean = false;
|
showNavbar: boolean = false;
|
||||||
showLanguageNavbar: boolean = false;
|
showLanguageNavbar: boolean = false;
|
||||||
currentUser: User | null = null;
|
currentUser: User | null = null;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(private userService: UserService) {}
|
constructor(private userService: UserService) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the current user data by calling the loadCurrentUser method.
|
* Loads the current user data by calling the loadCurrentUser method.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.loadCurrentUser();
|
this.loadCurrentUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads the current user data and sets it to the `currentUser` property.
|
* Loads the current user data and sets it to the `currentUser` property.
|
||||||
*/
|
*/
|
||||||
loadCurrentUser(): void {
|
loadCurrentUser(): void {
|
||||||
this.userService.getCurrentUser().subscribe((userData) => {
|
this.userService
|
||||||
|
.getCurrentUser()
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((userData) => {
|
||||||
this.currentUser = userData;
|
this.currentUser = userData;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { ContactFormComponent } from './contact-form/contact-form.component';
|
import { ContactFormComponent } from './contact-form/contact-form.component';
|
||||||
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
||||||
|
|
@ -18,7 +18,7 @@ import { ColorPickerModule } from 'ngx-color-picker';
|
||||||
templateUrl: './contact-overlay.component.html',
|
templateUrl: './contact-overlay.component.html',
|
||||||
styleUrl: './contact-overlay.component.scss',
|
styleUrl: './contact-overlay.component.scss',
|
||||||
})
|
})
|
||||||
export class ContactOverlayComponent implements OnInit {
|
export class ContactOverlayComponent {
|
||||||
@Input() overlayData: any = [];
|
@Input() overlayData: any = [];
|
||||||
@Input() overlayType: string = '';
|
@Input() overlayType: string = '';
|
||||||
@Output() closeDialogEmitter = new EventEmitter<boolean>();
|
@Output() closeDialogEmitter = new EventEmitter<boolean>();
|
||||||
|
|
@ -27,10 +27,6 @@ export class ContactOverlayComponent implements OnInit {
|
||||||
userInitials: string = '';
|
userInitials: string = '';
|
||||||
newColor: string = '';
|
newColor: string = '';
|
||||||
|
|
||||||
constructor() {}
|
|
||||||
|
|
||||||
ngOnInit() {}
|
|
||||||
|
|
||||||
getRandomColor(): string {
|
getRandomColor(): string {
|
||||||
const letters = '0123456789ABCDEF';
|
const letters = '0123456789ABCDEF';
|
||||||
let color = '#';
|
let color = '#';
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, HostListener, OnInit } from '@angular/core';
|
import { Component, HostListener, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { OverlayService } from '../../../services/overlay.service';
|
import { OverlayService } from '../../../services/overlay.service';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { TaskOverlayComponent } from './task-overlay/task-overlay.component';
|
import { TaskOverlayComponent } from './task-overlay/task-overlay.component';
|
||||||
|
|
@ -6,6 +6,7 @@ import { TaskEditOverlayComponent } from './task-edit-overlay/task-edit-overlay.
|
||||||
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';
|
import { ContactOverlayComponent } from './contact-overlay/contact-overlay.component';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-overlay',
|
selector: 'app-overlay',
|
||||||
|
|
@ -20,10 +21,12 @@ import { ContactOverlayComponent } from './contact-overlay/contact-overlay.compo
|
||||||
templateUrl: './overlay.component.html',
|
templateUrl: './overlay.component.html',
|
||||||
styleUrl: './overlay.component.scss',
|
styleUrl: './overlay.component.scss',
|
||||||
})
|
})
|
||||||
export class OverlayComponent implements OnInit {
|
export class OverlayComponent implements OnInit, OnDestroy {
|
||||||
overlayType: any;
|
overlayType: any;
|
||||||
overlayData: any;
|
overlayData: any;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(private overlayService: OverlayService, private router: Router) {}
|
constructor(private overlayService: OverlayService, private router: Router) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -34,13 +37,20 @@ export class OverlayComponent implements OnInit {
|
||||||
this.checkOverlayData();
|
this.checkOverlayData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to the overlay data observable from the OverlayService.
|
* Subscribes to the overlay data observable from the OverlayService.
|
||||||
* Updates the component's `overlayType` and `overlayData` properties
|
* Updates the component's `overlayType` and `overlayData` properties
|
||||||
* whenever new overlay data is emitted.
|
* whenever new overlay data is emitted.
|
||||||
*/
|
*/
|
||||||
checkOverlayData() {
|
checkOverlayData() {
|
||||||
this.overlayService.overlayData$.subscribe((data) => {
|
this.overlayService.overlayData$
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe((data) => {
|
||||||
if (data) {
|
if (data) {
|
||||||
this.overlayType = data.overlay;
|
this.overlayType = data.overlay;
|
||||||
this.overlayData = data.data;
|
this.overlayData = data.data;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,18 @@
|
||||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
} from '@angular/core';
|
||||||
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { AddTaskComponent } from '../../../../components/add-task/add-task.component';
|
import { AddTaskComponent } from '../../../../components/add-task/add-task.component';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { ApiService } from '../../../../services/api.service';
|
import { ApiService } from '../../../../services/api.service';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task-edit-overlay',
|
selector: 'app-task-edit-overlay',
|
||||||
|
|
@ -13,13 +21,15 @@ import { ApiService } from '../../../../services/api.service';
|
||||||
templateUrl: './task-edit-overlay.component.html',
|
templateUrl: './task-edit-overlay.component.html',
|
||||||
styleUrl: './task-edit-overlay.component.scss',
|
styleUrl: './task-edit-overlay.component.scss',
|
||||||
})
|
})
|
||||||
export class TaskEditOverlayComponent {
|
export class TaskEditOverlayComponent implements OnInit, OnDestroy {
|
||||||
@Input() overlayData: string = '';
|
@Input() overlayData: string = '';
|
||||||
@Input() overlayType: string = '';
|
@Input() overlayType: string = '';
|
||||||
@Output() closeDialogEmitter = new EventEmitter<boolean>();
|
@Output() closeDialogEmitter = new EventEmitter<boolean>();
|
||||||
|
|
||||||
overlayMobile: boolean = false;
|
overlayMobile: boolean = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
|
@ -33,17 +43,24 @@ export class TaskEditOverlayComponent {
|
||||||
* and sets the overlay data and type from the route parameters. It also sets
|
* and sets the overlay data and type from the route parameters. It also sets
|
||||||
* the overlay mobile flag to true.
|
* the overlay mobile flag to true.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
if (this.overlayData == '') {
|
this.loadOverlayData();
|
||||||
if (this.route.params.subscribe()) {
|
}
|
||||||
this.route.params.subscribe((params) => {
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadOverlayData(): void {
|
||||||
|
if (this.overlayData === '') {
|
||||||
|
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||||
this.overlayData = params['id'];
|
this.overlayData = params['id'];
|
||||||
this.overlayType = this.overlayType;
|
this.overlayType = this.overlayType;
|
||||||
this.overlayMobile = true;
|
this.overlayMobile = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the task data from the Firebase service for the given task id.
|
* Gets the task data from the Firebase service for the given task id.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,11 @@
|
||||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
import {
|
||||||
|
Component,
|
||||||
|
EventEmitter,
|
||||||
|
Input,
|
||||||
|
OnDestroy,
|
||||||
|
OnInit,
|
||||||
|
Output,
|
||||||
|
} from '@angular/core';
|
||||||
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
import { BtnCloseComponent } from '../../buttons/btn-close/btn-close.component';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { OverlayService } from '../../../../services/overlay.service';
|
import { OverlayService } from '../../../../services/overlay.service';
|
||||||
|
|
@ -8,7 +15,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { Task } from '../../../../interfaces/task.interface';
|
import { Task } from '../../../../interfaces/task.interface';
|
||||||
import { TaskService } from '../../../../services/task.service';
|
import { TaskService } from '../../../../services/task.service';
|
||||||
import { AuthService } from '../../../../services/auth.service';
|
import { AuthService } from '../../../../services/auth.service';
|
||||||
import { map } from 'rxjs';
|
import { map, Subject, takeUntil } from 'rxjs';
|
||||||
import { ApiService } from '../../../../services/api.service';
|
import { ApiService } from '../../../../services/api.service';
|
||||||
import { UpdateNotifierService } from '../../../../services/update-notifier.service';
|
import { UpdateNotifierService } from '../../../../services/update-notifier.service';
|
||||||
import { ToastNotificationService } from '../../../../services/toast-notification.service';
|
import { ToastNotificationService } from '../../../../services/toast-notification.service';
|
||||||
|
|
@ -27,7 +34,7 @@ import { ConfirmDialogComponent } from '../../confirm-dialog/confirm-dialog.comp
|
||||||
templateUrl: './task-overlay.component.html',
|
templateUrl: './task-overlay.component.html',
|
||||||
styleUrl: './task-overlay.component.scss',
|
styleUrl: './task-overlay.component.scss',
|
||||||
})
|
})
|
||||||
export class TaskOverlayComponent implements OnInit {
|
export class TaskOverlayComponent implements OnInit, OnDestroy {
|
||||||
@Input() overlayData: string = '';
|
@Input() overlayData: string = '';
|
||||||
@Output() closeDialogEmitter = new EventEmitter<boolean>();
|
@Output() closeDialogEmitter = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
|
@ -36,6 +43,8 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
currentUserId: string = '';
|
currentUserId: string = '';
|
||||||
showConfirmDialog = false;
|
showConfirmDialog = false;
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
private taskService: TaskService,
|
private taskService: TaskService,
|
||||||
|
|
@ -52,16 +61,24 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
['Technical Task', '#20d7c2'],
|
['Technical Task', '#20d7c2'],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit(): void {
|
||||||
this.setCurrentUserId();
|
this.setCurrentUserId();
|
||||||
this.setOverlayDataFromRoute();
|
this.setOverlayDataFromRoute();
|
||||||
this.loadTask(this.overlayData);
|
this.loadTask(this.overlayData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
setCurrentUserId() {
|
setCurrentUserId() {
|
||||||
this.authService
|
this.authService
|
||||||
.getCurrentUserId()
|
.getCurrentUserId()
|
||||||
.pipe(map((userId) => userId ?? ''))
|
.pipe(
|
||||||
|
takeUntil(this.destroy$),
|
||||||
|
map((userId) => userId ?? '')
|
||||||
|
)
|
||||||
.subscribe((userId) => {
|
.subscribe((userId) => {
|
||||||
this.currentUserId = userId;
|
this.currentUserId = userId;
|
||||||
});
|
});
|
||||||
|
|
@ -69,7 +86,7 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
|
|
||||||
setOverlayDataFromRoute() {
|
setOverlayDataFromRoute() {
|
||||||
if (this.overlayData === '') {
|
if (this.overlayData === '') {
|
||||||
this.route.params.subscribe((params) => {
|
this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => {
|
||||||
this.overlayData = params['id'];
|
this.overlayData = params['id'];
|
||||||
this.overlayMobile = true;
|
this.overlayMobile = true;
|
||||||
});
|
});
|
||||||
|
|
@ -77,7 +94,10 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
loadTask(taskId: string) {
|
loadTask(taskId: string) {
|
||||||
this.taskService.getTaskById(taskId).subscribe({
|
this.taskService
|
||||||
|
.getTaskById(taskId)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
next: (task) => {
|
next: (task) => {
|
||||||
this.task = task;
|
this.task = task;
|
||||||
},
|
},
|
||||||
|
|
@ -117,7 +137,10 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteTask(taskId: string) {
|
deleteTask(taskId: string) {
|
||||||
this.apiService.deleteTaskById(taskId).subscribe({
|
this.apiService
|
||||||
|
.deleteTaskById(taskId)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe({
|
||||||
next: (task) => {
|
next: (task) => {
|
||||||
this.toastNotificationService.deleteTaskSuccessToast();
|
this.toastNotificationService.deleteTaskSuccessToast();
|
||||||
this.updateNotifierService.notifyUpdate('task');
|
this.updateNotifierService.notifyUpdate('task');
|
||||||
|
|
@ -140,7 +163,10 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
subtask_title: subtaskTitle,
|
subtask_title: subtaskTitle,
|
||||||
subtask_status: !currentStatus,
|
subtask_status: !currentStatus,
|
||||||
};
|
};
|
||||||
this.apiService.updateSubtaskStatus(taskId, body).subscribe(
|
this.apiService
|
||||||
|
.updateSubtaskStatus(taskId, body)
|
||||||
|
.pipe(takeUntil(this.destroy$))
|
||||||
|
.subscribe(
|
||||||
(response) => {
|
(response) => {
|
||||||
this.task?.subtasks.forEach((subtask) => {
|
this.task?.subtasks.forEach((subtask) => {
|
||||||
if (subtask.id === subtaskId) {
|
if (subtask.id === subtaskId) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { NavigationEnd, Router, RouterModule } from '@angular/router';
|
import { NavigationEnd, Router, RouterModule } from '@angular/router';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { LanguageService } from '../../../services/language.service';
|
import { LanguageService } from '../../../services/language.service';
|
||||||
import { AuthService } from '../../../services/auth.service';
|
import { AuthService } from '../../../services/auth.service';
|
||||||
|
import { Subject, takeUntil } from 'rxjs';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-sidebar',
|
selector: 'app-sidebar',
|
||||||
|
|
@ -12,9 +13,11 @@ import { AuthService } from '../../../services/auth.service';
|
||||||
templateUrl: './sidebar.component.html',
|
templateUrl: './sidebar.component.html',
|
||||||
styleUrl: './sidebar.component.scss',
|
styleUrl: './sidebar.component.scss',
|
||||||
})
|
})
|
||||||
export class SidebarComponent implements OnInit {
|
export class SidebarComponent implements OnInit, OnDestroy {
|
||||||
currentPath: string = '';
|
currentPath: string = '';
|
||||||
|
|
||||||
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
public languageService: LanguageService,
|
public languageService: LanguageService,
|
||||||
|
|
@ -28,13 +31,18 @@ export class SidebarComponent implements OnInit {
|
||||||
this.getCurrentPath();
|
this.getCurrentPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to router events and updates the currentPath property
|
* Subscribes to router events and updates the currentPath property
|
||||||
* with the current route's URL, excluding the leading slash, whenever
|
* with the current route's URL, excluding the leading slash, whenever
|
||||||
* a navigation ends.
|
* a navigation ends.
|
||||||
*/
|
*/
|
||||||
getCurrentPath() {
|
getCurrentPath() {
|
||||||
this.router.events.subscribe((event) => {
|
this.router.events.pipe(takeUntil(this.destroy$)).subscribe((event) => {
|
||||||
if (event instanceof NavigationEnd) {
|
if (event instanceof NavigationEnd) {
|
||||||
this.currentPath = this.router.url.substring(1);
|
this.currentPath = this.router.url.substring(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue