feat: integrate moveTask functionality into TaskMenuComponent
This commit is contained in:
parent
2632f859fe
commit
00b811afbd
7 changed files with 129 additions and 51 deletions
|
|
@ -57,7 +57,10 @@
|
|||
<div id="todo" class="details">
|
||||
<!-- Loop through 'todo' tasks and display them -->
|
||||
@for (task of filteredTasks[TODO]; track task.id) {
|
||||
<app-task [task]="task"></app-task>
|
||||
<app-task
|
||||
[task]="task"
|
||||
(updateStatusEmitter)="onStatusUpdate($event)"
|
||||
></app-task>
|
||||
|
||||
<!-- Show empty state if no 'todo' tasks exist -->
|
||||
} @empty {
|
||||
|
|
@ -90,7 +93,10 @@
|
|||
<div id="inprogress" class="details">
|
||||
<!-- Loop through 'in progress' tasks and display them -->
|
||||
@for (task of filteredTasks[IN_PROGRESS]; track task.id) {
|
||||
<app-task [task]="task"></app-task>
|
||||
<app-task
|
||||
[task]="task"
|
||||
(updateStatusEmitter)="onStatusUpdate($event)"
|
||||
></app-task>
|
||||
|
||||
<!-- Show empty state if no 'in progress' tasks exist -->
|
||||
} @empty {
|
||||
|
|
@ -123,7 +129,10 @@
|
|||
<div id="awaitfeedback" class="details">
|
||||
<!-- Loop through 'await feedback' tasks and display them -->
|
||||
@for (task of filteredTasks[AWAIT_FEEDBACK]; track task.id) {
|
||||
<app-task [task]="task"></app-task>
|
||||
<app-task
|
||||
[task]="task"
|
||||
(updateStatusEmitter)="onStatusUpdate($event)"
|
||||
></app-task>
|
||||
|
||||
<!-- Show empty state if no 'await feedback' tasks exist -->
|
||||
} @empty {
|
||||
|
|
@ -157,7 +166,10 @@
|
|||
<div id="done" class="details">
|
||||
<!-- Loop through 'done' tasks and display them -->
|
||||
@for (task of filteredTasks[DONE]; track task.id) {
|
||||
<app-task [task]="task"></app-task>
|
||||
<app-task
|
||||
[task]="task"
|
||||
(updateStatusEmitter)="onStatusUpdate($event)"
|
||||
></app-task>
|
||||
|
||||
<!-- Show empty state if no 'done' tasks exist -->
|
||||
} @empty {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { Router } from '@angular/router';
|
|||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { TaskHighlightedComponent } from './task/task-highlighted/task-highlighted.component';
|
||||
import { ApiService } from '../../services/api.service';
|
||||
import { Task } from '../../interfaces/task.interface';
|
||||
import { Task, TaskMoveEvent } from '../../interfaces/task.interface';
|
||||
import { TaskService } from '../../services/task.service';
|
||||
import { LoadingSpinnerComponent } from '../../shared/components/loading-spinner/loading-spinner.component';
|
||||
import { debounceTime, finalize, Subject, take, takeUntil } from 'rxjs';
|
||||
|
|
@ -38,13 +38,13 @@ export class BoardComponent implements OnInit, OnDestroy {
|
|||
readonly AWAIT_FEEDBACK = 'awaitfeedback';
|
||||
readonly DONE = 'done';
|
||||
|
||||
allTasks: Task[] = [];
|
||||
allTasks: Array<Task> = [];
|
||||
filteredTasks: { [key: string]: Task[] } = {};
|
||||
|
||||
searchValue: string = '';
|
||||
searchInput: boolean = false;
|
||||
taskMovedTo: string = '';
|
||||
taskMovedFrom: string = '';
|
||||
taskMovedTo = '';
|
||||
taskMovedFrom = '';
|
||||
searchValue = '';
|
||||
searchInput = false;
|
||||
isLoading = false;
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
|
@ -151,6 +151,14 @@ export class BoardComponent implements OnInit, OnDestroy {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the status of a task when its status is changed.
|
||||
* @param event The event containing the task and the new status to move to.
|
||||
*/
|
||||
onStatusUpdate(event: TaskMoveEvent) {
|
||||
this.handleItemDropped(event.task, event.moveTo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the event when an item is dropped on a column.
|
||||
* @param taskId The id of the task being moved.
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
<section>
|
||||
@if (boardTaskStatus !== 'todo') {
|
||||
<div class="link" (click)="moveTask('todo')">To do</div>
|
||||
} @if (boardTaskStatus !== 'inprogress') {
|
||||
<div class="link" (click)="moveTask('inprogress')">In progress</div>
|
||||
} @if (boardTaskStatus !== 'awaitfeedback') {
|
||||
<div class="link" (click)="moveTask('awaitfeedback')">Await feedback</div>
|
||||
} @if (boardTaskStatus !== 'done') {
|
||||
<div class="link" (click)="moveTask('done')">Done</div>
|
||||
@if (boardTaskStatus !== TODO) {
|
||||
<div class="link" (click)="moveTask(TODO)">To do</div>
|
||||
} @if (boardTaskStatus !== IN_PROGRESS) {
|
||||
<div class="link" (click)="moveTask(IN_PROGRESS)">In progress</div>
|
||||
} @if (boardTaskStatus !== AWAIT_FEEDBACK) {
|
||||
<div class="link" (click)="moveTask(AWAIT_FEEDBACK)">Await feedback</div>
|
||||
} @if (boardTaskStatus !== DONE) {
|
||||
<div class="link" (click)="moveTask(DONE)">Done</div>
|
||||
}
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { Task, TaskMoveEvent } from '../../../../interfaces/task.interface';
|
||||
|
||||
@Component({
|
||||
selector: 'app-task-menu',
|
||||
|
|
@ -8,22 +9,19 @@ import { Component, Input } from '@angular/core';
|
|||
styleUrl: './task-menu.component.scss',
|
||||
})
|
||||
export class TaskMenuComponent {
|
||||
@Input() taskId: string = '';
|
||||
@Input() boardTaskStatus: string = '';
|
||||
@Input() task!: Task;
|
||||
@Input() boardTaskStatus!: string;
|
||||
@Output() updateStatusEmitter = new EventEmitter<TaskMoveEvent>();
|
||||
|
||||
constructor() {}
|
||||
readonly TODO = 'todo';
|
||||
readonly IN_PROGRESS = 'inprogress';
|
||||
readonly AWAIT_FEEDBACK = 'awaitfeedback';
|
||||
readonly DONE = 'done';
|
||||
|
||||
/**
|
||||
* Moves the task to a specified status.
|
||||
*
|
||||
* This function updates the status of the task identified by `taskId`
|
||||
* in both `allTasks` and `filteredTasks` lists to the new status
|
||||
* specified by `moveTo`. It also updates the task status in the
|
||||
* Firestore database.
|
||||
*
|
||||
* @param moveTo - The new status to move the task to.
|
||||
*/
|
||||
moveTask(moveTo: string) {
|
||||
// TODO
|
||||
this.updateStatusEmitter.emit({
|
||||
task: this.task,
|
||||
moveTo: moveTo,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
<section>
|
||||
@if (task.id) {
|
||||
<div (click)="handleMenuButtonClick($event, task.id)">
|
||||
{{ disableDrag }}
|
||||
<div
|
||||
class="content"
|
||||
draggable="true"
|
||||
(dragstart)="dragDropService.startDragging($event, task)"
|
||||
[draggable]="disableDrag"
|
||||
(dragstart)="
|
||||
disableDrag ? dragDropService.startDragging($event, task) : null
|
||||
"
|
||||
>
|
||||
<div class="header">
|
||||
<div
|
||||
|
|
@ -65,10 +68,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@if (isMenuOpen){
|
||||
@if (menuOpen){
|
||||
<app-task-menu
|
||||
[taskId]="task.id"
|
||||
[task]="task"
|
||||
[boardTaskStatus]="task.status"
|
||||
(updateStatusEmitter)="onStatusUpdate($event)"
|
||||
></app-task-menu>
|
||||
} @if (AssignedDialogId != '') {
|
||||
<div class="dialog" [style.left.px]="dialogX" [style.top.px]="dialogY">
|
||||
|
|
|
|||
|
|
@ -1,7 +1,17 @@
|
|||
import { CommonModule } from '@angular/common';
|
||||
import { Component, HostListener, Input } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
EventEmitter,
|
||||
HostListener,
|
||||
Input,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { DragDropService } from '../../../services/drag-drop.service';
|
||||
import { Task } from '../../../interfaces/task.interface';
|
||||
import {
|
||||
Assignee,
|
||||
Task,
|
||||
TaskMoveEvent,
|
||||
} from '../../../interfaces/task.interface';
|
||||
import { OverlayService } from '../../../services/overlay.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { TaskMenuComponent } from './task-menu/task-menu.component';
|
||||
|
|
@ -16,15 +26,13 @@ import { take } from 'rxjs';
|
|||
styleUrl: './task.component.scss',
|
||||
})
|
||||
export class TaskComponent {
|
||||
@Input() task: Task = {} as Task;
|
||||
@Input() task!: Task;
|
||||
@Output() updateStatusEmitter = new EventEmitter<TaskMoveEvent>();
|
||||
|
||||
isMenuOpen: boolean = false;
|
||||
AssignedDialogId: string = '';
|
||||
dialogX: number = 0;
|
||||
dialogY: number = 0;
|
||||
readonly DISABLE_DRAG_BREAKPOINT = 667;
|
||||
readonly DIALOG_OFFSET_X = 25;
|
||||
readonly DIALOG_OFFSET_Y = 10;
|
||||
|
||||
creator: any = '';
|
||||
assignees: any[] = [];
|
||||
categoryColors = new Map<string, string>([
|
||||
['User Story', '#0038ff'],
|
||||
['Technical Task', '#20d7c2'],
|
||||
|
|
@ -32,6 +40,15 @@ export class TaskComponent {
|
|||
|
||||
pageViewMedia$ = this.resizeService.pageViewMedia$;
|
||||
|
||||
menuOpen = false;
|
||||
disableDrag = false;
|
||||
AssignedDialogId = '';
|
||||
dialogX = 0;
|
||||
dialogY = 0;
|
||||
|
||||
creator = '';
|
||||
assignees: Assignee[] = [];
|
||||
|
||||
constructor(
|
||||
public dragDropService: DragDropService,
|
||||
public overlayService: OverlayService,
|
||||
|
|
@ -39,6 +56,20 @@ export class TaskComponent {
|
|||
private router: Router
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Sets the initial state of the `disableDrag` property based on the window width.
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
this.updateDisableDragStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the `disableDrag` property based on the current window width.
|
||||
*/
|
||||
private updateDisableDragStatus(): void {
|
||||
this.disableDrag = window.innerWidth > this.DISABLE_DRAG_BREAKPOINT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the button click event on a task in the board
|
||||
* @param event the MouseEvent
|
||||
|
|
@ -60,7 +91,7 @@ export class TaskComponent {
|
|||
* Toggle the task menu for the current task
|
||||
*/
|
||||
toggleTaskMenu() {
|
||||
this.isMenuOpen = !this.isMenuOpen;
|
||||
this.menuOpen = !this.menuOpen;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -72,7 +103,7 @@ export class TaskComponent {
|
|||
* If the page is not in the media view, open the task overlay
|
||||
*/
|
||||
openTaskDetailsOverlay(taskId: string) {
|
||||
if (this.isMenuOpen) {
|
||||
if (this.menuOpen) {
|
||||
this.toggleTaskMenu();
|
||||
}
|
||||
this.pageViewMedia$.pipe(take(1)).subscribe((isPageViewMedia) => {
|
||||
|
|
@ -96,7 +127,7 @@ export class TaskComponent {
|
|||
);
|
||||
|
||||
if (!isMenuClicked) {
|
||||
this.isMenuOpen = false;
|
||||
this.menuOpen = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -117,8 +148,8 @@ export class TaskComponent {
|
|||
* @param event the MouseEvent that triggered the dialog
|
||||
*/
|
||||
updateDialogPosition(event: MouseEvent) {
|
||||
this.dialogX = event.clientX + 25;
|
||||
this.dialogY = event.clientY + 10;
|
||||
this.dialogX = event.clientX + this.DIALOG_OFFSET_X;
|
||||
this.dialogY = event.clientY + this.DIALOG_OFFSET_Y;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -149,4 +180,24 @@ export class TaskComponent {
|
|||
|
||||
return (completedSubtasksCount / this.task.subtasks.length) * 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emits an event to update the status of a task.
|
||||
* @param event The TaskMoveEvent containing the task and the new status to move to.
|
||||
*/
|
||||
onStatusUpdate(event: TaskMoveEvent) {
|
||||
this.updateStatusEmitter.emit({
|
||||
task: event.task,
|
||||
moveTo: event.moveTo,
|
||||
});
|
||||
}
|
||||
|
||||
@HostListener('window:resize')
|
||||
/**
|
||||
* Called when the window is resized.
|
||||
* Updates the disableDragStatus so that tasks are not draggable on mobile devices.
|
||||
*/
|
||||
onResize() {
|
||||
this.updateDisableDragStatus();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,3 +24,8 @@ export interface Assignee {
|
|||
id?: string;
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export interface TaskMoveEvent {
|
||||
task: Task;
|
||||
moveTo: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue