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.
This commit is contained in:
2026-01-26 10:59:27 +00:00
parent b9eee07135
commit 9fd838c63e

View File

@@ -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<Set<string>>(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}
</Button>
))}
<Button
variant={isSelectionMode ? 'default' : 'outline'}
size="sm"
onClick={toggleSelectionMode}
>
<CheckSquare className="h-4 w-4 mr-1" />
Select
</Button>
</div>
</div>
@@ -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}
/>