diff --git a/src/app/components/board/board.component.html b/src/app/components/board/board.component.html index c694674..1df170f 100644 --- a/src/app/components/board/board.component.html +++ b/src/app/components/board/board.component.html @@ -57,7 +57,10 @@
@for (task of filteredTasks[TODO]; track task.id) { - + } @empty { @@ -90,7 +93,10 @@
@for (task of filteredTasks[IN_PROGRESS]; track task.id) { - + } @empty { @@ -123,7 +129,10 @@
@for (task of filteredTasks[AWAIT_FEEDBACK]; track task.id) { - + } @empty { @@ -157,7 +166,10 @@
@for (task of filteredTasks[DONE]; track task.id) { - + } @empty { diff --git a/src/app/components/board/board.component.ts b/src/app/components/board/board.component.ts index 3553ad8..43b477b 100644 --- a/src/app/components/board/board.component.ts +++ b/src/app/components/board/board.component.ts @@ -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 = []; filteredTasks: { [key: string]: Task[] } = {}; - searchValue: string = ''; - searchInput: boolean = false; - taskMovedTo: string = ''; - taskMovedFrom: string = ''; + taskMovedTo = ''; + taskMovedFrom = ''; + searchValue = ''; + searchInput = false; isLoading = false; private destroy$ = new Subject(); @@ -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. diff --git a/src/app/components/board/task/task-menu/task-menu.component.html b/src/app/components/board/task/task-menu/task-menu.component.html index b6f8f9a..68e4f62 100644 --- a/src/app/components/board/task/task-menu/task-menu.component.html +++ b/src/app/components/board/task/task-menu/task-menu.component.html @@ -1,11 +1,11 @@
- @if (boardTaskStatus !== 'todo') { - - } @if (boardTaskStatus !== 'inprogress') { - - } @if (boardTaskStatus !== 'awaitfeedback') { - - } @if (boardTaskStatus !== 'done') { - + @if (boardTaskStatus !== TODO) { + + } @if (boardTaskStatus !== IN_PROGRESS) { + + } @if (boardTaskStatus !== AWAIT_FEEDBACK) { + + } @if (boardTaskStatus !== DONE) { + }
diff --git a/src/app/components/board/task/task-menu/task-menu.component.ts b/src/app/components/board/task/task-menu/task-menu.component.ts index 67f17b6..36519a3 100644 --- a/src/app/components/board/task/task-menu/task-menu.component.ts +++ b/src/app/components/board/task/task-menu/task-menu.component.ts @@ -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(); - 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, + }); } } diff --git a/src/app/components/board/task/task.component.html b/src/app/components/board/task/task.component.html index 031e5b1..435c81d 100644 --- a/src/app/components/board/task/task.component.html +++ b/src/app/components/board/task/task.component.html @@ -1,10 +1,13 @@
@if (task.id) {
+ {{ disableDrag }}
- @if (isMenuOpen){ + @if (menuOpen){ } @if (AssignedDialogId != '') {
diff --git a/src/app/components/board/task/task.component.ts b/src/app/components/board/task/task.component.ts index 29f6f08..7201912 100644 --- a/src/app/components/board/task/task.component.ts +++ b/src/app/components/board/task/task.component.ts @@ -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(); - 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([ ['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(); + } } diff --git a/src/app/interfaces/task.interface.ts b/src/app/interfaces/task.interface.ts index 0280943..93997db 100644 --- a/src/app/interfaces/task.interface.ts +++ b/src/app/interfaces/task.interface.ts @@ -24,3 +24,8 @@ export interface Assignee { id?: string; userId: string; } + +export interface TaskMoveEvent { + task: Task; + moveTo: string; +}