feat: add search functionality and due date filter toggle in DesktopControls
- Implemented a debounced search input for filtering tasks, enhancing user experience with smooth input handling. - Added a toggle button for filtering tasks by due date, improving task visibility options. - Updated layout for better responsiveness and integrated new input components for a cleaner UI.
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { useState, useEffect, useRef, useCallback } from 'react';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
|
import { Input } from '@/components/ui/Input';
|
||||||
import { JiraQuickFilter } from '@/components/kanban/JiraQuickFilter';
|
import { JiraQuickFilter } from '@/components/kanban/JiraQuickFilter';
|
||||||
import { TfsQuickFilter } from '@/components/kanban/TfsQuickFilter';
|
import { TfsQuickFilter } from '@/components/kanban/TfsQuickFilter';
|
||||||
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
|
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
|
||||||
@@ -35,11 +37,64 @@ export function DesktopControls({
|
|||||||
onFiltersChange,
|
onFiltersChange,
|
||||||
onCreateTask,
|
onCreateTask,
|
||||||
}: DesktopControlsProps) {
|
}: DesktopControlsProps) {
|
||||||
|
// État local pour la recherche pour une saisie fluide
|
||||||
|
const [localSearch, setLocalSearch] = useState(kanbanFilters.search || '');
|
||||||
|
const searchTimeoutRef = useRef<number | undefined>(undefined);
|
||||||
|
|
||||||
|
// Fonction debouncée pour mettre à jour les filtres
|
||||||
|
const debouncedSearchChange = useCallback((search: string) => {
|
||||||
|
if (searchTimeoutRef.current) {
|
||||||
|
window.clearTimeout(searchTimeoutRef.current);
|
||||||
|
}
|
||||||
|
|
||||||
|
searchTimeoutRef.current = window.setTimeout(() => {
|
||||||
|
onFiltersChange({ ...kanbanFilters, search: search || undefined });
|
||||||
|
}, 300);
|
||||||
|
}, [kanbanFilters, onFiltersChange]);
|
||||||
|
|
||||||
|
const handleSearchChange = (search: string) => {
|
||||||
|
setLocalSearch(search);
|
||||||
|
debouncedSearchChange(search);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Synchroniser l'état local quand les filtres changent de l'extérieur
|
||||||
|
useEffect(() => {
|
||||||
|
setLocalSearch(kanbanFilters.search || '');
|
||||||
|
}, [kanbanFilters.search]);
|
||||||
|
|
||||||
|
// Nettoyer le timeout au démontage
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
if (searchTimeoutRef.current) {
|
||||||
|
window.clearTimeout(searchTimeoutRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const handleDueDateFilterToggle = () => {
|
||||||
|
onFiltersChange({
|
||||||
|
...kanbanFilters,
|
||||||
|
showWithDueDate: !kanbanFilters.showWithDueDate
|
||||||
|
});
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="bg-[var(--card)]/30 border-b border-[var(--border)]/30">
|
<div className="bg-[var(--card)]/30 border-b border-[var(--border)]/30 w-full">
|
||||||
<div className="container mx-auto px-6 py-2">
|
<div className="w-full px-6 py-2">
|
||||||
<div className="flex items-center justify-between w-full">
|
{/* Layout responsive : deux lignes sur tablette, une ligne sur desktop */}
|
||||||
|
<div className="flex flex-col lg:flex-row lg:items-center gap-4 lg:gap-0 w-full">
|
||||||
|
{/* Section gauche : Recherche + Boutons principaux */}
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
|
{/* Champ de recherche */}
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<Input
|
||||||
|
type="text"
|
||||||
|
value={localSearch}
|
||||||
|
onChange={(e) => handleSearchChange(e.target.value)}
|
||||||
|
placeholder="Rechercher des tâches..."
|
||||||
|
className="bg-[var(--card)] border-[var(--border)] w-full"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={onToggleFilters}
|
onClick={onToggleFilters}
|
||||||
@@ -68,8 +123,25 @@ export function DesktopControls({
|
|||||||
</svg>
|
</svg>
|
||||||
Objectifs
|
Objectifs
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleDueDateFilterToggle}
|
||||||
|
className={`flex items-center justify-center px-3 py-1.5 rounded-md transition-all mr-4 ${
|
||||||
|
kanbanFilters.showWithDueDate
|
||||||
|
? 'bg-[var(--cyan)]/20 text-[var(--cyan)] border border-[var(--cyan)]/30'
|
||||||
|
: 'bg-[var(--card)] text-[var(--muted-foreground)] border border-[var(--border)] hover:border-[var(--cyan)]/50'
|
||||||
|
}`}
|
||||||
|
title={kanbanFilters.showWithDueDate ? "Afficher toutes les tâches" : "Afficher seulement les tâches avec date de fin"}
|
||||||
|
>
|
||||||
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 002 2v12a2 2 0 002 2z" />
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Section droite : Raccourcis + Bouton Nouvelle tâche */}
|
||||||
|
<div className="flex items-center justify-between lg:justify-start gap-4">
|
||||||
<div className="flex items-center gap-2 border-l border-[var(--border)] pl-4">
|
<div className="flex items-center gap-2 border-l border-[var(--border)] pl-4">
|
||||||
{/* Raccourcis Jira */}
|
{/* Raccourcis Jira */}
|
||||||
<JiraQuickFilter
|
<JiraQuickFilter
|
||||||
@@ -124,20 +196,20 @@ export function DesktopControls({
|
|||||||
{/* Font Size Toggle */}
|
{/* Font Size Toggle */}
|
||||||
<FontSizeToggle />
|
<FontSizeToggle />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Bouton d'ajout de tâche */}
|
{/* Bouton d'ajout de tâche */}
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={onCreateTask}
|
size="sm"
|
||||||
className="flex items-center gap-2"
|
onClick={onCreateTask}
|
||||||
>
|
className="flex items-center gap-2"
|
||||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
>
|
||||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
</svg>
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 4v16m8-8H4" />
|
||||||
Nouvelle tâche
|
</svg>
|
||||||
</Button>
|
Nouvelle tâche
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user