Added completion status in task item

This commit is contained in:
Marta Borgia Leiva 2026-02-10 13:51:02 +01:00
parent a7f506b873
commit f7f12356de
4 changed files with 139 additions and 16 deletions

View file

@ -3,11 +3,59 @@
border-radius: 10px; border-radius: 10px;
padding: 16px; padding: 16px;
display: flex; display: flex;
flex-direction: column; flex-direction: row;
gap: 12px; align-items: center;
justify-content: space-between;
gap: 16px;
background-color: #f9fafb; background-color: #f9fafb;
} }
.task-meta {
display: flex;
flex-direction: row;
align-items: center;
flex-wrap: wrap;
gap: 6px;
}
.status-label {
font-size: 12px;
font-weight: 600;
color: #4b5563;
text-transform: uppercase;
letter-spacing: 0.04em;
}
.status-select {
padding: 6px 10px;
border-radius: 8px;
border: 1px solid #e5e7eb;
background-color: #ffffff;
font-size: 12px;
color: #374151;
min-width: 140px;
height: 32px;
}
.btn-remove {
width: 32px;
height: 32px;
border-radius: 8px;
border: 1px solid #fecaca;
background: #ffffff;
color: #b91c1c;
font-weight: 700;
cursor: pointer;
transition:
background-color 0.2s ease,
border-color 0.2s ease;
}
.btn-remove:hover {
background-color: #fee2e2;
border-color: #fca5a5;
}
.task-info h4 { .task-info h4 {
margin: 0 0 6px 0; margin: 0 0 6px 0;
color: #111827; color: #111827;
@ -19,6 +67,10 @@
font-size: 14px; font-size: 14px;
} }
.task-info {
flex: 1;
}
.status { .status {
align-self: flex-start; align-self: flex-start;
padding: 4px 10px; padding: 4px 10px;

View file

@ -3,7 +3,20 @@
<h4>{{ task.title }}</h4> <h4>{{ task.title }}</h4>
<p>{{ task.description || 'No description.' }}</p> <p>{{ task.description || 'No description.' }}</p>
</div> </div>
<span class="status" [ngClass]="'status-' + task.status.toLowerCase()"> <div class="task-meta">
{{ task.status.replace('_', ' ') }} <label class="status-label" for="status-{{ task.id }}">Status</label>
</span> <select
id="status-{{ task.id }}"
class="status-select"
[(ngModel)]="statusValue"
(ngModelChange)="onStatusChange($event)"
>
@for (status of statusOptions; track status) {
<option [value]="status">{{ status.replace('_', ' ') }}</option>
}
</select>
<button class="btn-remove" type="button" aria-label="Remove task" (click)="onRemove()">
x
</button>
</div>
</article> </article>

View file

@ -1,14 +1,62 @@
import { Component, Input } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common'; import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { Task } from '../../models/tasks.models'; import { Task } from '../../models/tasks.models';
@Component({ @Component({
selector: 'app-task-item', selector: 'app-task-item',
standalone: true, standalone: true,
imports: [CommonModule], imports: [CommonModule, FormsModule],
templateUrl: './task-item.component.html', templateUrl: './task-item.component.html',
styleUrl: './task-item.component.css', styleUrl: './task-item.component.css',
}) })
export class TaskItemComponent { export class TaskItemComponent {
@Input({ required: true }) task!: Task; private _task!: Task;
statusValue: Task['status'] = 'pending';
@Input({ required: true })
set task(value: Task) {
this._task = value;
this.statusValue = value?.status ?? 'pending';
}
get task(): Task {
return this._task;
}
@Output() statusChange = new EventEmitter<{
task: Task;
status: Task['status'];
previousStatus: Task['status'];
}>();
@Output() remove = new EventEmitter<Task>();
readonly statusOptions: Task['status'][] = [
'pending',
'in_progress',
'completed',
'stashed',
'failed',
];
onStatusChange(value: Task['status']) {
const previousStatus = this.statusValue;
const nextStatus = value;
this.statusValue = nextStatus;
if (this._task) {
this._task.status = nextStatus;
this.statusChange.emit({
task: this._task,
status: nextStatus,
previousStatus,
});
}
}
onRemove() {
if (this._task) {
this.remove.emit(this._task);
}
}
} }

View file

@ -1,10 +1,11 @@
import { User } from "./auth.models"; import { User } from './auth.models';
import { Task } from "./tasks.models"; import { Task } from './tasks.models';
export interface Project { export interface Project {
id: number; id: number;
name: string; name: string;
description?: string; description?: string;
tasks?: Task[];
} }
export interface ProjectFull { export interface ProjectFull {
@ -24,3 +25,12 @@ export interface UpdateProjectRequest {
name?: string; name?: string;
description?: string; description?: string;
} }
export interface AddCollaboratorRequest {
user_email: string;
}
export interface AddCollaboratorResponse {
success?: boolean;
message?: string;
}