mirror of
https://github.com/a-mayb3/KanbanCloneAngular.git
synced 2026-03-21 09:55:37 +01:00
Added completion status in task item
This commit is contained in:
parent
a7f506b873
commit
f7f12356de
4 changed files with 139 additions and 16 deletions
|
|
@ -3,11 +3,59 @@
|
|||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
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 {
|
||||
margin: 0 0 6px 0;
|
||||
color: #111827;
|
||||
|
|
@ -19,6 +67,10 @@
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
.task-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.status {
|
||||
align-self: flex-start;
|
||||
padding: 4px 10px;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,20 @@
|
|||
<h4>{{ task.title }}</h4>
|
||||
<p>{{ task.description || 'No description.' }}</p>
|
||||
</div>
|
||||
<span class="status" [ngClass]="'status-' + task.status.toLowerCase()">
|
||||
{{ task.status.replace('_', ' ') }}
|
||||
</span>
|
||||
<div class="task-meta">
|
||||
<label class="status-label" for="status-{{ task.id }}">Status</label>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,62 @@
|
|||
import { Component, Input } from '@angular/core';
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { Task } from '../../models/tasks.models';
|
||||
|
||||
@Component({
|
||||
selector: 'app-task-item',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
imports: [CommonModule, FormsModule],
|
||||
templateUrl: './task-item.component.html',
|
||||
styleUrl: './task-item.component.css',
|
||||
})
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,19 @@
|
|||
import { User } from "./auth.models";
|
||||
import { Task } from "./tasks.models";
|
||||
import { User } from './auth.models';
|
||||
import { Task } from './tasks.models';
|
||||
|
||||
export interface Project {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
tasks?: Task[];
|
||||
}
|
||||
|
||||
export interface ProjectFull {
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
tasks: Task[];
|
||||
users: User[];
|
||||
id: number;
|
||||
name: string;
|
||||
description?: string;
|
||||
tasks: Task[];
|
||||
users: User[];
|
||||
}
|
||||
|
||||
export interface CreateProjectRequest {
|
||||
|
|
@ -23,4 +24,13 @@ export interface CreateProjectRequest {
|
|||
export interface UpdateProjectRequest {
|
||||
name?: string;
|
||||
description?: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface AddCollaboratorRequest {
|
||||
user_email: string;
|
||||
}
|
||||
|
||||
export interface AddCollaboratorResponse {
|
||||
success?: boolean;
|
||||
message?: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue