From 4142d04361b8eded8441674db584a41c8ffe87c5 Mon Sep 17 00:00:00 2001 From: EENE Dashboard Date: Mon, 1 Jun 2026 11:44:58 +0900 Subject: [PATCH] fix: use onClick for card select, right-click safe Co-authored-by: Cursor --- .../src/components/dashboard/TaskCard.tsx | 35 ++++--------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/frontend/src/components/dashboard/TaskCard.tsx b/frontend/src/components/dashboard/TaskCard.tsx index 4de22f3..1c2035b 100644 --- a/frontend/src/components/dashboard/TaskCard.tsx +++ b/frontend/src/components/dashboard/TaskCard.tsx @@ -1,4 +1,4 @@ -import { useState, useRef } from 'react'; +import { useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useSortable } from '@dnd-kit/sortable'; import { CSS } from '@dnd-kit/utilities'; @@ -62,25 +62,8 @@ export function SortableTaskCard({ task, sectionOptions, onSelect }: { task: Tas opacity: isDragging ? 0.4 : 1, }; - // dnd-kit이 dragListeners의 onPointerDown을 가로채므로 onClick이 막힐 수 있음. - // pointerDown 시작 위치를 ref로 기억했다가 pointerUp에서 이동이 적으면 클릭으로 판정. - const pointerStart = useRef<{ x: number; y: number } | null>(null); - - const handlePointerDown = (e: React.PointerEvent) => { - if (e.button !== 0) return; // 좌클릭만 - pointerStart.current = { x: e.clientX, y: e.clientY }; - }; - - const handlePointerUp = (e: React.PointerEvent) => { - if (e.button !== 0) return; // 좌클릭만 - if (!pointerStart.current || isDragging) return; - const dx = e.clientX - pointerStart.current.x; - const dy = e.clientY - pointerStart.current.y; - const dist = Math.sqrt(dx * dx + dy * dy); - if (dist < 6) { - onSelect?.(task); - } - pointerStart.current = null; + const handleClick = () => { + if (!isDragging) onSelect?.(task); }; return ( @@ -91,8 +74,7 @@ export function SortableTaskCard({ task, sectionOptions, onSelect }: { task: Tas dragAttributes={attributes} dragListeners={listeners} sectionOptions={sectionOptions} - onCardPointerDown={handlePointerDown} - onCardPointerUp={handlePointerUp} + onCardClick={handleClick} /> ); } @@ -105,8 +87,7 @@ export function TaskCard({ dragAttributes, dragListeners, sectionOptions, - onCardPointerDown, - onCardPointerUp, + onCardClick, }: { task: Task; dragRef?: (node: HTMLElement | null) => void; @@ -114,8 +95,7 @@ export function TaskCard({ dragAttributes?: DraggableAttributes; dragListeners?: SyntheticListenerMap; sectionOptions?: SectionOption[]; - onCardPointerDown?: (e: React.PointerEvent) => void; - onCardPointerUp?: (e: React.PointerEvent) => void; + onCardClick?: () => void; }) { const queryClient = useQueryClient(); const tagCfg = TAG_CONFIG[task.tag ?? ''] ?? { bg: 'bg-gray-100', text: 'text-gray-600' }; @@ -195,8 +175,7 @@ export function TaskCard({ {...dragAttributes} {...dragListeners} className="bg-white rounded-2xl px-5 py-3 mb-3 shadow-sm border border-gray-100 hover:shadow-md hover:border-gray-200 transition-all select-none h-[112px] cursor-grab active:cursor-grabbing overflow-hidden" - onPointerDown={onCardPointerDown} - onPointerUp={onCardPointerUp} + onClick={onCardClick} onContextMenu={handleContextMenu} > {/* ── 상단: 제목 + 진행률 ── */}