feat: add filtering options for tags management

- Introduced `showOnlyWithoutIcons` state in `TagsManagement` to filter tags without icons.
- Updated `TagsFilters` component to include a button for toggling the new filter, displaying the count of tags without icons.
- Enhanced filtering logic to accommodate the new option, improving tag management functionality.
This commit is contained in:
Julien Froidefond
2025-10-01 13:40:51 +02:00
parent 4885871657
commit 7ebf7d491b
2 changed files with 27 additions and 3 deletions

View File

@@ -9,6 +9,8 @@ interface TagsFiltersProps {
onSearchChange: (query: string) => void; onSearchChange: (query: string) => void;
showOnlyUnused: boolean; showOnlyUnused: boolean;
onToggleUnused: () => void; onToggleUnused: () => void;
showOnlyWithoutIcons: boolean;
onToggleWithoutIcons: () => void;
tags: (Tag & { usage?: number })[]; tags: (Tag & { usage?: number })[];
onReset: () => void; onReset: () => void;
} }
@@ -18,11 +20,14 @@ export function TagsFilters({
onSearchChange, onSearchChange,
showOnlyUnused, showOnlyUnused,
onToggleUnused, onToggleUnused,
showOnlyWithoutIcons,
onToggleWithoutIcons,
tags, tags,
onReset onReset
}: TagsFiltersProps) { }: TagsFiltersProps) {
const unusedCount = tags.filter(tag => (tag.usage || 0) === 0).length; const unusedCount = tags.filter(tag => (tag.usage || 0) === 0).length;
const hasFilters = searchQuery || showOnlyUnused; const withoutIconsCount = tags.filter(tag => !tag.name.match(/^[\p{Emoji}\p{Symbol}]/u)).length;
const hasFilters = searchQuery || showOnlyUnused || showOnlyWithoutIcons;
return ( return (
<div className="space-y-3 mb-4"> <div className="space-y-3 mb-4">
@@ -45,6 +50,16 @@ export function TagsFilters({
Tags non utilisés ({unusedCount}) Tags non utilisés ({unusedCount})
</Button> </Button>
<Button
variant={showOnlyWithoutIcons ? "primary" : "ghost"}
size="sm"
onClick={onToggleWithoutIcons}
className="flex items-center gap-2"
>
<span className="text-xs">🚫</span>
Tags sans icônes ({withoutIconsCount})
</Button>
{hasFilters && ( {hasFilters && (
<Button <Button
variant="ghost" variant="ghost"

View File

@@ -18,6 +18,7 @@ interface TagsManagementProps {
export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagementProps) { export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagementProps) {
const [searchQuery, setSearchQuery] = useState(''); const [searchQuery, setSearchQuery] = useState('');
const [showOnlyUnused, setShowOnlyUnused] = useState(false); const [showOnlyUnused, setShowOnlyUnused] = useState(false);
const [showOnlyWithoutIcons, setShowOnlyWithoutIcons] = useState(false);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [editingTag, setEditingTag] = useState<Tag | null>(null); const [editingTag, setEditingTag] = useState<Tag | null>(null);
const [deletingTagId, setDeletingTagId] = useState<string | null>(null); const [deletingTagId, setDeletingTagId] = useState<string | null>(null);
@@ -42,6 +43,11 @@ export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagem
}); });
} }
// Filtrer pour afficher seulement les tags sans icônes
if (showOnlyWithoutIcons) {
filtered = filtered.filter(tag => !tag.name.match(/^[\p{Emoji}\p{Symbol}]/u));
}
const sorted = filtered.sort((a, b) => { const sorted = filtered.sort((a, b) => {
const usageA = a.usage || 0; const usageA = a.usage || 0;
const usageB = b.usage || 0; const usageB = b.usage || 0;
@@ -50,9 +56,9 @@ export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagem
}); });
// Limiter à 12 tags si pas de recherche ni filtre, sinon afficher tous les résultats // Limiter à 12 tags si pas de recherche ni filtre, sinon afficher tous les résultats
const hasFilters = searchQuery.trim() || showOnlyUnused; const hasFilters = searchQuery.trim() || showOnlyUnused || showOnlyWithoutIcons;
return hasFilters ? sorted : sorted.slice(0, 12); return hasFilters ? sorted : sorted.slice(0, 12);
}, [tags, searchQuery, showOnlyUnused]); }, [tags, searchQuery, showOnlyUnused, showOnlyWithoutIcons]);
const handleEditTag = (tag: Tag) => { const handleEditTag = (tag: Tag) => {
setEditingTag(tag); setEditingTag(tag);
@@ -77,6 +83,7 @@ export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagem
const handleReset = () => { const handleReset = () => {
setSearchQuery(''); setSearchQuery('');
setShowOnlyUnused(false); setShowOnlyUnused(false);
setShowOnlyWithoutIcons(false);
}; };
return ( return (
@@ -115,6 +122,8 @@ export function TagsManagement({ tags, onRefreshTags, onDeleteTag }: TagsManagem
onSearchChange={setSearchQuery} onSearchChange={setSearchQuery}
showOnlyUnused={showOnlyUnused} showOnlyUnused={showOnlyUnused}
onToggleUnused={() => setShowOnlyUnused(!showOnlyUnused)} onToggleUnused={() => setShowOnlyUnused(!showOnlyUnused)}
showOnlyWithoutIcons={showOnlyWithoutIcons}
onToggleWithoutIcons={() => setShowOnlyWithoutIcons(!showOnlyWithoutIcons)}
tags={tags} tags={tags}
onReset={handleReset} onReset={handleReset}
/> />