feat: migrate TaskComponent & TaskOverlayComponent to Django Rest and implement TaskService
This commit is contained in:
parent
df7629256a
commit
18903e3c55
10 changed files with 252 additions and 132 deletions
|
|
@ -59,6 +59,7 @@ export class AddTaskComponent implements OnInit {
|
||||||
subtasksDone: [],
|
subtasksDone: [],
|
||||||
assigned: [],
|
assigned: [],
|
||||||
assignees: [],
|
assignees: [],
|
||||||
|
userData: [],
|
||||||
creator: this.firebaseService.getCurrentUserId(),
|
creator: this.firebaseService.getCurrentUserId(),
|
||||||
date: this.currentDate,
|
date: this.currentDate,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { TaskHighlightedComponent } from './task/task-highlighted/task-highlighted.component';
|
import { TaskHighlightedComponent } from './task/task-highlighted/task-highlighted.component';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { Task } from '../../interfaces/task.interface';
|
import { Task } from '../../interfaces/task.interface';
|
||||||
import { forkJoin } from 'rxjs';
|
import { TaskService } from '../../services/task.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-board',
|
selector: 'app-board',
|
||||||
|
|
@ -37,6 +37,7 @@ export class BoardComponent {
|
||||||
public dragDropService: DragDropService,
|
public dragDropService: DragDropService,
|
||||||
public overlayService: OverlayService,
|
public overlayService: OverlayService,
|
||||||
private sharedService: SharedService,
|
private sharedService: SharedService,
|
||||||
|
private taskService: TaskService,
|
||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {}
|
) {}
|
||||||
|
|
@ -62,22 +63,15 @@ export class BoardComponent {
|
||||||
* Retrieves all tasks from the API and initializes the `allTasks` and `filteredTasks` properties.
|
* Retrieves all tasks from the API and initializes the `allTasks` and `filteredTasks` properties.
|
||||||
*/
|
*/
|
||||||
loadTasks(): void {
|
loadTasks(): void {
|
||||||
const statuses = [
|
this.taskService.loadAllTasks().subscribe({
|
||||||
this.TODO,
|
next: (result) => {
|
||||||
this.IN_PROGRESS,
|
this.allTasks = result.allTasks;
|
||||||
this.AWAIT_FEEDBACK,
|
this.filteredTasks = result.filteredTasks;
|
||||||
this.DONE,
|
},
|
||||||
];
|
|
||||||
const requests = statuses.map((status) =>
|
|
||||||
this.apiService.getTasksByStatus(status)
|
|
||||||
);
|
|
||||||
|
|
||||||
forkJoin(requests).subscribe((results) => {
|
error: (err) => {
|
||||||
this.allTasks = results.flat();
|
console.error('Error loading the tasks:', err);
|
||||||
this.filteredTasks = statuses.reduce((acc, status, index) => {
|
},
|
||||||
acc[status] = results[index];
|
|
||||||
return acc;
|
|
||||||
}, {} as { [key: string]: Task[] });
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
<div class="description">
|
<div class="description">
|
||||||
{{ task.description }}
|
{{ task.description }}
|
||||||
</div>
|
</div>
|
||||||
@if(task.subtasksTitle.length > 0) {
|
@if(task.subtasks.length > 0) {
|
||||||
<div class="subtask">
|
<div class="subtask">
|
||||||
<div class="subtask-line">
|
<div class="subtask-line">
|
||||||
<span
|
<span
|
||||||
|
|
@ -36,28 +36,31 @@
|
||||||
></span>
|
></span>
|
||||||
</div>
|
</div>
|
||||||
<div class="subtask-text">
|
<div class="subtask-text">
|
||||||
{{ completedSubtasks() }} / {{ task.subtasksTitle.length }} Subtasks
|
{{ completedSubtasks() }} / {{ task.subtasks.length }} Subtasks
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<div class="footer-badge">
|
<div class="footer-badge">
|
||||||
|
@for (user of task.userData; track user) { @if (task.creator ===
|
||||||
|
user.id) {
|
||||||
<span
|
<span
|
||||||
class="footer-badged"
|
class="footer-badged"
|
||||||
(mousemove)="openDialog(task.creator, $event)"
|
(mousemove)="openDialog(task.creator, $event)"
|
||||||
(mouseleave)="closeDialog()"
|
(mouseleave)="closeDialog()"
|
||||||
[style.background-color]="userBadgedColor(task.creator)"
|
[style.background-color]="user.color"
|
||||||
>{{ userBadged(task.creator) }}</span
|
>{{ user.initials }}</span
|
||||||
>
|
>
|
||||||
@for (assigned of task.assigned; track assigned) {
|
} @for (assigned of task.assignees; track assigned.id) { @if
|
||||||
|
(assigned.user === user.id) {
|
||||||
<span
|
<span
|
||||||
class="footer-badged"
|
class="footer-badged"
|
||||||
(mousemove)="openDialog(assigned, $event)"
|
(mousemove)="openDialog(user.id, $event)"
|
||||||
(mouseleave)="closeDialog()"
|
(mouseleave)="closeDialog()"
|
||||||
[style.background-color]="userBadgedColor(assigned)"
|
[style.background-color]="user.color"
|
||||||
>{{ userBadged(assigned) }}</span
|
>{{ user.initials }}</span
|
||||||
>
|
>
|
||||||
}
|
} } }
|
||||||
</div>
|
</div>
|
||||||
<div class="footer-priority prio-{{ task.priority }}"></div>
|
<div class="footer-priority prio-{{ task.priority }}"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -70,14 +73,15 @@
|
||||||
></app-task-menu>
|
></app-task-menu>
|
||||||
} @if (AssignedDialogId != '') {
|
} @if (AssignedDialogId != '') {
|
||||||
<div class="dialog" [style.left.px]="dialogX" [style.top.px]="dialogY">
|
<div class="dialog" [style.left.px]="dialogX" [style.top.px]="dialogY">
|
||||||
|
@for (user of task.userData; track user) { @if (user.id ===
|
||||||
|
AssignedDialogId) {
|
||||||
<p>
|
<p>
|
||||||
{{ firebaseService.getUserDetails(AssignedDialogId, "firstName") }}
|
{{ user.firstName }}
|
||||||
@if (AssignedDialogId === firebaseService.getCurrentUserId()) {
|
|
||||||
<span>(du)</span> }
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{{ firebaseService.getUserDetails(AssignedDialogId, "lastName") }}
|
{{ user.lastName }}
|
||||||
</p>
|
</p>
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
} }
|
} }
|
||||||
</section>
|
</section>
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,9 @@ export class TaskComponent {
|
||||||
dialogX: number = 0;
|
dialogX: number = 0;
|
||||||
dialogY: number = 0;
|
dialogY: number = 0;
|
||||||
|
|
||||||
|
creator: any = '';
|
||||||
|
assignees: any[] = [];
|
||||||
|
|
||||||
categoryColors = new Map<string, string>([
|
categoryColors = new Map<string, string>([
|
||||||
['User Story', '#0038ff'],
|
['User Story', '#0038ff'],
|
||||||
['Technical Task', '#20d7c2'],
|
['Technical Task', '#20d7c2'],
|
||||||
|
|
@ -129,8 +132,7 @@ export class TaskComponent {
|
||||||
* @returns the number of completed subtasks
|
* @returns the number of completed subtasks
|
||||||
*/
|
*/
|
||||||
completedSubtasks(): number {
|
completedSubtasks(): number {
|
||||||
return this.task.subtasksDone.filter((subtask: boolean) => subtask === true)
|
return this.task.subtasks.filter((subtask) => subtask.done).length;
|
||||||
.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -138,12 +140,11 @@ export class TaskComponent {
|
||||||
* @returns the percentage of completed subtasks as a number
|
* @returns the percentage of completed subtasks as a number
|
||||||
*/
|
*/
|
||||||
completedSubtasksPercent(): number {
|
completedSubtasksPercent(): number {
|
||||||
const subtasks = this.task.subtasksDone;
|
const completedSubtasksCount = this.task.subtasks.filter(
|
||||||
const completedSubtasksCount = subtasks.filter(
|
(subtask) => subtask.done
|
||||||
(subtask: boolean) => subtask === true
|
|
||||||
).length;
|
).length;
|
||||||
|
|
||||||
return (completedSubtasksCount / subtasks.length) * 100;
|
return (completedSubtasksCount / this.task.subtasks.length) * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assigned
|
// Assigned
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import { UserSummary } from './user.interface';
|
||||||
|
|
||||||
export interface Task {
|
export interface Task {
|
||||||
id?: string;
|
id?: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
|
@ -9,7 +11,8 @@ export interface Task {
|
||||||
subtasksTitle: string[];
|
subtasksTitle: string[];
|
||||||
subtasksDone: boolean[];
|
subtasksDone: boolean[];
|
||||||
assigned: string[];
|
assigned: string[];
|
||||||
assignees: string[];
|
assignees: Assignee[];
|
||||||
|
userData: UserSummary[];
|
||||||
creator: string;
|
creator: string;
|
||||||
date: string;
|
date: string;
|
||||||
}
|
}
|
||||||
|
|
@ -19,3 +22,9 @@ export interface Subtask {
|
||||||
title: string;
|
title: string;
|
||||||
done: boolean;
|
done: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Assignee {
|
||||||
|
id: string;
|
||||||
|
user: string;
|
||||||
|
task: string;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,11 @@ export interface User {
|
||||||
status: boolean;
|
status: boolean;
|
||||||
lastLogin: number;
|
lastLogin: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UserSummary {
|
||||||
|
id?: string;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
initials: string;
|
||||||
|
color: string;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import { Injectable } from '@angular/core';
|
import { Injectable, signal } from '@angular/core';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { apiConfig } from '../environments/config';
|
import { apiConfig } from '../environments/config';
|
||||||
import { Task } from '../interfaces/task.interface';
|
import { Task } from '../interfaces/task.interface';
|
||||||
|
import { User } from '../interfaces/user.interface';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
|
|
@ -14,6 +15,10 @@ export class ApiService {
|
||||||
|
|
||||||
// ------------- TASKS ------------- //
|
// ------------- TASKS ------------- //
|
||||||
|
|
||||||
|
getTaskById(taskId: string): Observable<Task> {
|
||||||
|
return this.http.get<Task>(`${this.apiUrl}/api/tasks/${taskId}/`);
|
||||||
|
}
|
||||||
|
|
||||||
getTasksByStatus(status: string): Observable<Task[]> {
|
getTasksByStatus(status: string): Observable<Task[]> {
|
||||||
return this.http.get<Task[]>(`${this.apiUrl}/api/tasks/`, {
|
return this.http.get<Task[]>(`${this.apiUrl}/api/tasks/`, {
|
||||||
params: { status },
|
params: { status },
|
||||||
|
|
@ -26,4 +31,12 @@ export class ApiService {
|
||||||
{ status: status }
|
{ status: status }
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------- USERS ------------- //
|
||||||
|
|
||||||
|
getUsersByIds(userIds: string[]): Observable<User[]> {
|
||||||
|
return this.http.get<User[]>(`${this.apiUrl}/api/users/`, {
|
||||||
|
params: { ids: userIds.join(',') },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
130
src/app/services/task.service.ts
Normal file
130
src/app/services/task.service.ts
Normal file
|
|
@ -0,0 +1,130 @@
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Observable, forkJoin, of } from 'rxjs';
|
||||||
|
import { ApiService } from './api.service';
|
||||||
|
import { Task } from '../interfaces/task.interface';
|
||||||
|
import { catchError, map, switchMap } from 'rxjs/operators';
|
||||||
|
import { UserSummary } from '../interfaces/user.interface';
|
||||||
|
|
||||||
|
@Injectable({ providedIn: 'root' })
|
||||||
|
export class TaskService {
|
||||||
|
private readonly statuses = ['todo', 'inprogress', 'awaitfeedback', 'done'];
|
||||||
|
|
||||||
|
constructor(private apiService: ApiService) {}
|
||||||
|
|
||||||
|
loadAllTasks(): Observable<{
|
||||||
|
allTasks: Task[];
|
||||||
|
filteredTasks: Record<string, Task[]>;
|
||||||
|
}> {
|
||||||
|
return forkJoin(
|
||||||
|
this.statuses.map((status) => this.fetchTasksByStatus(status))
|
||||||
|
).pipe(
|
||||||
|
switchMap((results) => {
|
||||||
|
const allTasks = results.flat();
|
||||||
|
const filteredTasks = this.statuses.reduce((acc, status, index) => {
|
||||||
|
acc[status] = results[index] || [];
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, Task[]>);
|
||||||
|
|
||||||
|
return this.loadUsersForTasks(allTasks).pipe(
|
||||||
|
map((tasksWithUsers) => {
|
||||||
|
const updatedFilteredTasks = this.statuses.reduce((acc, status) => {
|
||||||
|
acc[status] = tasksWithUsers.filter(
|
||||||
|
(task) => task.status === status
|
||||||
|
);
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, Task[]>);
|
||||||
|
|
||||||
|
return {
|
||||||
|
allTasks: tasksWithUsers,
|
||||||
|
filteredTasks: updatedFilteredTasks,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private fetchTasksByStatus(status: string): Observable<Task[]> {
|
||||||
|
return this.apiService.getTasksByStatus(status).pipe(
|
||||||
|
catchError((error) => {
|
||||||
|
console.error(
|
||||||
|
`Fehler beim Abrufen von Tasks für Status ${status}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
return of([]);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadUsersForTasks(tasks: Task[]): Observable<Task[]> {
|
||||||
|
const userIds = new Set(
|
||||||
|
tasks.flatMap((task) => [
|
||||||
|
task.creator,
|
||||||
|
...task.assignees.map((a) => a.user),
|
||||||
|
])
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.apiService.getUsersByIds([...userIds]).pipe(
|
||||||
|
catchError((error) => {
|
||||||
|
console.error('Fehler beim Abrufen der Benutzer:', error);
|
||||||
|
return of([]);
|
||||||
|
}),
|
||||||
|
map((users) => {
|
||||||
|
const userMap = this.createUserMap(users);
|
||||||
|
return tasks.map((task) => ({
|
||||||
|
...task,
|
||||||
|
userData: [
|
||||||
|
...task.assignees.map((a) => userMap[a.user] || null),
|
||||||
|
userMap[task.creator] || null,
|
||||||
|
].filter(Boolean),
|
||||||
|
}));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadSingleTask(taskId: string): Observable<Task | null> {
|
||||||
|
return this.apiService.getTaskById(taskId).pipe(
|
||||||
|
switchMap((task) => {
|
||||||
|
if (!task) return of(null);
|
||||||
|
const userIds = [task.creator, ...task.assignees.map((a) => a.user)];
|
||||||
|
|
||||||
|
return this.apiService.getUsersByIds(userIds).pipe(
|
||||||
|
map((users) => ({
|
||||||
|
...task,
|
||||||
|
userData: this.mapTaskUsers(task, users),
|
||||||
|
})),
|
||||||
|
catchError((error) => {
|
||||||
|
console.error('Fehler beim Abrufen der Benutzerdaten:', error);
|
||||||
|
return of(task);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
catchError((error) => {
|
||||||
|
console.error('Fehler beim Laden des Tasks:', error);
|
||||||
|
return of(null);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createUserMap(users: UserSummary[]): Record<string, UserSummary> {
|
||||||
|
return users.reduce((acc, user) => {
|
||||||
|
if (user?.id)
|
||||||
|
acc[user.id] = {
|
||||||
|
id: user.id,
|
||||||
|
firstName: user.firstName,
|
||||||
|
lastName: user.lastName,
|
||||||
|
initials: user.initials,
|
||||||
|
color: user.color,
|
||||||
|
};
|
||||||
|
return acc;
|
||||||
|
}, {} as Record<string, UserSummary>);
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapTaskUsers(task: Task, users: UserSummary[]): UserSummary[] {
|
||||||
|
const userMap = this.createUserMap(users);
|
||||||
|
return [
|
||||||
|
...task.assignees.map((a) => userMap[a.user] || null),
|
||||||
|
userMap[task.creator] || null,
|
||||||
|
].filter(Boolean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,16 +3,14 @@
|
||||||
overlay: !overlayMobile,
|
overlay: !overlayMobile,
|
||||||
'overlay-mobile': overlayMobile,
|
'overlay-mobile': overlayMobile,
|
||||||
}"
|
}"
|
||||||
*ngIf="overlayData !== '' && getTaskData(overlayData).length > 0"
|
*ngIf="overlayData !== '' && task != null"
|
||||||
>
|
>
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div
|
<div
|
||||||
class="category"
|
class="category"
|
||||||
[style.background-color]="
|
[style.background-color]="categoryColors.get(task.category)"
|
||||||
categoryColors.get(getTaskData(overlayData)[0].category)
|
|
||||||
"
|
|
||||||
>
|
>
|
||||||
{{ getTaskData(overlayData)[0].category }}
|
{{ task.category }}
|
||||||
</div>
|
</div>
|
||||||
@if (overlayMobile) {
|
@if (overlayMobile) {
|
||||||
<app-btn-back></app-btn-back>
|
<app-btn-back></app-btn-back>
|
||||||
|
|
@ -26,126 +24,104 @@
|
||||||
'content-mobile': overlayMobile,
|
'content-mobile': overlayMobile,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="headline">{{ getTaskData(overlayData)[0].title }}</div>
|
<div class="headline">{{ task.title }}</div>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
{{ getTaskData(overlayData)[0].description }}
|
{{ task.description }}
|
||||||
</div>
|
</div>
|
||||||
<div class="date">
|
<div class="date">
|
||||||
<p>{{ "addTask.date" | translate }}:</p>
|
<p>{{ "addTask.date" | translate }}:</p>
|
||||||
{{ timeConverter(getTaskData(overlayData)[0].date) }}
|
{{ timeConverter(task.date) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="priority">
|
<div class="priority">
|
||||||
<p>{{ "addTask.priority" | translate }}:</p>
|
<p>{{ "addTask.priority" | translate }}:</p>
|
||||||
{{ capitalizeFirstLetter(getTaskData(overlayData)[0].priority) }}
|
{{ capitalizeFirstLetter(task.priority) }}
|
||||||
<div
|
<div class="priority-bg priority-{{ task.priority }}"></div>
|
||||||
class="priority-bg priority-{{ getTaskData(overlayData)[0].priority }}"
|
|
||||||
></div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="creator">
|
<div class="creator">
|
||||||
<p>{{ "addTask.creator" | translate }}:</p>
|
<p>{{ "addTask.creator" | translate }}:</p>
|
||||||
|
@for (user of task.userData; track user) { @if (task.creator === user.id)
|
||||||
|
{
|
||||||
<div class="users">
|
<div class="users">
|
||||||
<div
|
<div
|
||||||
class="circle"
|
class="circle"
|
||||||
[ngStyle]="{
|
[ngStyle]="{
|
||||||
'background-color': firebaseService.getUserDetails(
|
'background-color': user.color
|
||||||
getTaskData(overlayData)[0].creator,
|
|
||||||
'color'
|
|
||||||
)
|
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="initials">
|
<div class="initials">
|
||||||
{{
|
{{ user.initials }}
|
||||||
firebaseService.getUserDetails(
|
|
||||||
getTaskData(overlayData)[0].creator,
|
|
||||||
"initials"
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<p>
|
<p>
|
||||||
{{
|
{{ user.firstName }}
|
||||||
firebaseService.getUserDetails(
|
|
||||||
getTaskData(overlayData)[0].creator,
|
|
||||||
"firstName"
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</p>
|
</p>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<p class="last-name">
|
<p class="last-name">
|
||||||
{{
|
{{ user.lastName }}
|
||||||
firebaseService.getUserDetails(
|
|
||||||
getTaskData(overlayData)[0].creator,
|
|
||||||
"lastName"
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
} }
|
||||||
</div>
|
</div>
|
||||||
@if (getTaskData(overlayData)[0].assigned.length > 0) {
|
@if (task.assignees.length > 0) {
|
||||||
<div class="assigned">
|
<div class="assigned">
|
||||||
<p>{{ "addTask.assigned" | translate }}:</p>
|
<p>{{ "addTask.assigned" | translate }}:</p>
|
||||||
@for (user of getTaskData(overlayData)[0].assigned; track user) {
|
@for (assigned of task.assignees; track assigned.id) { @for (user of
|
||||||
|
task.userData; track user) { @if (assigned.user === user.id) {
|
||||||
<div class="users">
|
<div class="users">
|
||||||
<div
|
<div
|
||||||
class="circle"
|
class="circle"
|
||||||
[ngStyle]="{
|
[ngStyle]="{
|
||||||
'background-color': firebaseService.getUserDetails(user, 'color')
|
'background-color': user.color
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div class="initials">
|
<div class="initials">
|
||||||
{{ firebaseService.getUserDetails(user, "initials") }}
|
{{ user.initials }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="details">
|
<div class="details">
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<p>
|
<p>
|
||||||
{{ firebaseService.getUserDetails(user, "firstName") }}
|
{{ user.firstName }}
|
||||||
</p>
|
</p>
|
||||||
<span> </span>
|
<span> </span>
|
||||||
<p class="last-name">
|
<p class="last-name">
|
||||||
{{ firebaseService.getUserDetails(user, "lastName") }}
|
{{ user.lastName }}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
} } }
|
||||||
</div>
|
</div>
|
||||||
} @if (getTaskData(overlayData)[0].subtasksTitle.length > 0) {
|
} @if (task.subtasks.length > 0) {
|
||||||
<div class="subtasks">
|
<div class="subtasks">
|
||||||
<p>{{ "addTask.subtask" | translate }}:</p>
|
<p>{{ "addTask.subtask" | translate }}:</p>
|
||||||
@for (subtask of getTaskData(overlayData)[0].subtasksTitle; track subtask;
|
@for (subtask of task.subtasks; track subtask; let i = $index) {
|
||||||
let i = $index) {
|
|
||||||
<div
|
<div
|
||||||
class="single-subtask"
|
class="single-subtask"
|
||||||
(click)="
|
(click)="
|
||||||
toggleSubtaskStatus(
|
toggleSubtaskStatus(overlayData, i, task.subtasksDone, subtask.done)
|
||||||
overlayData,
|
|
||||||
i,
|
|
||||||
getTaskData(overlayData)[0].subtasksDone,
|
|
||||||
getSubTaskStatus(overlayData, i)
|
|
||||||
)
|
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
[src]="
|
[src]="
|
||||||
getSubTaskStatus(overlayData, i)
|
subtask.done
|
||||||
? './../../../../../assets/img/board/check-btn-checked.svg'
|
? './../../../../../assets/img/board/check-btn-checked.svg'
|
||||||
: './../../../../../assets/img/board/check-btn-unchecked.svg'
|
: './../../../../../assets/img/board/check-btn-unchecked.svg'
|
||||||
"
|
"
|
||||||
alt=""
|
alt=""
|
||||||
/>
|
/>
|
||||||
<p>{{ subtask }}</p>
|
<p>{{ subtask.title }}</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@if(getTaskData(overlayData)[0].creator ===
|
@if(task.creator === firebaseService.getCurrentUserId()) {
|
||||||
firebaseService.getCurrentUserId()) {
|
|
||||||
<div class="btns">
|
<div class="btns">
|
||||||
<div class="btn btn-delete" (click)="deleteTask(overlayData)">
|
<div class="btn btn-delete" (click)="deleteTask(overlayData)">
|
||||||
<img src="./../../../../../assets/img/contact/delete.svg" alt="" />
|
<img src="./../../../../../assets/img/contact/delete.svg" alt="" />
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ import { OverlayService } from '../../../../services/overlay.service';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { BtnBackComponent } from '../../buttons/btn-back/btn-back.component';
|
import { BtnBackComponent } from '../../buttons/btn-back/btn-back.component';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { Task } from '../../../../interfaces/task.interface';
|
||||||
|
import { TaskService } from '../../../../services/task.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-task-overlay',
|
selector: 'app-task-overlay',
|
||||||
|
|
@ -18,11 +20,13 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
@Input() overlayData: string = '';
|
@Input() overlayData: string = '';
|
||||||
@Output() closeDialogEmitter = new EventEmitter<string>();
|
@Output() closeDialogEmitter = new EventEmitter<string>();
|
||||||
|
|
||||||
|
task: Task | null = null;
|
||||||
overlayMobile: boolean = false;
|
overlayMobile: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public firebaseService: FirebaseService,
|
public firebaseService: FirebaseService,
|
||||||
private overlayService: OverlayService,
|
private overlayService: OverlayService,
|
||||||
|
private taskService: TaskService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute
|
private route: ActivatedRoute
|
||||||
) {}
|
) {}
|
||||||
|
|
@ -40,14 +44,28 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
* Also sets `overlayMobile` to `true` if parameters are successfully retrieved.
|
* Also sets `overlayMobile` to `true` if parameters are successfully retrieved.
|
||||||
*/
|
*/
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
if (this.overlayData == '') {
|
this.setOverlayDataFromRoute();
|
||||||
if (this.route.params.subscribe()) {
|
this.loadTask(this.overlayData);
|
||||||
|
}
|
||||||
|
|
||||||
|
setOverlayDataFromRoute() {
|
||||||
|
if (this.overlayData === '') {
|
||||||
this.route.params.subscribe((params) => {
|
this.route.params.subscribe((params) => {
|
||||||
this.overlayData = params['id'];
|
this.overlayData = params['id'];
|
||||||
this.overlayMobile = true;
|
this.overlayMobile = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loadTask(taskId: string) {
|
||||||
|
this.taskService.loadSingleTask(taskId).subscribe({
|
||||||
|
next: (task) => {
|
||||||
|
this.task = task;
|
||||||
|
},
|
||||||
|
error: (err) => {
|
||||||
|
console.error('Error loading the task:', err);
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -89,40 +107,6 @@ export class TaskOverlayComponent implements OnInit {
|
||||||
this.closeDialog();
|
this.closeDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the task data from the Firebase Realtime Database for the given task id.
|
|
||||||
*
|
|
||||||
* This function takes a task id and returns an array of tasks with the given id.
|
|
||||||
* The function uses the Firebase service to get all tasks from the Realtime Database
|
|
||||||
* and then filters the result to return only the task with the given id.
|
|
||||||
*
|
|
||||||
* @param taskId The id of the task to be retrieved.
|
|
||||||
* @returns {Task[]} An array of tasks with the given id.
|
|
||||||
*/
|
|
||||||
getTaskData(taskId: string) {
|
|
||||||
return this.firebaseService
|
|
||||||
.getAllTasks()
|
|
||||||
.filter((task) => task.id === taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the status of a single subtask of a task.
|
|
||||||
*
|
|
||||||
* This function takes the task id and the index of the subtask
|
|
||||||
* and returns the status of the subtask at the given index.
|
|
||||||
*
|
|
||||||
* @param taskId The task id of the task containing the subtask.
|
|
||||||
* @param index The index of the subtask.
|
|
||||||
* @returns {boolean} The status of the subtask at the given index.
|
|
||||||
*/
|
|
||||||
getSubTaskStatus(taskId: string, index: number) {
|
|
||||||
const subtask = this.firebaseService
|
|
||||||
.getAllTasks()
|
|
||||||
.filter((task) => task.id === taskId);
|
|
||||||
|
|
||||||
return subtask[0].subtasksDone[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the status of a single subtask of a task.
|
* Toggles the status of a single subtask of a task.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue