fix(sprint-backlog): prevent text selection on PBI collapse button

This commit is contained in:
Janpeter Visser 2026-04-27 20:12:47 +02:00
parent 92576abc0b
commit eab2f698d6

View file

@ -1,7 +1,7 @@
'use client'
import { useState, useTransition } from 'react'
import { Trash2, MoreHorizontal } from 'lucide-react'
import { Trash2, MoreHorizontal, ChevronsUp, ChevronsDown, ListFilter } from 'lucide-react'
import { useDroppable, useDraggable } from '@dnd-kit/core'
import { SortableContext, useSortable, verticalListSortingStrategy } from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
@ -15,6 +15,7 @@ import {
import { PanelNavBar } from '@/components/shared/panel-nav-bar'
import { UserAvatar } from '@/components/shared/user-avatar'
import { DemoTooltip } from '@/components/shared/demo-tooltip'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import { PRIORITY_BORDER } from '@/components/backlog/backlog-card'
import { useSprintStore } from '@/stores/sprint-store'
import { claimStoryAction, unclaimStoryAction, reassignStoryAction, claimAllUnassignedInActiveSprintAction } from '@/actions/stories'
@ -372,7 +373,15 @@ interface SprintBacklogRightProps {
}
export function SprintBacklogRight({ pbisWithStories, sprintStoryIds, isDemo, onAdd }: SprintBacklogRightProps) {
const [collapsed, setCollapsed] = useState<Set<string>>(new Set())
const [collapsed, setCollapsed] = useState<Set<string>>(() => {
const auto = new Set<string>()
for (const pbi of pbisWithStories) {
if (pbi.stories.length > 0 && pbi.stories.every(s => s.status === 'DONE')) {
auto.add(pbi.id)
}
}
return auto
})
const { setNodeRef, isOver } = useDroppable({ id: 'backlog-zone' })
function toggle(pbiId: string) {
@ -383,9 +392,50 @@ export function SprintBacklogRight({ pbisWithStories, sprintStoryIds, isDemo, on
})
}
function collapseAll() {
setCollapsed(new Set(pbisWithStories.map(p => p.id)))
}
function expandAll() {
setCollapsed(new Set())
}
function onlyNotDone() {
const auto = new Set<string>()
for (const pbi of pbisWithStories) {
if (pbi.stories.length > 0 && pbi.stories.every(s => s.status === 'DONE')) {
auto.add(pbi.id)
}
}
setCollapsed(auto)
}
const collapseActions = (
<TooltipProvider>
<Tooltip>
<TooltipTrigger onClick={collapseAll} className="text-muted-foreground hover:text-foreground p-0.5 rounded" aria-label="Alles inklappen">
<ChevronsUp size={14} />
</TooltipTrigger>
<TooltipContent>Alles inklappen</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger onClick={expandAll} className="text-muted-foreground hover:text-foreground p-0.5 rounded" aria-label="Alles uitklappen">
<ChevronsDown size={14} />
</TooltipTrigger>
<TooltipContent>Alles uitklappen</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger onClick={onlyNotDone} className="text-muted-foreground hover:text-foreground p-0.5 rounded" aria-label="Alleen niet klaar">
<ListFilter size={14} />
</TooltipTrigger>
<TooltipContent>Alleen niet klaar</TooltipContent>
</Tooltip>
</TooltipProvider>
)
return (
<div className="flex flex-col h-full">
<PanelNavBar title="Product Backlog" />
<PanelNavBar title="Product Backlog" actions={collapseActions} />
<div
ref={setNodeRef}
className={cn(
@ -397,12 +447,14 @@ export function SprintBacklogRight({ pbisWithStories, sprintStoryIds, isDemo, on
<div key={pbi.id}>
<button
onClick={() => toggle(pbi.id)}
className="w-full flex items-center gap-2 px-4 py-1.5 hover:bg-surface-container transition-colors text-left"
className="w-full flex items-center gap-2 px-4 py-1.5 hover:bg-surface-container transition-colors text-left select-none"
>
<span className="text-xs">{collapsed.has(pbi.id) ? '▶' : '▼'}</span>
<span className="text-sm font-medium truncate flex-1">{pbi.title}</span>
{pbi.code && <CodeBadge code={pbi.code} />}
<span className="text-xs text-muted-foreground">{pbi.stories.length}</span>
<span className="text-xs text-muted-foreground">
{pbi.stories.filter(s => s.status === 'DONE').length}/{pbi.stories.length} klaar
</span>
</button>
{!collapsed.has(pbi.id) && pbi.stories.map(story => {