feat: enhance Kanban functionality and update TODO.md
- Completed the creation and validation forms for tasks in the Kanban board, improving task management capabilities. - Integrated new task creation and deletion functionalities in the `KanbanBoard` and `KanbanColumn` components. - Added quick task addition feature in `Column` component for better user experience. - Updated `TaskCard` to support task deletion with a new button. - Marked several tasks as completed in `TODO.md` to reflect the progress on Kanban features. - Updated TypeScript types to include 'manual' as a new task source.
This commit is contained in:
72
clients/base/http-client.ts
Normal file
72
clients/base/http-client.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* Client HTTP de base pour toutes les requêtes API
|
||||
*/
|
||||
export class HttpClient {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor(baseUrl: string = '') {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
|
||||
private async request<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
|
||||
const config: RequestInit = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
},
|
||||
...options,
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(url, config);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
console.error(`HTTP Request failed: ${url}`, error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async get<T>(endpoint: string, params?: Record<string, string>): Promise<T> {
|
||||
const url = params
|
||||
? `${endpoint}?${new URLSearchParams(params)}`
|
||||
: endpoint;
|
||||
|
||||
return this.request<T>(url, { method: 'GET' });
|
||||
}
|
||||
|
||||
async post<T>(endpoint: string, data?: unknown): Promise<T> {
|
||||
return this.request<T>(endpoint, {
|
||||
method: 'POST',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
async patch<T>(endpoint: string, data?: unknown): Promise<T> {
|
||||
return this.request<T>(endpoint, {
|
||||
method: 'PATCH',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
});
|
||||
}
|
||||
|
||||
async delete<T>(endpoint: string, params?: Record<string, string>): Promise<T> {
|
||||
const url = params
|
||||
? `${endpoint}?${new URLSearchParams(params)}`
|
||||
: endpoint;
|
||||
|
||||
return this.request<T>(url, { method: 'DELETE' });
|
||||
}
|
||||
}
|
||||
|
||||
// Instance par défaut
|
||||
export const httpClient = new HttpClient('/api');
|
||||
114
clients/tasks-client.ts
Normal file
114
clients/tasks-client.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { httpClient } from './base/http-client';
|
||||
import { Task, TaskStatus, TaskPriority } from '@/lib/types';
|
||||
|
||||
export interface TaskFilters {
|
||||
status?: TaskStatus[];
|
||||
source?: string[];
|
||||
search?: string;
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
}
|
||||
|
||||
export interface TasksResponse {
|
||||
success: boolean;
|
||||
data: Task[];
|
||||
stats: {
|
||||
total: number;
|
||||
completed: number;
|
||||
inProgress: number;
|
||||
todo: number;
|
||||
completionRate: number;
|
||||
};
|
||||
count: number;
|
||||
}
|
||||
|
||||
export interface CreateTaskData {
|
||||
title: string;
|
||||
description?: string;
|
||||
status?: TaskStatus;
|
||||
priority?: TaskPriority;
|
||||
tags?: string[];
|
||||
dueDate?: Date;
|
||||
}
|
||||
|
||||
export interface UpdateTaskData {
|
||||
taskId: string;
|
||||
title?: string;
|
||||
description?: string;
|
||||
status?: TaskStatus;
|
||||
priority?: TaskPriority;
|
||||
tags?: string[];
|
||||
dueDate?: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client pour la gestion des tâches
|
||||
*/
|
||||
export class TasksClient {
|
||||
|
||||
/**
|
||||
* Récupère toutes les tâches avec filtres
|
||||
*/
|
||||
async getTasks(filters?: TaskFilters): Promise<TasksResponse> {
|
||||
const params: Record<string, string> = {};
|
||||
|
||||
if (filters?.status) {
|
||||
params.status = filters.status.join(',');
|
||||
}
|
||||
if (filters?.source) {
|
||||
params.source = filters.source.join(',');
|
||||
}
|
||||
if (filters?.search) {
|
||||
params.search = filters.search;
|
||||
}
|
||||
if (filters?.limit) {
|
||||
params.limit = filters.limit.toString();
|
||||
}
|
||||
if (filters?.offset) {
|
||||
params.offset = filters.offset.toString();
|
||||
}
|
||||
|
||||
return httpClient.get<TasksResponse>('/tasks', params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Crée une nouvelle tâche
|
||||
*/
|
||||
async createTask(data: CreateTaskData): Promise<{ success: boolean; data: Task; message: string }> {
|
||||
const payload = {
|
||||
...data,
|
||||
dueDate: data.dueDate?.toISOString()
|
||||
};
|
||||
|
||||
return httpClient.post('/tasks', payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour une tâche
|
||||
*/
|
||||
async updateTask(data: UpdateTaskData): Promise<{ success: boolean; data: Task; message: string }> {
|
||||
const payload = {
|
||||
...data,
|
||||
dueDate: data.dueDate?.toISOString()
|
||||
};
|
||||
|
||||
return httpClient.patch('/tasks', payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Supprime une tâche
|
||||
*/
|
||||
async deleteTask(taskId: string): Promise<{ success: boolean; message: string }> {
|
||||
return httpClient.delete('/tasks', { taskId });
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour le statut d'une tâche
|
||||
*/
|
||||
async updateTaskStatus(taskId: string, status: TaskStatus): Promise<{ success: boolean; data: Task; message: string }> {
|
||||
return this.updateTask({ taskId, status });
|
||||
}
|
||||
}
|
||||
|
||||
// Instance singleton
|
||||
export const tasksClient = new TasksClient();
|
||||
Reference in New Issue
Block a user