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:
Julien Froidefond
2025-09-14 16:44:22 +02:00
parent edbd82e8ac
commit c5a7d16425
27 changed files with 2055 additions and 224 deletions

View File

@@ -2,7 +2,7 @@
import { useState, useRef, useEffect } from 'react';
import { Card } from '@/components/ui/Card';
import { Badge } from '@/components/ui/Badge';
import { TagInput } from '@/components/ui/TagInput';
import { TaskStatus, TaskPriority } from '@/lib/types';
import { CreateTaskData } from '@/clients/tasks-client';
@@ -21,7 +21,6 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
tags: [],
dueDate: undefined
});
const [tagInput, setTagInput] = useState('');
const [isSubmitting, setIsSubmitting] = useState(false);
const [activeField, setActiveField] = useState<'title' | 'description' | 'tags' | 'date' | null>('title');
const titleRef = useRef<HTMLInputElement>(null);
@@ -53,7 +52,6 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
tags: [],
dueDate: undefined
});
setTagInput('');
setActiveField('title');
setIsSubmitting(false);
titleRef.current?.focus();
@@ -73,9 +71,8 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
if (field === 'title' && formData.title.trim()) {
console.log('Calling handleSubmit from title');
handleSubmit();
} else if (field === 'tags' && tagInput.trim()) {
console.log('Adding tag');
addTag();
} else if (field === 'tags') {
// TagInput gère ses propres événements Enter
} else if (formData.title.trim()) {
// Permettre création depuis n'importe quel champ si titre rempli
console.log('Calling handleSubmit from other field');
@@ -95,21 +92,10 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
// Laisser passer tous les autres événements (y compris les raccourcis système)
};
const addTag = () => {
const tag = tagInput.trim();
if (tag && !formData.tags?.includes(tag)) {
setFormData(prev => ({
...prev,
tags: [...(prev.tags || []), tag]
}));
setTagInput('');
}
};
const removeTag = (tagToRemove: string) => {
const handleTagsChange = (tags: string[]) => {
setFormData(prev => ({
...prev,
tags: prev.tags?.filter(tag => tag !== tagToRemove) || []
tags
}));
};
@@ -171,28 +157,12 @@ export function QuickAddTask({ status, onSubmit, onCancel }: QuickAddTaskProps)
{/* Tags */}
<div className="mb-2">
<div className="flex flex-wrap gap-1 mb-1">
{formData.tags && formData.tags.map((tag: string, index: number) => (
<Badge
key={index}
variant="primary"
size="sm"
className="cursor-pointer hover:bg-red-950/50 hover:text-red-300 hover:border-red-500/30 transition-colors"
onClick={() => removeTag(tag)}
>
{tag}
</Badge>
))}
</div>
<input
type="text"
value={tagInput}
onChange={(e) => setTagInput(e.target.value)}
onKeyDown={(e) => handleKeyDown(e, 'tags')}
onFocus={() => setActiveField('tags')}
<TagInput
tags={formData.tags || []}
onChange={handleTagsChange}
placeholder="Tags..."
disabled={isSubmitting}
className="w-full bg-transparent border-none outline-none text-xs text-slate-400 font-mono placeholder-slate-500"
maxTags={5}
className="text-xs"
/>
</div>