feat: improve TaskCard and TagList components, enhance task loading logic

- Updated TaskCard to conditionally render footer elements based on available data (due date, source, completion status).
- Enhanced TagList to visually indicate deleting tags and improved button styles for better UX.
- Modified useTasks hook to refresh tasks only if no initial data is present, optimizing loading behavior.
- Updated TagsPageClient to manage local tags and handle optimistic UI updates during tag deletion.
This commit is contained in:
Julien Froidefond
2025-09-14 17:22:06 +02:00
parent 5e09759c2b
commit c1844cfb71
7 changed files with 94 additions and 67 deletions

View File

@@ -4,7 +4,7 @@ import { HomePageClient } from '@/components/HomePageClient';
export default async function HomePage() {
// SSR - Récupération des données côté serveur
const [initialTasks, initialStats] = await Promise.all([
tasksService.getTasks({ limit: 20 }),
tasksService.getTasks(),
tasksService.getTaskStats()
]);

View File

@@ -1,6 +1,7 @@
'use client';
import { useState } from 'react';
import React from 'react';
import { Tag } from '@/lib/types';
import { useTags } from '@/hooks/useTags';
import { CreateTagData, UpdateTagData } from '@/clients/tags-client';
@@ -32,11 +33,20 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [editingTag, setEditingTag] = useState<Tag | null>(null);
const [showPopular, setShowPopular] = useState(false);
const [deletingTagId, setDeletingTagId] = useState<string | null>(null);
const [localTags, setLocalTags] = useState<Tag[]>(initialTags);
// Utiliser les tags initiaux si pas encore chargés
const displayTags = tags.length > 0 ? tags : initialTags;
// Utiliser les tags du hook s'ils sont chargés, sinon les tags locaux
const displayTags = tags.length > 0 ? tags : localTags;
const filteredTags = searchQuery ? searchResults : displayTags;
// Synchroniser les tags locaux avec les tags du hook une seule fois
React.useEffect(() => {
if (tags.length > 0 && localTags === initialTags) {
setLocalTags(tags);
}
}, [tags, localTags, initialTags]);
const handleSearch = async (query: string) => {
setSearchQuery(query);
if (query.trim()) {
@@ -67,13 +77,22 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
};
const handleDeleteTag = async (tag: Tag) => {
if (confirm(`Êtes-vous sûr de vouloir supprimer le tag "${tag.name}" ?`)) {
try {
await deleteTag(tag.id);
} catch (error) {
// L'erreur est déjà gérée dans le hook
console.error('Erreur lors de la suppression:', error);
}
// Suppression optimiste : retirer immédiatement de l'affichage
setDeletingTagId(tag.id);
// Mettre à jour les tags locaux pour suppression immédiate
const updatedTags = displayTags.filter(t => t.id !== tag.id);
setLocalTags(updatedTags);
try {
await deleteTag(tag.id);
// Succès : les tags seront mis à jour par le hook
} catch (error) {
// En cas d'erreur, restaurer le tag dans l'affichage
setLocalTags(prev => [...prev, tag].sort((a, b) => a.name.localeCompare(b.name)));
console.error('Erreur lors de la suppression:', error);
} finally {
setDeletingTagId(null);
}
};
@@ -122,14 +141,14 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
<Button
variant="secondary"
onClick={handleShowPopular}
disabled={loading}
disabled={false}
>
{showPopular ? 'Tous les tags' : 'Tags populaires'}
</Button>
<Button
variant="primary"
onClick={() => setIsCreateModalOpen(true)}
disabled={loading}
disabled={false}
>
+ Nouveau tag
</Button>
@@ -194,7 +213,7 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
</div>
)}
{loading && (
{loading && displayTags.length === 0 && (
<div className="text-center py-8">
<div className="text-slate-400">Chargement...</div>
</div>
@@ -215,6 +234,7 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
onTagEdit={handleEditTag}
onTagDelete={handleDeleteTag}
showUsage={true}
deletingTagId={deletingTagId}
/>
</div>
</div>
@@ -225,7 +245,7 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
isOpen={isCreateModalOpen}
onClose={() => setIsCreateModalOpen(false)}
onSubmit={handleCreateTag}
loading={loading}
loading={false}
/>
<TagForm
@@ -233,7 +253,7 @@ export function TagsPageClient({ initialTags }: TagsPageClientProps) {
onClose={() => setEditingTag(null)}
onSubmit={handleUpdateTag}
tag={editingTag}
loading={loading}
loading={false}
/>
</div>
);