From 9fd838c63e6fac551d7cf9bce75e9b8cc4fafa59 Mon Sep 17 00:00:00 2001 From: Travis Vasceannie Date: Mon, 26 Jan 2026 10:59:27 +0000 Subject: [PATCH] fix(client): add selection mode toggle for bulk delete UX - Add 'Select' toggle button in filter area - Checkboxes only visible when selection mode is active - Hide individual trash buttons during selection mode - Exit selection mode when: deselecting all, deleting, or changing filters - Resolves visual conflict between checkbox and card title - Removes redundancy between checkbox and trash button The checkbox now appears on-demand via toggle, providing cleaner default UI. --- client/src/pages/Meetings.tsx | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/client/src/pages/Meetings.tsx b/client/src/pages/Meetings.tsx index 72185f3..80c89fc 100644 --- a/client/src/pages/Meetings.tsx +++ b/client/src/pages/Meetings.tsx @@ -1,6 +1,6 @@ // Meetings list page -import { Calendar, Loader2 } from 'lucide-react'; +import { Calendar, Loader2, CheckSquare } from 'lucide-react'; import { useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useParams } from 'react-router-dom'; import { getAPI } from '@/api/interface'; @@ -52,6 +52,7 @@ export default function MeetingsPage() { const [loadingMore, setLoadingMore] = useState(false); // Bulk selection state + const [isSelectionMode, setIsSelectionMode] = useState(false); const [selectedMeetingIds, setSelectedMeetingIds] = useState>(new Set()); const [showBulkDeleteDialog, setShowBulkDeleteDialog] = useState(false); const { mutate: deleteMeetings, isLoading: isDeleting } = useDeleteMeetings(); @@ -117,6 +118,7 @@ export default function MeetingsPage() { // Clear selections when filters change useEffect(() => { setSelectedMeetingIds(new Set()); + setIsSelectionMode(false); }, [searchQuery, stateFilter, projectScope, resolvedProjectId]); const filteredMeetings = useMemo( @@ -149,6 +151,14 @@ export default function MeetingsPage() { const handleDeselectAll = useCallback(() => { setSelectedMeetingIds(new Set()); + setIsSelectionMode(false); + }, []); + + const toggleSelectionMode = useCallback(() => { + setIsSelectionMode((prev) => { + if (prev) setSelectedMeetingIds(new Set()); + return !prev; + }); }, []); const handleBulkDelete = useCallback(() => { @@ -160,6 +170,7 @@ export default function MeetingsPage() { onSuccess: () => { setSelectedMeetingIds(new Set()); setShowBulkDeleteDialog(false); + setIsSelectionMode(false); fetchMeetings(0, false); }, }); @@ -232,6 +243,14 @@ export default function MeetingsPage() { {state} ))} + @@ -261,8 +280,8 @@ export default function MeetingsPage() { meeting={meeting} index={i} onDelete={handleDelete} - showDeleteButton - isSelectable={meeting.state !== 'recording'} + showDeleteButton={!isSelectionMode} + isSelectable={isSelectionMode && meeting.state !== 'recording'} isSelected={selectedMeetingIds.has(meeting.id)} onSelect={handleSelect} />