feat: complete tag management and UI integration
- Marked multiple tasks as completed in TODO.md related to tag management features. - Replaced manual tag input with `TagInput` component in `CreateTaskForm`, `EditTaskForm`, and `QuickAddTask` for better UX. - Updated `TaskCard` to display tags using `TagDisplay` with color support. - Enhanced `TasksService` to manage task-tag relationships with CRUD operations. - Integrated tag management into the global context for better accessibility across components.
This commit is contained in:
@@ -31,6 +31,13 @@ export class TasksService {
|
||||
|
||||
const tasks = await prisma.task.findMany({
|
||||
where,
|
||||
include: {
|
||||
taskTags: {
|
||||
include: {
|
||||
tag: true
|
||||
}
|
||||
}
|
||||
},
|
||||
take: filters?.limit || 100,
|
||||
skip: filters?.offset || 0,
|
||||
orderBy: [
|
||||
@@ -60,19 +67,37 @@ export class TasksService {
|
||||
description: taskData.description,
|
||||
status: taskData.status || 'todo',
|
||||
priority: taskData.priority || 'medium',
|
||||
tagsJson: JSON.stringify(taskData.tags || []),
|
||||
dueDate: taskData.dueDate,
|
||||
source: 'manual', // Source manuelle
|
||||
sourceId: `manual-${Date.now()}` // ID unique
|
||||
},
|
||||
include: {
|
||||
taskTags: {
|
||||
include: {
|
||||
tag: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Gérer les tags
|
||||
// Créer les relations avec les tags
|
||||
if (taskData.tags && taskData.tags.length > 0) {
|
||||
await this.processTags(taskData.tags);
|
||||
await this.createTaskTagRelations(task.id, taskData.tags);
|
||||
}
|
||||
|
||||
return this.mapPrismaTaskToTask(task);
|
||||
// Récupérer la tâche avec les tags pour le retour
|
||||
const taskWithTags = await prisma.task.findUnique({
|
||||
where: { id: task.id },
|
||||
include: {
|
||||
taskTags: {
|
||||
include: {
|
||||
tag: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return this.mapPrismaTaskToTask(taskWithTags!);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,9 +129,6 @@ export class TasksService {
|
||||
updatedAt: new Date()
|
||||
};
|
||||
|
||||
if (updates.tags) {
|
||||
updateData.tagsJson = JSON.stringify(updates.tags);
|
||||
}
|
||||
|
||||
if (updates.status === 'done' && !task.completedAt) {
|
||||
updateData.completedAt = new Date();
|
||||
@@ -114,17 +136,29 @@ export class TasksService {
|
||||
updateData.completedAt = null;
|
||||
}
|
||||
|
||||
const updatedTask = await prisma.task.update({
|
||||
await prisma.task.update({
|
||||
where: { id: taskId },
|
||||
data: updateData
|
||||
});
|
||||
|
||||
// Gérer les tags
|
||||
if (updates.tags && updates.tags.length > 0) {
|
||||
await this.processTags(updates.tags);
|
||||
// Mettre à jour les relations avec les tags
|
||||
if (updates.tags !== undefined) {
|
||||
await this.updateTaskTagRelations(taskId, updates.tags);
|
||||
}
|
||||
|
||||
return this.mapPrismaTaskToTask(updatedTask);
|
||||
// Récupérer la tâche avec les tags pour le retour
|
||||
const taskWithTags = await prisma.task.findUnique({
|
||||
where: { id: taskId },
|
||||
include: {
|
||||
taskTags: {
|
||||
include: {
|
||||
tag: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return this.mapPrismaTaskToTask(taskWithTags!);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -174,12 +208,13 @@ export class TasksService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Traite et crée les tags s'ils n'existent pas
|
||||
* Crée les relations TaskTag pour une tâche
|
||||
*/
|
||||
private async processTags(tagNames: string[]): Promise<void> {
|
||||
private async createTaskTagRelations(taskId: string, tagNames: string[]): Promise<void> {
|
||||
for (const tagName of tagNames) {
|
||||
try {
|
||||
await prisma.tag.upsert({
|
||||
// Créer ou récupérer le tag
|
||||
const tag = await prisma.tag.upsert({
|
||||
where: { name: tagName },
|
||||
update: {}, // Pas de mise à jour nécessaire
|
||||
create: {
|
||||
@@ -187,12 +222,42 @@ export class TasksService {
|
||||
color: this.generateTagColor(tagName)
|
||||
}
|
||||
});
|
||||
|
||||
// Créer la relation TaskTag si elle n'existe pas
|
||||
await prisma.taskTag.upsert({
|
||||
where: {
|
||||
taskId_tagId: {
|
||||
taskId: taskId,
|
||||
tagId: tag.id
|
||||
}
|
||||
},
|
||||
update: {}, // Pas de mise à jour nécessaire
|
||||
create: {
|
||||
taskId: taskId,
|
||||
tagId: tag.id
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`Erreur lors de la création du tag ${tagName}:`, error);
|
||||
console.error(`Erreur lors de la création de la relation tag ${tagName}:`, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Met à jour les relations TaskTag pour une tâche
|
||||
*/
|
||||
private async updateTaskTagRelations(taskId: string, tagNames: string[]): Promise<void> {
|
||||
// Supprimer toutes les relations existantes
|
||||
await prisma.taskTag.deleteMany({
|
||||
where: { taskId: taskId }
|
||||
});
|
||||
|
||||
// Créer les nouvelles relations
|
||||
if (tagNames.length > 0) {
|
||||
await this.createTaskTagRelations(taskId, tagNames);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Génère une couleur pour un tag basée sur son nom
|
||||
*/
|
||||
@@ -216,7 +281,23 @@ export class TasksService {
|
||||
/**
|
||||
* Convertit une tâche Prisma en objet Task
|
||||
*/
|
||||
private mapPrismaTaskToTask(prismaTask: Prisma.TaskGetPayload<object>): Task {
|
||||
private mapPrismaTaskToTask(prismaTask: Prisma.TaskGetPayload<{
|
||||
include: {
|
||||
taskTags: {
|
||||
include: {
|
||||
tag: true
|
||||
}
|
||||
}
|
||||
}
|
||||
}> | Prisma.TaskGetPayload<object>): Task {
|
||||
// Extraire les tags depuis les relations TaskTag ou fallback sur tagsJson
|
||||
let tags: string[] = [];
|
||||
|
||||
if ('taskTags' in prismaTask && prismaTask.taskTags && Array.isArray(prismaTask.taskTags)) {
|
||||
// Utiliser les relations Prisma
|
||||
tags = prismaTask.taskTags.map((tt) => tt.tag.name);
|
||||
}
|
||||
|
||||
return {
|
||||
id: prismaTask.id,
|
||||
title: prismaTask.title,
|
||||
@@ -224,8 +305,8 @@ export class TasksService {
|
||||
status: prismaTask.status as TaskStatus,
|
||||
priority: prismaTask.priority as TaskPriority,
|
||||
source: prismaTask.source as TaskSource,
|
||||
sourceId: prismaTask.sourceId?? undefined,
|
||||
tags: JSON.parse(prismaTask.tagsJson || '[]'),
|
||||
sourceId: prismaTask.sourceId ?? undefined,
|
||||
tags: tags,
|
||||
dueDate: prismaTask.dueDate ?? undefined,
|
||||
completedAt: prismaTask.completedAt ?? undefined,
|
||||
createdAt: prismaTask.createdAt,
|
||||
|
||||
Reference in New Issue
Block a user