import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, effect, input, output, signal, } from '@angular/core'; import { MatBadgeModule } from '@angular/material/badge'; import { MatButtonModule } from '@angular/material/button'; import { MatDividerModule } from '@angular/material/divider'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatIconModule } from '@angular/material/icon'; import { CommentResponse, TaskResponse, User } from '@org/shared/api'; import { TaskCommentComponent } from './task-comment.component'; @Component({ selector: 'lib-task-card', imports: [ CommonModule, MatExpansionModule, MatIconModule, MatDividerModule, MatBadgeModule, MatButtonModule, TaskCommentComponent, ], changeDetection: ChangeDetectionStrategy.OnPush, template: ` assignment {{ task().tasks.title }} By {{ getUserName(task().tasks.userId) }} @if (taskComments().length) { comment } {{ formatDate(task().tasks.timestamp) }} {{ task().tasks.description }} forum Comments `, styles: [ ` .task-panel { margin-bottom: 1rem; border-radius: var(--mat-sys-corner-small); box-shadow: var(--mat-sys-level1); transition: all 0.3s ease; } .task-panel:hover { box-shadow: var(--mat-sys-level3); } .task-panel .mat-expansion-panel-header { height: auto; min-height: 64px; padding: 0.75rem 1rem; } .task-title-container { display: flex; align-items: center; gap: 0.5rem; flex: 1; min-width: 0; margin-right: 1rem; } .task-title-container mat-icon { color: #1976d2; } .task-title-container span { font-weight: 500; font-size: 1.1rem; overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; } .task-info { display: flex; flex-direction: column; align-items: flex-end; gap: 0.25rem; min-width: 150px; text-align: right; } .task-info-row { display: flex; align-items: center; gap: 0.5rem; justify-content: flex-end; margin-top: 0.5rem; } .task-author { font-weight: 500; color: #424242; } .task-timestamp { font-size: 0.8rem; color: var(--mat-sys-on-surface-variant); } .task-details { padding: 1rem 0; } .task-description { font-size: var(--mat-sys-body-large-size); line-height: 1.6; margin-bottom: 1.5rem; white-space: pre-line; color: var(--mat-sys-on-surface); background-color: var(--mat-sys-surface-container-low); padding: 1rem; border-radius: var(--mat-sys-corner-small); border-left: 4px solid var(--mat-sys-primary); } .comments-section { margin-top: 1.5rem; } .comments-section h3 { display: flex; align-items: center; gap: 0.5rem; font-size: var(--mat-sys-title-medium-size); margin-bottom: 1rem; color: var(--mat-sys-on-surface); } .comments-section h3 mat-icon { color: #1976d2; } @media (max-width: 768px) { .task-info { align-items: flex-start; } } `, ], }) export class TaskCardComponent { readonly task = input.required(); readonly users = input([]); readonly comments = input([]); readonly addingComment = input(false); readonly commentAdded = output<{ taskId: number; content: string; userId: number; }>(); readonly taskComments = signal([]); constructor() { // Update task comments whenever comments or task changes effect(() => { const taskId = this.task()?.tasks?.id; if (taskId && this.comments()) { this.taskComments.set( this.comments().filter( (comment) => comment.comments.taskId === taskId ) ); } }); } getUserName(userId: number): string { const user = this.users().find((u) => u.id === userId); return user ? user.name : 'Unknown User'; } formatDate(timestamp?: string): string { if (!timestamp) return 'Unknown date'; const date = new Date(timestamp); const now = new Date(); const diffMs = now.getTime() - date.getTime(); const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); if (diffDays === 0) { return ( 'Today at ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) ); } else if (diffDays === 1) { return ( 'Yesterday at ' + date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) ); } else if (diffDays < 7) { return `${diffDays} days ago`; } else { return date.toLocaleDateString([], { day: 'numeric', month: 'short', year: 'numeric', }); } } handleAddComment(commentData: { content: string; userId: number }) { this.commentAdded.emit({ taskId: this.task().tasks.id, ...commentData, }); } }
{{ task().tasks.description }}